annotate src/breadcrumbs/src/PCoA.py @ 0:0de566f21448 draft default tip

v2
author sagun98
date Thu, 03 Jun 2021 18:13:32 +0000
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
sagun98
parents:
diff changeset
1 """
sagun98
parents:
diff changeset
2 Author: Timothy Tickle
sagun98
parents:
diff changeset
3 Description: Perfroms and plots Principle Coordinates Analysis.
sagun98
parents:
diff changeset
4 """
sagun98
parents:
diff changeset
5
sagun98
parents:
diff changeset
6 #####################################################################################
sagun98
parents:
diff changeset
7 #Copyright (C) <2012>
sagun98
parents:
diff changeset
8 #
sagun98
parents:
diff changeset
9 #Permission is hereby granted, free of charge, to any person obtaining a copy of
sagun98
parents:
diff changeset
10 #this software and associated documentation files (the "Software"), to deal in the
sagun98
parents:
diff changeset
11 #Software without restriction, including without limitation the rights to use, copy,
sagun98
parents:
diff changeset
12 #modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
sagun98
parents:
diff changeset
13 #and to permit persons to whom the Software is furnished to do so, subject to
sagun98
parents:
diff changeset
14 #the following conditions:
sagun98
parents:
diff changeset
15 #
sagun98
parents:
diff changeset
16 #The above copyright notice and this permission notice shall be included in all copies
sagun98
parents:
diff changeset
17 #or substantial portions of the Software.
sagun98
parents:
diff changeset
18 #
sagun98
parents:
diff changeset
19 #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
sagun98
parents:
diff changeset
20 #INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
sagun98
parents:
diff changeset
21 #PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
sagun98
parents:
diff changeset
22 #HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
sagun98
parents:
diff changeset
23 #OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
sagun98
parents:
diff changeset
24 #SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
sagun98
parents:
diff changeset
25 #####################################################################################
sagun98
parents:
diff changeset
26
sagun98
parents:
diff changeset
27 __author__ = "Timothy Tickle"
sagun98
parents:
diff changeset
28 __copyright__ = "Copyright 2012"
sagun98
parents:
diff changeset
29 __credits__ = ["Timothy Tickle"]
sagun98
parents:
diff changeset
30 __license__ = "MIT"
sagun98
parents:
diff changeset
31 __maintainer__ = "Timothy Tickle"
sagun98
parents:
diff changeset
32 __email__ = "ttickle@sph.harvard.edu"
sagun98
parents:
diff changeset
33 __status__ = "Development"
sagun98
parents:
diff changeset
34
sagun98
parents:
diff changeset
35 #External libraries
sagun98
parents:
diff changeset
36 from ConstantsFiguresBreadCrumbs import ConstantsFiguresBreadCrumbs
sagun98
parents:
diff changeset
37 from cogent.cluster.nmds import NMDS
sagun98
parents:
diff changeset
38 import csv
sagun98
parents:
diff changeset
39 import math
sagun98
parents:
diff changeset
40 import matplotlib.cm as cm
sagun98
parents:
diff changeset
41 from Metric import Metric
sagun98
parents:
diff changeset
42 import numpy as np
sagun98
parents:
diff changeset
43 from scipy.spatial.distance import squareform
sagun98
parents:
diff changeset
44 from scipy.stats.stats import spearmanr
sagun98
parents:
diff changeset
45 from Utility import Utility
sagun98
parents:
diff changeset
46 from UtilityMath import UtilityMath
sagun98
parents:
diff changeset
47 from ValidateData import ValidateData
sagun98
parents:
diff changeset
48 from matplotlib import pyplot as plt
sagun98
parents:
diff changeset
49
sagun98
parents:
diff changeset
50 class PCoA:
sagun98
parents:
diff changeset
51 """
sagun98
parents:
diff changeset
52 Class to Run Principle Coordinates Analysis.
sagun98
parents:
diff changeset
53
sagun98
parents:
diff changeset
54 To run PCoA first load the AbundanceTable or distance matrix using the "load" method,
sagun98
parents:
diff changeset
55 then use the "run" method to derive points, and then use "plot" to plot the graph.
sagun98
parents:
diff changeset
56 The process is structured in this way so that data is read once but can be transformed to different
sagun98
parents:
diff changeset
57 distance matricies and after analysis can be plotted with multiple sample highlighting.
sagun98
parents:
diff changeset
58 One can always reload or rerun data by calling the appropriate function.
sagun98
parents:
diff changeset
59
sagun98
parents:
diff changeset
60 Supported beta diversity metrics include "braycurtis","canberra","chebyshev","cityblock","correlation",
sagun98
parents:
diff changeset
61 "cosine","euclidean","hamming","sqeuclidean",unifrac_unweighted","unifrac_weighted"
sagun98
parents:
diff changeset
62 """
sagun98
parents:
diff changeset
63
sagun98
parents:
diff changeset
64 #Supported distance metrics
sagun98
parents:
diff changeset
65 c_BRAY_CURTIS="B_Curtis"
sagun98
parents:
diff changeset
66 c_SPEARMAN="spearman"
sagun98
parents:
diff changeset
67
sagun98
parents:
diff changeset
68 #Holds the data Matrix
sagun98
parents:
diff changeset
69 dataMatrix=None
sagun98
parents:
diff changeset
70 #Indicates if the data matrix is raw data (True) or a distance matrix (False)
sagun98
parents:
diff changeset
71 isRawData=None
sagun98
parents:
diff changeset
72 # Holds current matrix ids
sagun98
parents:
diff changeset
73 lsIDs = None
sagun98
parents:
diff changeset
74
sagun98
parents:
diff changeset
75 #Current pcoa object
sagun98
parents:
diff changeset
76 pcoa = None
sagun98
parents:
diff changeset
77
sagun98
parents:
diff changeset
78 #Holds the most recently successful distance metric
sagun98
parents:
diff changeset
79 strRecentMetric = None
sagun98
parents:
diff changeset
80
sagun98
parents:
diff changeset
81 #Current dimensions
sagun98
parents:
diff changeset
82 _iDimensions = 2
sagun98
parents:
diff changeset
83
sagun98
parents:
diff changeset
84 #Get plot colors
sagun98
parents:
diff changeset
85 objFigureControl = ConstantsFiguresBreadCrumbs()
sagun98
parents:
diff changeset
86
sagun98
parents:
diff changeset
87 #Forced X Axis
sagun98
parents:
diff changeset
88 ldForcedXAxis = None
sagun98
parents:
diff changeset
89
sagun98
parents:
diff changeset
90 #Indices for the plot group dictionary
sagun98
parents:
diff changeset
91 c_iXPointIndex = 0
sagun98
parents:
diff changeset
92 c_iYPointIndex = 1
sagun98
parents:
diff changeset
93 c_iColorIndex = 2
sagun98
parents:
diff changeset
94 c_iMarkerIndex = 3
sagun98
parents:
diff changeset
95 c_iAlphaIndex = 4
sagun98
parents:
diff changeset
96 c_iLabelIndex = 5
sagun98
parents:
diff changeset
97 c_iShapeIndex = 6
sagun98
parents:
diff changeset
98 c_iEdgeColorIndex = 7
sagun98
parents:
diff changeset
99 c_strTiesKey = "Ties"
sagun98
parents:
diff changeset
100
sagun98
parents:
diff changeset
101 #Happy path tested
sagun98
parents:
diff changeset
102 def loadData(self, xData, fIsRawData):
sagun98
parents:
diff changeset
103 """
sagun98
parents:
diff changeset
104 Loads data into PCoA (given the matrix or an abundance table)
sagun98
parents:
diff changeset
105 Data can be the Abundance Table to be converted to a distance matrix or a distance matrix
sagun98
parents:
diff changeset
106 If it is the AbundanceTable, indicate that it is rawData (tempIsRawData=True)
sagun98
parents:
diff changeset
107 If it is the distance matrix already generated indicate (tempIsRawData=False)
sagun98
parents:
diff changeset
108 and no conversion will occur in subsequent methods.
sagun98
parents:
diff changeset
109
sagun98
parents:
diff changeset
110 :params xData: AbundanceTable or Distance matrix . Taxa (columns) by samples (rows)(lists)
sagun98
parents:
diff changeset
111 :type: AbundanceTable or DistanceMatrix
sagun98
parents:
diff changeset
112 :param fIsRawData: Indicates if the xData is an AbudanceTable (True) or distance matrix (False; numpy array)
sagun98
parents:
diff changeset
113 :type: boolean
sagun98
parents:
diff changeset
114 :return boolean: indicator of success (True=Was able to load data)
sagun98
parents:
diff changeset
115 """
sagun98
parents:
diff changeset
116
sagun98
parents:
diff changeset
117 if fIsRawData:
sagun98
parents:
diff changeset
118 #Read in the file data to a numpy array.
sagun98
parents:
diff changeset
119 #Samples (column) by Taxa (rows)(lists) without the column
sagun98
parents:
diff changeset
120 data = xData.funcToArray()
sagun98
parents:
diff changeset
121 if data==None:
sagun98
parents:
diff changeset
122 print("PCoA:loadData::Error when converting AbundanceTable to Array, did not perform PCoA.")
sagun98
parents:
diff changeset
123 return False
sagun98
parents:
diff changeset
124
sagun98
parents:
diff changeset
125 #Transpose data to be Taxa (columns) by samples (rows)(lists)
sagun98
parents:
diff changeset
126 data = UtilityMath.funcTransposeDataMatrix(data,fRemoveAdornments=False)
sagun98
parents:
diff changeset
127 if(ValidateData.funcIsFalse(data)):
sagun98
parents:
diff changeset
128 print("PCoA:loadData::Error when transposing data file, did not perform PCoA.")
sagun98
parents:
diff changeset
129 return False
sagun98
parents:
diff changeset
130 else:
sagun98
parents:
diff changeset
131 self.dataMatrix=data
sagun98
parents:
diff changeset
132 self.isRawData=fIsRawData
sagun98
parents:
diff changeset
133 self.lsIDs=xData.funcGetMetadata(xData.funcGetIDMetadataName())
sagun98
parents:
diff changeset
134
sagun98
parents:
diff changeset
135 #Otherwise load the data directly as passed.
sagun98
parents:
diff changeset
136 else:
sagun98
parents:
diff changeset
137 self.dataMatrix=xData
sagun98
parents:
diff changeset
138 self.isRawData=fIsRawData
sagun98
parents:
diff changeset
139 return True
sagun98
parents:
diff changeset
140
sagun98
parents:
diff changeset
141 def run(self, tempDistanceMetric=None, iDims=2, strDistanceMatrixFile=None, istrmTree=None, istrmEnvr=None):
sagun98
parents:
diff changeset
142 """
sagun98
parents:
diff changeset
143 Runs analysis on loaded data.
sagun98
parents:
diff changeset
144
sagun98
parents:
diff changeset
145 :param tempDistanceMetric: The name of the distance metric to use when performing PCoA.
sagun98
parents:
diff changeset
146 None indicates a distance matrix was already given when loading and will be used.
sagun98
parents:
diff changeset
147 Supports "braycurtis","canberra","chebyshev","cityblock","correlation",
sagun98
parents:
diff changeset
148 "cosine","euclidean","hamming","sqeuclidean",unifrac_unweighted","unifrac_weighted"
sagun98
parents:
diff changeset
149 :type: String Distance matrix name
sagun98
parents:
diff changeset
150 :param iDims: How many dimension to plot the PCoA graphs.
sagun98
parents:
diff changeset
151 (This can be minimally 2; all combinations of dimensions are plotted).
sagun98
parents:
diff changeset
152 iDims start with 1 (not index-based).
sagun98
parents:
diff changeset
153 :type: Integer Positive integer 2 or greater.
sagun98
parents:
diff changeset
154 :param strDistanceMatrixFile: If the underlying distance matrix should be output, this is the file to output to.
sagun98
parents:
diff changeset
155 :type: String Output file for distances of None for indicating it shoudl not be done.
sagun98
parents:
diff changeset
156 :param istrmTree: One of two files needed for unifrac calculations, this is the phylogeny of the features.
sagun98
parents:
diff changeset
157 :type: String Path to file
sagun98
parents:
diff changeset
158 :param istrmEnvr: One of two files needed for unifrac calculations, this is the environment file for the features.
sagun98
parents:
diff changeset
159 :type: String Path to file
sagun98
parents:
diff changeset
160 :return boolean: Indicator of success (True)
sagun98
parents:
diff changeset
161 """
sagun98
parents:
diff changeset
162
sagun98
parents:
diff changeset
163 if iDims > 1:
sagun98
parents:
diff changeset
164 self._iDimensions = iDims
sagun98
parents:
diff changeset
165
sagun98
parents:
diff changeset
166 #If distance metric is none, check to see if the matrix is a distance matrix
sagun98
parents:
diff changeset
167 #If so, run NMDS on the distance matrix
sagun98
parents:
diff changeset
168 #Otherwise return a false and do not run
sagun98
parents:
diff changeset
169 if(tempDistanceMetric==None):
sagun98
parents:
diff changeset
170 if(ValidateData.funcIsTrue(self.isRawData)):
sagun98
parents:
diff changeset
171 print("PCoA:run::Error, no distance metric was specified but the previous load was not of a distance matrix.")
sagun98
parents:
diff changeset
172 return False
sagun98
parents:
diff changeset
173 elif(ValidateData.funcIsFalse(self.isRawData)):
sagun98
parents:
diff changeset
174 self.pcoa = NMDS(dataMatrix, verbosity=0)
sagun98
parents:
diff changeset
175 return True
sagun98
parents:
diff changeset
176
sagun98
parents:
diff changeset
177 #Make sure the distance metric was a valid string type
sagun98
parents:
diff changeset
178 if(not ValidateData.funcIsValidString(tempDistanceMetric)):
sagun98
parents:
diff changeset
179 print("PCoA:run::Error, distance metric was not a valid string type.")
sagun98
parents:
diff changeset
180 return False
sagun98
parents:
diff changeset
181
sagun98
parents:
diff changeset
182 #Supported distances
sagun98
parents:
diff changeset
183
sagun98
parents:
diff changeset
184 distanceMatrix = None
sagun98
parents:
diff changeset
185 if(tempDistanceMetric==self.c_SPEARMAN):
sagun98
parents:
diff changeset
186 distanceMatrix = Metric().funcGetDissimilarity(ldSampleTaxaAbundancies=self.dataMatrix, funcDistanceFunction=lambda u,v: spearmanr(u,v)[0])
sagun98
parents:
diff changeset
187 if(tempDistanceMetric in [Metric.c_strUnifracUnweighted,Metric.c_strUnifracWeighted]):
sagun98
parents:
diff changeset
188 distanceMatrix,lsLabels = Metric().funcGetBetaMetric(sMetric=tempDistanceMetric, istrmTree=istrmTree, istrmEnvr=istrmEnvr)
sagun98
parents:
diff changeset
189 self.lsIDs = lsLabels
sagun98
parents:
diff changeset
190 else:
sagun98
parents:
diff changeset
191 distanceMatrix = Metric().funcGetBetaMetric(npadAbundancies=self.dataMatrix, sMetric=tempDistanceMetric)
sagun98
parents:
diff changeset
192 if(ValidateData.funcIsFalse(distanceMatrix)):
sagun98
parents:
diff changeset
193 print "PCoA:run::Error, when generating distance matrix."
sagun98
parents:
diff changeset
194 return False
sagun98
parents:
diff changeset
195
sagun98
parents:
diff changeset
196 # Make squareform
sagun98
parents:
diff changeset
197 distanceMatrix = squareform(distanceMatrix)
sagun98
parents:
diff changeset
198
sagun98
parents:
diff changeset
199 # Writes distance measures if needed.
sagun98
parents:
diff changeset
200 if strDistanceMatrixFile:
sagun98
parents:
diff changeset
201 csvrDistance = csv.writer(open(strDistanceMatrixFile, 'w'))
sagun98
parents:
diff changeset
202 if self.lsIDs:
sagun98
parents:
diff changeset
203 csvrDistance.writerow(["ID"]+self.lsIDs)
sagun98
parents:
diff changeset
204
sagun98
parents:
diff changeset
205 for x in xrange(distanceMatrix.shape[0]):
sagun98
parents:
diff changeset
206 strId = [self.lsIDs[x]] if self.lsIDs else []
sagun98
parents:
diff changeset
207 csvrDistance.writerow(strId+distanceMatrix[x].tolist())
sagun98
parents:
diff changeset
208
sagun98
parents:
diff changeset
209 self.pcoa = NMDS(distanceMatrix, dimension=max(self._iDimensions,2), verbosity=0)
sagun98
parents:
diff changeset
210 self.strRecentMetric = tempDistanceMetric
sagun98
parents:
diff changeset
211 return True
sagun98
parents:
diff changeset
212
sagun98
parents:
diff changeset
213 #TODO Test
sagun98
parents:
diff changeset
214 def funcGetCoordinates(self):
sagun98
parents:
diff changeset
215 return(self.pcoa.getPoints())
sagun98
parents:
diff changeset
216
sagun98
parents:
diff changeset
217 #TODO Test
sagun98
parents:
diff changeset
218 def funcGetIDs(self):
sagun98
parents:
diff changeset
219 return(self.lsIDs)
sagun98
parents:
diff changeset
220
sagun98
parents:
diff changeset
221 #Happy path tested
sagun98
parents:
diff changeset
222 def plot(self, tempPlotName="PCOA.png", tempColorGrouping=None, tempShape=None, tempLabels=None, tempShapeSize=None, tempAlpha = 1.0, tempLegendLocation="upper right", tempInvert=False, iDim1 = 1, iDim2 = 2):
sagun98
parents:
diff changeset
223 """
sagun98
parents:
diff changeset
224 Plots the provided data by the given distance matrix in the file.
sagun98
parents:
diff changeset
225 All lists should be in order in relation to each other.
sagun98
parents:
diff changeset
226
sagun98
parents:
diff changeset
227 :param tempPlotName: Path of file to save figure.
sagun98
parents:
diff changeset
228 :type: String File path.
sagun98
parents:
diff changeset
229 :param tempColorGrouping: Colors for markers.
sagun98
parents:
diff changeset
230 If you want a marker with multiple colors (piewedges) for that marker give a list in the list of colors.
sagun98
parents:
diff changeset
231 For example ['r','r','r',['r','g','b']] This would make 3 red markers and 1 split into 3 wedges (red, green, and blue).
sagun98
parents:
diff changeset
232 This is only possible if you are using circle shapes ('o') or square shapes ('s').
sagun98
parents:
diff changeset
233 :type: Character or list of characters: Characters should be useable by matplotlib as a color.
sagun98
parents:
diff changeset
234 :param tempShape: Marker shapes. If you want to specify one shape for all markers then just pass a char/str for the marker not a list.
sagun98
parents:
diff changeset
235 :type: Character or list of characters. Characters should be useable by matplotlib as shapes.
sagun98
parents:
diff changeset
236 :param tempLabels: Labels associated with the coloring. Should be consistent with tempColorGrouping (both should be strings or lists of equal length).
sagun98
parents:
diff changeset
237 :type: String or list of Strings.
sagun98
parents:
diff changeset
238 :param tempShapeSize: Sizes of markers (points). If no list is given, all markers are given the same size.
sagun98
parents:
diff changeset
239 :type: Integer of list of integers: 1 or greater.
sagun98
parents:
diff changeset
240 :param tempAlpha: Value between 0.0 and 1.0 (0.0 being completely transparent, 1.0 being opaque).
sagun98
parents:
diff changeset
241 :type: Float 0.0-1.0.
sagun98
parents:
diff changeset
242 :param tempLegendLocation: Indicates where to put the legend.
sagun98
parents:
diff changeset
243 :type: String Either "upper right", "lower right", "upper left", "lower left".
sagun98
parents:
diff changeset
244 :param tempInvert: Allows the inverting of the figure.
sagun98
parents:
diff changeset
245 :type: boolean True inverts.
sagun98
parents:
diff changeset
246 :param iDim1: First dimension to plot.
sagun98
parents:
diff changeset
247 :type: Integer Greater than 1.
sagun98
parents:
diff changeset
248 :param iDim2: Second dimension to plot.
sagun98
parents:
diff changeset
249 :type: Integer Greater than 1.
sagun98
parents:
diff changeset
250 :return boolean: Indicator of success (True)
sagun98
parents:
diff changeset
251 """
sagun98
parents:
diff changeset
252
sagun98
parents:
diff changeset
253 if(not self.pcoa == None):
sagun98
parents:
diff changeset
254
sagun98
parents:
diff changeset
255 #Get point count
sagun98
parents:
diff changeset
256 iDimensionOne = max(0,min(self._iDimensions-2, iDim1-1))
sagun98
parents:
diff changeset
257 iDimensionTwo = max(1,min(self._iDimensions-1, iDim2-1))
sagun98
parents:
diff changeset
258 adPoints = self.pcoa.getPoints()
sagun98
parents:
diff changeset
259
sagun98
parents:
diff changeset
260 #This is 1-stress which is the amount of variance not explained by all dimensions
sagun98
parents:
diff changeset
261 #There is no precent variance, so I am trying this as a substitute
sagun98
parents:
diff changeset
262 dPercentVariance = int((1.0-self.pcoa.getStress())*100)
sagun98
parents:
diff changeset
263 ldXPoints = list(adPoints[:,iDimensionOne])
sagun98
parents:
diff changeset
264 if not (self.ldForcedXAxis == None):
sagun98
parents:
diff changeset
265 ldXPoints = self.ldForcedXAxis
sagun98
parents:
diff changeset
266 ldYPoints = list(adPoints[:,iDimensionTwo])
sagun98
parents:
diff changeset
267 iPointCount = len(ldXPoints)
sagun98
parents:
diff changeset
268
sagun98
parents:
diff changeset
269 #Get plot object
sagun98
parents:
diff changeset
270 imgFigure = plt.figure()
sagun98
parents:
diff changeset
271 self.objFigureControl.invertColors(fInvert=tempInvert)
sagun98
parents:
diff changeset
272
sagun98
parents:
diff changeset
273 #Manage Labels
sagun98
parents:
diff changeset
274 if tempLabels is None:
sagun98
parents:
diff changeset
275 tempLabels = [self.objFigureControl.c_strPCoALabelDefault] * iPointCount
sagun98
parents:
diff changeset
276 elif(ValidateData.funcIsValidList(tempLabels)):
sagun98
parents:
diff changeset
277 if not len(tempLabels) == iPointCount:
sagun98
parents:
diff changeset
278 print "PCoA::plot:Error, the list of labels was given but was not the same length as the points so nothing was plotted."
sagun98
parents:
diff changeset
279 print "PCoA::plot:tempLabels=", tempLabels
sagun98
parents:
diff changeset
280 print "PCoA::plot:Label list length=", len(tempLabels)
sagun98
parents:
diff changeset
281 print "PCoA::plot:iPointCount=", iPointCount
sagun98
parents:
diff changeset
282 return False
sagun98
parents:
diff changeset
283 elif ValidateData.funcIsValidString(tempLabels):
sagun98
parents:
diff changeset
284 tempLabels = [tempLabels] * iPointCount
sagun98
parents:
diff changeset
285 else:
sagun98
parents:
diff changeset
286 print "PCoA::plot:tempLabels was of an unexpected type. Expecting None, List, string, or char."
sagun98
parents:
diff changeset
287 print tempLabels
sagun98
parents:
diff changeset
288 return False
sagun98
parents:
diff changeset
289
sagun98
parents:
diff changeset
290 #Manage Colors
sagun98
parents:
diff changeset
291 if tempColorGrouping is None:
sagun98
parents:
diff changeset
292 tempColorGrouping = [self.objFigureControl.c_cPCoAColorDefault] * iPointCount
sagun98
parents:
diff changeset
293 elif(ValidateData.funcIsValidList(tempColorGrouping)):
sagun98
parents:
diff changeset
294 if not len(tempColorGrouping) == iPointCount:
sagun98
parents:
diff changeset
295 print "PCoA::plot:Error, the list of colors was given but was not the same length as the points so nothing was plotted."
sagun98
parents:
diff changeset
296 print "PCoA::plot:tempColorGrouping=", tempColorGrouping
sagun98
parents:
diff changeset
297 print "PCoA::plot:Color list length=", len(tempColorGrouping)
sagun98
parents:
diff changeset
298 print "PCoA::plot:iPointCount=", iPointCount
sagun98
parents:
diff changeset
299 return False
sagun98
parents:
diff changeset
300 elif ValidateData.funcIsValidString(tempColorGrouping):
sagun98
parents:
diff changeset
301 tempColorGrouping = [tempColorGrouping] * iPointCount
sagun98
parents:
diff changeset
302 else:
sagun98
parents:
diff changeset
303 print "PCoA::plot:tempColorGrouping was of an unexpected type. Expecting None, List, string, or char."
sagun98
parents:
diff changeset
304 print tempColorGrouping
sagun98
parents:
diff changeset
305 return False
sagun98
parents:
diff changeset
306
sagun98
parents:
diff changeset
307 #Manage tempShape
sagun98
parents:
diff changeset
308 if tempShape is None:
sagun98
parents:
diff changeset
309 tempShape = [self.objFigureControl.c_cPCoAShapeDefault] * iPointCount
sagun98
parents:
diff changeset
310 elif(ValidateData.funcIsValidList(tempShape)):
sagun98
parents:
diff changeset
311 if not len(tempShape) == iPointCount:
sagun98
parents:
diff changeset
312 print "PCoA::plot:Error, the list of shapes was given but was not the same length as the points so nothing was plotted."
sagun98
parents:
diff changeset
313 print "PCoA::plot:tempShape=", tempShape
sagun98
parents:
diff changeset
314 print "PCoA::plot:Shape list length=", len(tempShape)
sagun98
parents:
diff changeset
315 print "PCoA::plot:iPointCount=", iPointCount
sagun98
parents:
diff changeset
316 return False
sagun98
parents:
diff changeset
317 elif ValidateData.funcIsValidString(tempShape):
sagun98
parents:
diff changeset
318 tempShape = [tempShape] * iPointCount
sagun98
parents:
diff changeset
319 else:
sagun98
parents:
diff changeset
320 print("PCoA::plot:tempShape was of an unexpected type. Expecting None, List, string, or char.")
sagun98
parents:
diff changeset
321 print tempShape
sagun98
parents:
diff changeset
322 return False
sagun98
parents:
diff changeset
323
sagun98
parents:
diff changeset
324 #Manage tempShapeSize
sagun98
parents:
diff changeset
325 if tempShapeSize is None:
sagun98
parents:
diff changeset
326 tempShapeSize = [self.objFigureControl.c_cPCoASizeDefault] * iPointCount
sagun98
parents:
diff changeset
327 elif(ValidateData.funcIsValidList(tempShapeSize)):
sagun98
parents:
diff changeset
328 if not len(tempShapeSize) == iPointCount:
sagun98
parents:
diff changeset
329 print "PCoA::plot:Error, the list of sizes was given but was not the same length as the points so nothing was plotted."
sagun98
parents:
diff changeset
330 print "PCoA::plot:tempShapeSize=", tempShapeSize
sagun98
parents:
diff changeset
331 print "PCoA::plot:Size list length=", len(tempShapeSize)
sagun98
parents:
diff changeset
332 print "PCoA::plot:iPointCount=", iPointCount
sagun98
parents:
diff changeset
333 return False
sagun98
parents:
diff changeset
334 elif ValidateData.funcIsValidInteger(tempShapeSize):
sagun98
parents:
diff changeset
335 tempShapeSize = [tempShapeSize] * iPointCount
sagun98
parents:
diff changeset
336 else:
sagun98
parents:
diff changeset
337 print "PCoA::plot:tempShapeSize was of an unexpected type. Expecting None, List, string, or char."
sagun98
parents:
diff changeset
338 print tempShapeSize
sagun98
parents:
diff changeset
339 return False
sagun98
parents:
diff changeset
340
sagun98
parents:
diff changeset
341 #Color/Invert figure
sagun98
parents:
diff changeset
342 imgFigure.set_facecolor(self.objFigureControl.c_strBackgroundColorWord)
sagun98
parents:
diff changeset
343 imgSubplot = imgFigure.add_subplot(111,axisbg=self.objFigureControl.c_strBackgroundColorLetter)
sagun98
parents:
diff changeset
344 imgSubplot.set_xlabel("Dimension "+str(iDimensionOne+1)+" (1-Stress = "+str(dPercentVariance)+"% )")
sagun98
parents:
diff changeset
345 imgSubplot.set_ylabel("Dimension "+str(iDimensionTwo+1))
sagun98
parents:
diff changeset
346 imgSubplot.spines['top'].set_color(self.objFigureControl.c_strDetailsColorLetter)
sagun98
parents:
diff changeset
347 imgSubplot.spines['bottom'].set_color(self.objFigureControl.c_strDetailsColorLetter)
sagun98
parents:
diff changeset
348 imgSubplot.spines['left'].set_color(self.objFigureControl.c_strDetailsColorLetter)
sagun98
parents:
diff changeset
349 imgSubplot.spines['right'].set_color(self.objFigureControl.c_strDetailsColorLetter)
sagun98
parents:
diff changeset
350 imgSubplot.xaxis.label.set_color(self.objFigureControl.c_strDetailsColorLetter)
sagun98
parents:
diff changeset
351 imgSubplot.yaxis.label.set_color(self.objFigureControl.c_strDetailsColorLetter)
sagun98
parents:
diff changeset
352 imgSubplot.tick_params(axis='x', colors=self.objFigureControl.c_strDetailsColorLetter)
sagun98
parents:
diff changeset
353 imgSubplot.tick_params(axis='y', colors=self.objFigureControl.c_strDetailsColorLetter)
sagun98
parents:
diff changeset
354 charMarkerEdgeColor = self.objFigureControl.c_strDetailsColorLetter
sagun98
parents:
diff changeset
355
sagun98
parents:
diff changeset
356 #If given a list of colors, each color will be plotted individually stratified by shape
sagun98
parents:
diff changeset
357 #Plot colors seperately so the legend will pick up on the labels and make a legend
sagun98
parents:
diff changeset
358 if(ValidateData.funcIsValidList(tempColorGrouping)):
sagun98
parents:
diff changeset
359 if len(tempColorGrouping) == iPointCount:
sagun98
parents:
diff changeset
360
sagun98
parents:
diff changeset
361 #Dictionary to hold plotting groups
sagun98
parents:
diff changeset
362 #Logistical to plot points as layers in an intelligent fashion
sagun98
parents:
diff changeset
363 #{CountofPoints: [[plot info list]]} The list happends so ties can occur in the key
sagun98
parents:
diff changeset
364 dictPlotGroups = dict()
sagun98
parents:
diff changeset
365
sagun98
parents:
diff changeset
366 #Check for lists in the list which indicate the need to plot pie charts
sagun98
parents:
diff changeset
367 lfAreLists = [ValidateData.funcIsValidList(objColor) for objIndex, objColor in enumerate(tempColorGrouping)]
sagun98
parents:
diff changeset
368
sagun98
parents:
diff changeset
369 #Pie chart data seperated out
sagun98
parents:
diff changeset
370 lsColorsPieCharts = None
sagun98
parents:
diff changeset
371 lcShapesPieCharts = None
sagun98
parents:
diff changeset
372 lsLabelsPieCharts = None
sagun98
parents:
diff changeset
373 lsSizesPieCharts = None
sagun98
parents:
diff changeset
374 ldXPointsPieCharts = None
sagun98
parents:
diff changeset
375 ldYPointsPieCharts = None
sagun98
parents:
diff changeset
376
sagun98
parents:
diff changeset
377 #Split out piechart data
sagun98
parents:
diff changeset
378 if sum(lfAreLists) > 0:
sagun98
parents:
diff changeset
379 #Get lists of index that are and are not lists
sagun98
parents:
diff changeset
380 liAreLists = []
sagun98
parents:
diff changeset
381 liAreNotLists = []
sagun98
parents:
diff changeset
382 curIndex = 0
sagun98
parents:
diff changeset
383 for fIsList in lfAreLists:
sagun98
parents:
diff changeset
384 if fIsList: liAreLists.append(curIndex)
sagun98
parents:
diff changeset
385 else: liAreNotLists.append(curIndex)
sagun98
parents:
diff changeset
386 curIndex = curIndex + 1
sagun98
parents:
diff changeset
387
sagun98
parents:
diff changeset
388 lsColorsPieCharts = Utility.reduceList(tempColorGrouping, liAreLists)
sagun98
parents:
diff changeset
389 tempColorGrouping = Utility.reduceList(tempColorGrouping, liAreNotLists)
sagun98
parents:
diff changeset
390
sagun98
parents:
diff changeset
391 #Split out shapes
sagun98
parents:
diff changeset
392 lcShapesPieCharts = Utility.reduceList(tempShape, liAreLists)
sagun98
parents:
diff changeset
393 tempShape = Utility.reduceList(tempShape, liAreNotLists)
sagun98
parents:
diff changeset
394
sagun98
parents:
diff changeset
395 #Split out labels
sagun98
parents:
diff changeset
396 lsLabelsPieCharts = Utility.reduceList(tempLabels, liAreLists)
sagun98
parents:
diff changeset
397 tempLabels = Utility.reduceList(tempLabels, liAreNotLists)
sagun98
parents:
diff changeset
398
sagun98
parents:
diff changeset
399 #Split out sizes
sagun98
parents:
diff changeset
400 lsSizesPieCharts = Utility.reduceList(tempShapeSize, liAreLists)
sagun98
parents:
diff changeset
401 tempShapeSize = Utility.reduceList(tempShapeSize, liAreNotLists)
sagun98
parents:
diff changeset
402
sagun98
parents:
diff changeset
403 #Split out xpoints
sagun98
parents:
diff changeset
404 ldXPointsPieCharts = Utility.reduceList(ldXPoints, liAreLists)
sagun98
parents:
diff changeset
405 ldXPoints = Utility.reduceList(ldXPoints, liAreNotLists)
sagun98
parents:
diff changeset
406
sagun98
parents:
diff changeset
407 #Split out ypoints
sagun98
parents:
diff changeset
408 ldYPointsPieCharts = Utility.reduceList(ldYPoints, liAreLists)
sagun98
parents:
diff changeset
409 ldYPoints = Utility.reduceList(ldYPoints, liAreNotLists)
sagun98
parents:
diff changeset
410
sagun98
parents:
diff changeset
411 #Get unique colors and plot each individually
sagun98
parents:
diff changeset
412 acharUniqueColors = list(set(tempColorGrouping))
sagun98
parents:
diff changeset
413 for iColorIndex in xrange(0,len(acharUniqueColors)):
sagun98
parents:
diff changeset
414 #Get the color
sagun98
parents:
diff changeset
415 charColor = acharUniqueColors[iColorIndex]
sagun98
parents:
diff changeset
416
sagun98
parents:
diff changeset
417 #Get indices of colors
sagun98
parents:
diff changeset
418 aiColorPointPositions = Utility.getIndices(tempColorGrouping,charColor)
sagun98
parents:
diff changeset
419
sagun98
parents:
diff changeset
420 #Reduce the labels by color
sagun98
parents:
diff changeset
421 acharLabelsByColor = Utility.reduceList(tempLabels,aiColorPointPositions)
sagun98
parents:
diff changeset
422
sagun98
parents:
diff changeset
423 #Reduces sizes to indices if a list
sagun98
parents:
diff changeset
424 reducedSizes = tempShapeSize
sagun98
parents:
diff changeset
425 #Reduce sizes if a list
sagun98
parents:
diff changeset
426 if(ValidateData.funcIsValidList(reducedSizes)):
sagun98
parents:
diff changeset
427 reducedSizes = Utility.reduceList(reducedSizes,aiColorPointPositions)
sagun98
parents:
diff changeset
428
sagun98
parents:
diff changeset
429 #Reduce to the current color grouping
sagun98
parents:
diff changeset
430 aiXPoints = Utility.reduceList(ldXPoints,aiColorPointPositions)
sagun98
parents:
diff changeset
431 aiYPoints = Utility.reduceList(ldYPoints,aiColorPointPositions)
sagun98
parents:
diff changeset
432
sagun98
parents:
diff changeset
433 #There are 3 options for shapes which are checked in this order.
sagun98
parents:
diff changeset
434 #1. 1 shape character is given which is used for all markers
sagun98
parents:
diff changeset
435 #2. A list is given of marker characters or lists of decimals which will be used to make pie chart markers
sagun98
parents:
diff changeset
436 #This is handled after the rest this block of code
sagun98
parents:
diff changeset
437 #3. A list of char are given each indicating the marker for a sample
sagun98
parents:
diff changeset
438 #If the shapes are not a list plot
sagun98
parents:
diff changeset
439 #Otherwise plot per shape per color (can not plot list of shapes in matplotlib)
sagun98
parents:
diff changeset
440 reducedShapes = tempShape
sagun98
parents:
diff changeset
441 if(not ValidateData.funcIsValidList(reducedShapes)):
sagun98
parents:
diff changeset
442 reducedShapes = reducedShapes[0]
sagun98
parents:
diff changeset
443 dictPlotGroups.setdefault(len(aiXPoints), []).append([aiXPoints,aiYPoints,[charColor],reducedShapes,tempAlpha,tempLabels[tempColorGrouping.index(charColor)],reducedSizes,charMarkerEdgeColor])
sagun98
parents:
diff changeset
444 #Shapes are supplied as a list so plot each shape
sagun98
parents:
diff changeset
445 else:
sagun98
parents:
diff changeset
446 #Reduce to shapes of the current colors
sagun98
parents:
diff changeset
447 reducedShapes = Utility.reduceList(reducedShapes,aiColorPointPositions)
sagun98
parents:
diff changeset
448 acharReducedShapesElements = list(set(reducedShapes))
sagun98
parents:
diff changeset
449 #If there are multiple shapes, plot seperately because one is not allowed to plot them as a list
sagun98
parents:
diff changeset
450 for aCharShapeElement in acharReducedShapesElements:
sagun98
parents:
diff changeset
451 #Get indices
sagun98
parents:
diff changeset
452 aiShapeIndices = Utility.getIndices(reducedShapes,aCharShapeElement)
sagun98
parents:
diff changeset
453 #Reduce label by shapes
sagun98
parents:
diff changeset
454 strShapeLabel = Utility.reduceList(acharLabelsByColor,aiShapeIndices)
sagun98
parents:
diff changeset
455 #Reduce sizes by shapes
sagun98
parents:
diff changeset
456 strShapeSizes = reducedSizes
sagun98
parents:
diff changeset
457 if ValidateData.funcIsValidList(reducedSizes):
sagun98
parents:
diff changeset
458 strShapeSizes = Utility.reduceList(reducedSizes,aiShapeIndices)
sagun98
parents:
diff changeset
459 #Get points per shape
sagun98
parents:
diff changeset
460 aiXPointsPerShape = Utility.reduceList(aiXPoints,aiShapeIndices)
sagun98
parents:
diff changeset
461 aiYPointsPerShape = Utility.reduceList(aiYPoints,aiShapeIndices)
sagun98
parents:
diff changeset
462 #Get sizes per shape
sagun98
parents:
diff changeset
463 #Reduce sizes if a list
sagun98
parents:
diff changeset
464 reducedSizesPerShape = reducedSizes
sagun98
parents:
diff changeset
465 if(ValidateData.funcIsValidList(reducedSizes)):
sagun98
parents:
diff changeset
466 reducedSizesPerShape = Utility.reduceList(reducedSizes,aiShapeIndices)
sagun98
parents:
diff changeset
467 #Put plot data in dict of lists for later plotting
sagun98
parents:
diff changeset
468 #Separate out the background printing
sagun98
parents:
diff changeset
469 dictPlotGroups.setdefault(len(aiXPointsPerShape), []).append([aiXPointsPerShape,aiYPointsPerShape,[charColor],aCharShapeElement,tempAlpha,strShapeLabel[0],strShapeSizes,charMarkerEdgeColor])
sagun98
parents:
diff changeset
470
sagun98
parents:
diff changeset
471 #Plot each color starting with largest color amount to smallest color anmount so small groups will not be covered up by larger groups
sagun98
parents:
diff changeset
472 #Plot other colors in increasing order
sagun98
parents:
diff changeset
473 for sPlotGroupKey in sorted(list(dictPlotGroups.keys()), reverse=True):
sagun98
parents:
diff changeset
474 lslsCurPlotGroup = dictPlotGroups[sPlotGroupKey]
sagun98
parents:
diff changeset
475 #Plot
sagun98
parents:
diff changeset
476 for lsGroup in lslsCurPlotGroup:
sagun98
parents:
diff changeset
477 imgSubplot.scatter(lsGroup[self.c_iXPointIndex],
sagun98
parents:
diff changeset
478 lsGroup[self.c_iYPointIndex],
sagun98
parents:
diff changeset
479 c = lsGroup[self.c_iColorIndex],
sagun98
parents:
diff changeset
480 marker = lsGroup[self.c_iMarkerIndex],
sagun98
parents:
diff changeset
481 alpha = lsGroup[self.c_iAlphaIndex],
sagun98
parents:
diff changeset
482 label = lsGroup[self.c_iLabelIndex],
sagun98
parents:
diff changeset
483 s = lsGroup[self.c_iShapeIndex],
sagun98
parents:
diff changeset
484 edgecolor = lsGroup[self.c_iEdgeColorIndex])
sagun98
parents:
diff changeset
485
sagun98
parents:
diff changeset
486 #Plot pie charts
sagun98
parents:
diff changeset
487 if not lsColorsPieCharts is None:
sagun98
parents:
diff changeset
488 self.plotWithPieMarkers(imgSubplot=imgSubplot, aiXPoints=ldXPointsPieCharts, aiYPoints=ldYPointsPieCharts, dSize=lsSizesPieCharts, llColors=lsColorsPieCharts, lsLabels=lsLabelsPieCharts, lcShapes=lcShapesPieCharts, edgeColor=charMarkerEdgeColor, dAlpha=tempAlpha)
sagun98
parents:
diff changeset
489
sagun98
parents:
diff changeset
490 objLegend = imgSubplot.legend(loc=tempLegendLocation, scatterpoints=1, prop={'size':10})
sagun98
parents:
diff changeset
491
sagun98
parents:
diff changeset
492 #Invert legend
sagun98
parents:
diff changeset
493 if(tempInvert):
sagun98
parents:
diff changeset
494 if objLegend:
sagun98
parents:
diff changeset
495 objLegend.legendPatch.set_fc(self.objFigureControl.c_strBackgroundColorWord)
sagun98
parents:
diff changeset
496 objLegend.legendPatch.set_ec(self.objFigureControl.c_strDetailsColorLetter)
sagun98
parents:
diff changeset
497 plt.setp(objLegend.get_texts(),color=self.objFigureControl.c_strDetailsColorLetter)
sagun98
parents:
diff changeset
498
sagun98
parents:
diff changeset
499 #Make legend background transparent
sagun98
parents:
diff changeset
500 if objLegend:
sagun98
parents:
diff changeset
501 objLegendFrame = objLegend.get_frame()
sagun98
parents:
diff changeset
502 objLegendFrame.set_alpha(self.objFigureControl.c_dAlpha)
sagun98
parents:
diff changeset
503
sagun98
parents:
diff changeset
504 imgFigure.savefig(tempPlotName, facecolor=imgFigure.get_facecolor())
sagun98
parents:
diff changeset
505 return True
sagun98
parents:
diff changeset
506
sagun98
parents:
diff changeset
507 #Indirectly tested
sagun98
parents:
diff changeset
508 def plotWithPieMarkers(self, imgSubplot, aiXPoints, aiYPoints, dSize, llColors, lsLabels, lcShapes, edgeColor, dAlpha):
sagun98
parents:
diff changeset
509 """
sagun98
parents:
diff changeset
510 The all lists should be in the same order
sagun98
parents:
diff changeset
511
sagun98
parents:
diff changeset
512 :param imgSubPlot: Image to plot to
sagun98
parents:
diff changeset
513 :type: Image
sagun98
parents:
diff changeset
514 :param aiXPoints: List of X axis points (one element per color list)
sagun98
parents:
diff changeset
515 :type: List of Floats
sagun98
parents:
diff changeset
516 :param aiYPoints: List of X axis points (one element per color list)
sagun98
parents:
diff changeset
517 :type: List of Floats
sagun98
parents:
diff changeset
518 :param dSize: double or List of doubles (one element per color list)
sagun98
parents:
diff changeset
519 :type: List of Floats
sagun98
parents:
diff changeset
520 :param llColors: List of Lists of colors, one list of colors is for 1 piechart/multiply highlighted feature
sagun98
parents:
diff changeset
521 Example ["red","blue","green"] for a marker with 3 sections.
sagun98
parents:
diff changeset
522 :type: List of strings
sagun98
parents:
diff changeset
523 :param lsLabels: List of labels (one element per color list).
sagun98
parents:
diff changeset
524 :type: List of Floats
sagun98
parents:
diff changeset
525 :param lcShapes: Indicates which shape of a pie chart to use, currently supported 'o' and 's' (one element per color list).
sagun98
parents:
diff changeset
526 :type: List of characters
sagun98
parents:
diff changeset
527 :param edgeColor: One color entry for the edge of the piechart.
sagun98
parents:
diff changeset
528 :type: List of characters
sagun98
parents:
diff changeset
529 :param dAlpha: Value between 0.0 and 1.0 (0.0 being completely transparent, 1.0 being opaque).
sagun98
parents:
diff changeset
530 :type: Float 0.0-1.0.
sagun98
parents:
diff changeset
531 """
sagun98
parents:
diff changeset
532
sagun98
parents:
diff changeset
533 #Zip up points to pairs
sagun98
parents:
diff changeset
534 xyPoints = zip(aiXPoints,aiYPoints)
sagun98
parents:
diff changeset
535 #For each pair of points
sagun98
parents:
diff changeset
536 for iIndex,dXY in enumerate(xyPoints):
sagun98
parents:
diff changeset
537 ldWedges = []
sagun98
parents:
diff changeset
538 #Get colors
sagun98
parents:
diff changeset
539 lcurColors = llColors[iIndex]
sagun98
parents:
diff changeset
540 #Get pie cut shape
sagun98
parents:
diff changeset
541 cPieChartType = lcShapes[iIndex]
sagun98
parents:
diff changeset
542 if cPieChartType == ConstantsFiguresBreadCrumbs().c_charPCOAPieChart:
sagun98
parents:
diff changeset
543 ldWedges = self.makePieWedges(len(lcurColors),20)
sagun98
parents:
diff changeset
544 elif cPieChartType == ConstantsFiguresBreadCrumbs().c_charPCOASquarePieChart:
sagun98
parents:
diff changeset
545 ldWedges = self.makeSquarePieWedges(len(lcurColors))
sagun98
parents:
diff changeset
546 for iWedgeIndex,dWedge in enumerate(ldWedges):
sagun98
parents:
diff changeset
547 imgSubplot.scatter(x=dXY[0], y=dXY[1], marker=(dWedge,0), s=dSize[iIndex], label=lsLabels[iIndex], facecolor=lcurColors[iWedgeIndex], edgecolor=edgeColor, alpha=dAlpha)
sagun98
parents:
diff changeset
548
sagun98
parents:
diff changeset
549 #Indirectly tested
sagun98
parents:
diff changeset
550 def makePieWedges(self, iWedgeCount, iSplineResolution = 10):
sagun98
parents:
diff changeset
551 """
sagun98
parents:
diff changeset
552 Generate a list of tuple points which will draw a square broken up into pie cuts.
sagun98
parents:
diff changeset
553
sagun98
parents:
diff changeset
554 :param iWedgeCount: The number of piecuts in the square.
sagun98
parents:
diff changeset
555 :type: Integer Number greater than 1.
sagun98
parents:
diff changeset
556 :param iSplineResolution: The amount of smoothing to the circle's outer edge, the higher the number the more smooth.
sagun98
parents:
diff changeset
557 :type: integer Greater than 1.
sagun98
parents:
diff changeset
558 :return list List of tuples. Each tuple is a point, formatted for direct plotting of the marker.
sagun98
parents:
diff changeset
559 """
sagun98
parents:
diff changeset
560
sagun98
parents:
diff changeset
561 ldWedge = []
sagun98
parents:
diff changeset
562 dLastValue = 0.0
sagun98
parents:
diff changeset
563
sagun98
parents:
diff changeset
564 #Create a list of equal percentages for all wedges
sagun98
parents:
diff changeset
565 #Do not include a last wedge it gets all the space from the 2nd to last wedge to the end
sagun98
parents:
diff changeset
566 #Which should still be equal to the others
sagun98
parents:
diff changeset
567 ldPercentages = [1.0/iWedgeCount]*(iWedgeCount-1)
sagun98
parents:
diff changeset
568
sagun98
parents:
diff changeset
569 for dPercentage in ldPercentages:
sagun98
parents:
diff changeset
570 ldX = [0] + np.cos(np.linspace(2*math.pi*dLastValue,2*math.pi*(dLastValue+dPercentage),iSplineResolution)).tolist()
sagun98
parents:
diff changeset
571 ldY = [0] + np.sin(np.linspace(2*math.pi*dLastValue,2*math.pi*(dLastValue+dPercentage),iSplineResolution)).tolist()
sagun98
parents:
diff changeset
572 ldWedge.append(zip(ldX,ldY))
sagun98
parents:
diff changeset
573 dLastValue = dLastValue+dPercentage
sagun98
parents:
diff changeset
574 ldX = [0] + np.cos(np.linspace(2*math.pi*dLastValue,2*math.pi,iSplineResolution)).tolist()
sagun98
parents:
diff changeset
575 ldY = [0] + np.sin(np.linspace(2*math.pi*dLastValue,2*math.pi,iSplineResolution)).tolist()
sagun98
parents:
diff changeset
576 ldWedge.append(zip(ldX,ldY))
sagun98
parents:
diff changeset
577 return ldWedge
sagun98
parents:
diff changeset
578
sagun98
parents:
diff changeset
579 #Indirectly tested
sagun98
parents:
diff changeset
580 def makeSquarePieWedges(self, iWedgeCount):
sagun98
parents:
diff changeset
581 """
sagun98
parents:
diff changeset
582 Generate a list of tuple points which will draw a square broken up into pie cuts.
sagun98
parents:
diff changeset
583
sagun98
parents:
diff changeset
584 :param iWedgeCount: The number of piecuts in the square.
sagun98
parents:
diff changeset
585 :type: Integer Number greater than 1.
sagun98
parents:
diff changeset
586 :return list List of tuples. Each tuple is a point, formatted for direct plotting of the marker.
sagun98
parents:
diff changeset
587 """
sagun98
parents:
diff changeset
588
sagun98
parents:
diff changeset
589 ldWedge = []
sagun98
parents:
diff changeset
590 dLastPercentageValue = 0.0
sagun98
parents:
diff changeset
591 dLastSquareValue = 0.0
sagun98
parents:
diff changeset
592 dCumulativePercentageValue = 0.0
sagun98
parents:
diff changeset
593 dRadius = None
sagun98
parents:
diff changeset
594 fXYSwitched = False
sagun98
parents:
diff changeset
595 fAfterCorner = False
sagun98
parents:
diff changeset
596 iSwitchCounts = 0
sagun98
parents:
diff changeset
597 iMagicNumber =(1.0/4)
sagun98
parents:
diff changeset
598
sagun98
parents:
diff changeset
599 #Create a list of equal percentages for all wedges
sagun98
parents:
diff changeset
600 #Do not include a last wedge it gets all the space from the 2nd to last wedge to the end
sagun98
parents:
diff changeset
601 #Which should still be equal to the others
sagun98
parents:
diff changeset
602 ldPercentages = [1.0/iWedgeCount]*(iWedgeCount)
sagun98
parents:
diff changeset
603
sagun98
parents:
diff changeset
604 for dPercentage in ldPercentages:
sagun98
parents:
diff changeset
605 ldCircleXs = np.cos([2*math.pi*dLastPercentageValue,2*math.pi*(dLastPercentageValue+dPercentage)])
sagun98
parents:
diff changeset
606 ldCircleYs = np.sin([2*math.pi*dLastPercentageValue,2*math.pi*(dLastPercentageValue+dPercentage)])
sagun98
parents:
diff changeset
607
sagun98
parents:
diff changeset
608 if dRadius == None:
sagun98
parents:
diff changeset
609 dRadius = ldCircleXs[0]
sagun98
parents:
diff changeset
610
sagun98
parents:
diff changeset
611 #Check to see if at corner
sagun98
parents:
diff changeset
612 fAtCorner = False
sagun98
parents:
diff changeset
613 iDistance = int((dLastPercentageValue+dPercentage+(iMagicNumber/2))/iMagicNumber
sagun98
parents:
diff changeset
614 ) - int((dLastPercentageValue+(iMagicNumber/2))/iMagicNumber)
sagun98
parents:
diff changeset
615 if(iDistance > 0):
sagun98
parents:
diff changeset
616 fAtCorner = True
sagun98
parents:
diff changeset
617 if iDistance > 1:
sagun98
parents:
diff changeset
618 fXYSwitched = not fXYSwitched
sagun98
parents:
diff changeset
619 iSwitchCounts = iSwitchCounts + 1
sagun98
parents:
diff changeset
620
sagun98
parents:
diff changeset
621 #Check to see if at a side center
sagun98
parents:
diff changeset
622 fAtSide = False
sagun98
parents:
diff changeset
623 if (int((dLastPercentageValue+dPercentage)/iMagicNumber) > int(dLastPercentageValue/iMagicNumber)):
sagun98
parents:
diff changeset
624 fAtSide = True
sagun98
parents:
diff changeset
625
sagun98
parents:
diff changeset
626 #Handle corner xy switching
sagun98
parents:
diff changeset
627 if fAtCorner:
sagun98
parents:
diff changeset
628 fXYSwitched = not fXYSwitched
sagun98
parents:
diff changeset
629 iSwitchCounts = iSwitchCounts + 1
sagun98
parents:
diff changeset
630 #Make sure the xy switching occurs to vary the slope at the corner.
sagun98
parents:
diff changeset
631 if fXYSwitched:
sagun98
parents:
diff changeset
632 ldCircleXs,ldCircleYs = ldCircleYs,ldCircleXs
sagun98
parents:
diff changeset
633
sagun98
parents:
diff changeset
634 dSquarePoint = dRadius * (ldCircleYs[1]/float(ldCircleXs[1]))
sagun98
parents:
diff changeset
635 dRadiusSq1 = dRadius
sagun98
parents:
diff changeset
636 dRadiusSq2 = dRadius
sagun98
parents:
diff changeset
637 dLastSquareValueSq = dLastSquareValue
sagun98
parents:
diff changeset
638 dSquarePointSq = dSquarePoint
sagun98
parents:
diff changeset
639
sagun98
parents:
diff changeset
640 #If in quadrants 2,3 make sign changes
sagun98
parents:
diff changeset
641 if iSwitchCounts in [2,3]:
sagun98
parents:
diff changeset
642 if iSwitchCounts == 2:
sagun98
parents:
diff changeset
643 dRadiusSq1 = dRadiusSq1 *-1
sagun98
parents:
diff changeset
644 elif iSwitchCounts == 3:
sagun98
parents:
diff changeset
645 dRadiusSq1 = dRadiusSq1 * -1
sagun98
parents:
diff changeset
646 dRadiusSq2 = dRadiusSq2 * -1
sagun98
parents:
diff changeset
647 dLastSquareValueSq = dLastSquareValueSq * -1.0
sagun98
parents:
diff changeset
648 dSquarePointSq = dSquarePointSq * -1.0
sagun98
parents:
diff changeset
649
sagun98
parents:
diff changeset
650 if fAtCorner:
sagun98
parents:
diff changeset
651 #Corner 1
sagun98
parents:
diff changeset
652 if iSwitchCounts==1:
sagun98
parents:
diff changeset
653 ldWedge.append(zip([0,dRadiusSq1,dRadiusSq1,dSquarePointSq,0],[0,dLastSquareValueSq,dRadiusSq2,dRadiusSq2,0]))
sagun98
parents:
diff changeset
654 #Corner 2
sagun98
parents:
diff changeset
655 elif iSwitchCounts==2:
sagun98
parents:
diff changeset
656 if iDistance > 1:
sagun98
parents:
diff changeset
657 ldWedge.append(zip([0,-dRadiusSq1,-dRadiusSq1,dRadiusSq1,dRadiusSq1,0],[0,-dLastSquareValueSq,dRadiusSq2,dRadiusSq2,dSquarePointSq,0]))
sagun98
parents:
diff changeset
658 else:
sagun98
parents:
diff changeset
659 ldWedge.append(zip([0,-dLastSquareValueSq,dRadiusSq1,dRadiusSq1,0],[0,dRadiusSq2,dRadiusSq2,dSquarePointSq,0]))
sagun98
parents:
diff changeset
660 #Corner 3
sagun98
parents:
diff changeset
661 elif iSwitchCounts==3:
sagun98
parents:
diff changeset
662 if iDistance > 1:
sagun98
parents:
diff changeset
663 ldWedge.append(zip([0,-dLastSquareValueSq,dRadiusSq1,dRadiusSq1,dSquarePointSq,0],[0,-dRadiusSq2,-dRadiusSq2,dRadiusSq2,dRadiusSq2,0]))
sagun98
parents:
diff changeset
664 else:
sagun98
parents:
diff changeset
665 ldWedge.append(zip([0,dRadiusSq1,dRadiusSq1,dSquarePointSq,0],[0,dLastSquareValueSq,dRadiusSq2,dRadiusSq2,0]))
sagun98
parents:
diff changeset
666 #Corner 4
sagun98
parents:
diff changeset
667 elif iSwitchCounts==4:
sagun98
parents:
diff changeset
668 if iDistance > 1:
sagun98
parents:
diff changeset
669 ldWedge.append(zip([0,-dRadiusSq1,-dRadiusSq1,dRadiusSq1,dRadiusSq1,0],[0,-dLastSquareValueSq,-dRadiusSq2,-dRadiusSq2,dSquarePointSq,0]))
sagun98
parents:
diff changeset
670 else:
sagun98
parents:
diff changeset
671 ldWedge.append(zip([0,(-1.0*dLastSquareValueSq),dRadiusSq1,dRadiusSq1,0],[0,(-1.0*dRadiusSq2),(-1.0*dRadiusSq2),dSquarePointSq,0]))
sagun98
parents:
diff changeset
672
sagun98
parents:
diff changeset
673 fAfterCorner = True
sagun98
parents:
diff changeset
674 else:
sagun98
parents:
diff changeset
675 if iSwitchCounts%2:
sagun98
parents:
diff changeset
676 ldWedge.append(zip([0,dLastSquareValueSq,dSquarePointSq,0],[0,dRadiusSq2,dRadiusSq2,0]))
sagun98
parents:
diff changeset
677 else:
sagun98
parents:
diff changeset
678 ldWedge.append(zip([0,dRadiusSq1,dRadiusSq1,0],[0,dLastSquareValueSq,dSquarePointSq,0]))
sagun98
parents:
diff changeset
679
sagun98
parents:
diff changeset
680 dLastSquareValue = dSquarePoint
sagun98
parents:
diff changeset
681 dCumulativePercentageValue = dCumulativePercentageValue + dLastSquareValue
sagun98
parents:
diff changeset
682 dLastPercentageValue = dLastPercentageValue+dPercentage
sagun98
parents:
diff changeset
683
sagun98
parents:
diff changeset
684 return ldWedge
sagun98
parents:
diff changeset
685
sagun98
parents:
diff changeset
686 #Happy Path Tested
sagun98
parents:
diff changeset
687 def plotList(self, lsLabelList, strOutputFileName, iSize=20, dAlpha=1.0, charForceColor=None, charForceShape=None, fInvert=False, iDim1=1, iDim2=2):
sagun98
parents:
diff changeset
688 """
sagun98
parents:
diff changeset
689 Convenience method used to plot data in the PCoA given a label list (which is in order of the underlying data).
sagun98
parents:
diff changeset
690 This is for the scenario where you do not care that the color or shape of the data will be as long as it varies
sagun98
parents:
diff changeset
691 with the label.
sagun98
parents:
diff changeset
692 This method does allow forcing color or shape to 1 character so that they do not vary with the label but are one value.
sagun98
parents:
diff changeset
693 This is helpful when you have a large number of labels to plot given the shapes in the PCoA are limited but not the coloring.
sagun98
parents:
diff changeset
694
sagun98
parents:
diff changeset
695 :param lsLabelList: List of string labels which are in order of the data in the PCoA object (as the data was loaded the PCoA object).
sagun98
parents:
diff changeset
696 :type: List of strings
sagun98
parents:
diff changeset
697 :param strOutputFileName: File path to save figure.
sagun98
parents:
diff changeset
698 :type: String
sagun98
parents:
diff changeset
699 :param iSize: Size of marker. Default 20.
sagun98
parents:
diff changeset
700 :type: Integer
sagun98
parents:
diff changeset
701 :param dAlpha: Alpha for the markers. (0.0 tranparent, 1.0 opaque)
sagun98
parents:
diff changeset
702 :type: Double between 0.0 and 1.0
sagun98
parents:
diff changeset
703 :param charForceColor: Color to force the points to. (Must be understandable by matplotlib as a color [ie. 'k','m','c','r','g','b','y','w'])
sagun98
parents:
diff changeset
704 :type: Character
sagun98
parents:
diff changeset
705 :param charForceShape: Shape to force the points to. (Must be understandable by matplotlib as a shape [ie. 'o','s','^','v','<','>','8','p','h'])
sagun98
parents:
diff changeset
706 :type: Character
sagun98
parents:
diff changeset
707 :param fInvert: Allows one to invert the background and plot details from white to black (True == background is black).
sagun98
parents:
diff changeset
708 :type: Boolean
sagun98
parents:
diff changeset
709 :param iDim1: The first dimension to plot
sagun98
parents:
diff changeset
710 :type: Integer starting at 1
sagun98
parents:
diff changeset
711 :param iDim2: The second dimension to plot
sagun98
parents:
diff changeset
712 :type: Integer starting at 2
sagun98
parents:
diff changeset
713 :return boolean: Indicator of success (True)
sagun98
parents:
diff changeset
714 """
sagun98
parents:
diff changeset
715
sagun98
parents:
diff changeset
716 #Get uniqueValues for labels
sagun98
parents:
diff changeset
717 acharUniqueValues = list(set(lsLabelList))
sagun98
parents:
diff changeset
718 iCountUniqueValues = len(acharUniqueValues)
sagun98
parents:
diff changeset
719
sagun98
parents:
diff changeset
720 #Set colors
sagun98
parents:
diff changeset
721 atupldLabelColors = None
sagun98
parents:
diff changeset
722
sagun98
parents:
diff changeset
723 #Set shapes
sagun98
parents:
diff changeset
724 alLabelShapes = None
sagun98
parents:
diff changeset
725 if charForceShape == None:
sagun98
parents:
diff changeset
726 #Get shapes
sagun98
parents:
diff changeset
727 acharShapes = PCoA.getShapes(iCountUniqueValues)
sagun98
parents:
diff changeset
728 if len(acharShapes) == 0:
sagun98
parents:
diff changeset
729 return False
sagun98
parents:
diff changeset
730 #Make label shapes
sagun98
parents:
diff changeset
731 alLabelShapes = [ acharShapes[acharUniqueValues.index(sMetadata)] for sMetadata in lsLabelList ]
sagun98
parents:
diff changeset
732 else:
sagun98
parents:
diff changeset
733 alLabelShapes = charForceShape
sagun98
parents:
diff changeset
734
sagun98
parents:
diff changeset
735 #If the coloring is not forced, color so it is based on the labels
sagun98
parents:
diff changeset
736 if charForceColor == None:
sagun98
parents:
diff changeset
737 #Get colors based on labels
sagun98
parents:
diff changeset
738 atupldColors = [Utility.RGBToHex(cm.jet(float(iUniqueValueIndex)/float(iCountUniqueValues))) for iUniqueValueIndex in xrange(0,iCountUniqueValues)]
sagun98
parents:
diff changeset
739 #Make sure generated colors are unique
sagun98
parents:
diff changeset
740 if not iCountUniqueValues == len(set(atupldColors)):
sagun98
parents:
diff changeset
741 print "PCoA::plotList:Error, generated colors were not unique for each unique label value."
sagun98
parents:
diff changeset
742 print "Labels"
sagun98
parents:
diff changeset
743 print lsLabelList
sagun98
parents:
diff changeset
744 print len(lsLabelList)
sagun98
parents:
diff changeset
745 print "Unique Labels"
sagun98
parents:
diff changeset
746 print set(lsLabelList)
sagun98
parents:
diff changeset
747 print len(set(lsLabelList))
sagun98
parents:
diff changeset
748 print "Colors"
sagun98
parents:
diff changeset
749 print atupldColors
sagun98
parents:
diff changeset
750 print len(atupldColors)
sagun98
parents:
diff changeset
751 print "Unique Colors"
sagun98
parents:
diff changeset
752 print set(atupldColors)
sagun98
parents:
diff changeset
753 print len(set(atupldColors))
sagun98
parents:
diff changeset
754 return False
sagun98
parents:
diff changeset
755 #Make label coloring
sagun98
parents:
diff changeset
756 atupldLabelColors = [ atupldColors[acharUniqueValues.index(sMetadata)] for sMetadata in lsLabelList ]
sagun98
parents:
diff changeset
757 #If the coloring is forced, color so it is based on the charForcedColor list
sagun98
parents:
diff changeset
758 elif(ValidateData.funcIsValidList(charForceColor)):
sagun98
parents:
diff changeset
759 atupldLabelColors = charForceColor[0]
sagun98
parents:
diff changeset
760 if not len(lsLabelList) == len(atupldLabelColors):
sagun98
parents:
diff changeset
761 print "PCoA::plotList:Error, label and forced color lengths were not the same."
sagun98
parents:
diff changeset
762 print "Labels"
sagun98
parents:
diff changeset
763 print lsLabelList
sagun98
parents:
diff changeset
764 print len(lsLabelList)
sagun98
parents:
diff changeset
765 print "Forced Colors"
sagun98
parents:
diff changeset
766 print charForceColor[0]
sagun98
parents:
diff changeset
767 print len(charForceColor[0])
sagun98
parents:
diff changeset
768 return False
sagun98
parents:
diff changeset
769 lsLabelList = [ "".join([charForceColor[1][iLabelIndex], "_", lsLabelList[iLabelIndex]]) for iLabelIndex in xrange(0,len(charForceColor[1]))]
sagun98
parents:
diff changeset
770 #If the color is forced but the color does not vary, color all markers are the same.
sagun98
parents:
diff changeset
771 else:
sagun98
parents:
diff changeset
772 atupldLabelColors = charForceColor
sagun98
parents:
diff changeset
773
sagun98
parents:
diff changeset
774 #Call plot
sagun98
parents:
diff changeset
775 self.plot(tempPlotName=strOutputFileName, tempColorGrouping=atupldLabelColors, tempShape=alLabelShapes, tempLabels=lsLabelList, tempShapeSize = iSize, tempAlpha=dAlpha, tempInvert = fInvert, iDim1=iDim1, iDim2=iDim2)
sagun98
parents:
diff changeset
776
sagun98
parents:
diff changeset
777 def funcForceXAxis(self, dList):
sagun98
parents:
diff changeset
778 """
sagun98
parents:
diff changeset
779 Force the X axis to the given list.
sagun98
parents:
diff changeset
780
sagun98
parents:
diff changeset
781 :param dList: List of values to force the x axis of the plot (floats).
sagun98
parents:
diff changeset
782 :type: List of floats
sagun98
parents:
diff changeset
783 """
sagun98
parents:
diff changeset
784
sagun98
parents:
diff changeset
785 self.ldForcedXAxis = dList
sagun98
parents:
diff changeset
786
sagun98
parents:
diff changeset
787 def funcUnforceXAxis(self):
sagun98
parents:
diff changeset
788 """
sagun98
parents:
diff changeset
789 Return the X axis to the values derived from the loaded data.
sagun98
parents:
diff changeset
790 """
sagun98
parents:
diff changeset
791
sagun98
parents:
diff changeset
792 self.ldForcedXAxis = None
sagun98
parents:
diff changeset
793
sagun98
parents:
diff changeset
794 #Happy Path Tested
sagun98
parents:
diff changeset
795 @staticmethod
sagun98
parents:
diff changeset
796 def getShapes(intShapeCount):
sagun98
parents:
diff changeset
797 """
sagun98
parents:
diff changeset
798 Returns a list of characters which are valid shapes for markers.
sagun98
parents:
diff changeset
799
sagun98
parents:
diff changeset
800 :param intShapeCount: The number of shapes to return.
sagun98
parents:
diff changeset
801 :type: Integer (min 1, max 9)
sagun98
parents:
diff changeset
802 :return: A list of characters to use as markers. [] is returned on error
sagun98
parents:
diff changeset
803 """
sagun98
parents:
diff changeset
804
sagun98
parents:
diff changeset
805 lsPointShapes = ['o','s','^','v','<','>','8','p','h']
sagun98
parents:
diff changeset
806 if intShapeCount > len(lsPointShapes):
sagun98
parents:
diff changeset
807 print("".join(["Error, PCoA.getShapes. Do not have enough shapes to give. Received request for ",str(intShapeCount)," shapes. Max available shape count is ",str(len(lsPointShapes)),"."]))
sagun98
parents:
diff changeset
808 return []
sagun98
parents:
diff changeset
809 return lsPointShapes[0:intShapeCount]