def __call__(self, metricValues, slicer, userPlotDict, fignum=None): """ Plot a set of oneD binned metric data. """ if slicer.slicerName != 'OneDSlicer': raise ValueError('OneDBinnedData plotter is for use with OneDSlicer') fig = plt.figure(fignum) plotDict = {} plotDict.update(self.defaultPlotDict) plotDict.update(userPlotDict) # Plot the histogrammed data. if 'bins' not in slicer.slicePoints: raise ValueError('OneDSlicer has to contain bins in slicePoints metadata') leftedge = slicer.slicePoints['bins'][:-1] width = np.diff(slicer.slicePoints['bins']) if plotDict['filled']: plt.bar(leftedge, metricValues.filled(), width, label=plotDict['label'], linewidth=0, alpha=plotDict['alpha'], log=plotDict['logScale'], color=plotDict['color']) else: good = np.where(metricValues.mask == False) x = np.ravel(zip(leftedge[good], leftedge[good] + width[good])) y = np.ravel(zip(metricValues[good], metricValues[good])) if plotDict['logScale']: plt.semilogy(x, y, label=plotDict['label'], color=plotDict['color'], linestyle=plotDict['linestyle'], linewidth=plotDict['linewidth'], alpha=plotDict['alpha']) else: plt.plot(x, y, label=plotDict['label'], color=plotDict['color'], linestyle=plotDict['linestyle'], linewidth=plotDict['linewidth'], alpha=plotDict['alpha']) if 'ylabel' in plotDict: plt.ylabel(plotDict['ylabel'], fontsize=plotDict['fontsize']) if 'xlabel' in plotDict: plt.xlabel(plotDict['xlabel'], fontsize=plotDict['fontsize']) # Set y limits (either from values in args, percentileClipping or compressed data values). if (plotDict['yMin'] is None) or (plotDict['yMax'] is None): if plotDict['percentileClip'] is not None: plotDict['yMin'], plotDict['yMax'] = percentileClipping(metricValues.compressed(), percentile=plotDict['percentileClip']) # Set y and x limits, if provided. if 'yMin' in plotDict: if plotDict['yMin'] is not None: plt.ylim(ymin=plotDict['yMin']) if 'yMax' in plotDict: if plotDict['yMax'] is not None: plt.ylim(ymax=plotDict['yMax']) if 'xMin' in plotDict: if plotDict['xMin'] is not None: plt.xlim(xmin=plotDict['xMin']) if 'xMax' in plotDict: if plotDict['xMax'] is not None: plt.xlim(xmax=plotDict['xMax']) if 'title' in plotDict: plt.title(plotDict['title']) return fig.number
def setColorLims(metricValue, plotDict): """Set up color bar limits.""" # Use plot dict if these values are set. colorMin = plotDict['colorMin'] colorMax = plotDict['colorMax'] # If not, try to use percentile clipping. if (plotDict['percentileClip'] is not None) & (np.size(metricValue.compressed()) > 0): pcMin, pcMax = percentileClipping(metricValue.compressed(), percentile=plotDict['percentileClip']) if colorMin is None: colorMin = pcMin if colorMax is None: colorMax = pcMax # If not, just use the data limits. if colorMin is None: colorMin = metricValue.compressed().min() if colorMax is None: colorMax = metricValue.compressed().max() # But make sure there is some range on the colorbar if colorMin == colorMax: colorMin = colorMin - 0.5 colorMax = colorMax + 0.5 return np.sort([colorMin, colorMax])
def setColorLims(metricValue, plotDict): """Set up color bar limits.""" # Use plot dict if these values are set. colorMin = plotDict['colorMin'] colorMax = plotDict['colorMax'] # If not, try to use percentile clipping. if plotDict['percentileClip'] is not None: pcMin, pcMax = percentileClipping( metricValue.compressed(), percentile=plotDict['percentileClip']) if colorMin is None: colorMin = pcMin if colorMax is None: colorMax = pcMax # If not, just use the data limits. if colorMin is None: colorMin = metricValue.compressed().min() if colorMax is None: colorMax = metricValue.compressed().max() # But make sure there is some range on the colorbar if colorMin == colorMax: colorMin = colorMin - 0.5 colorMax = colorMax + 0.5 return np.sort([colorMin, colorMax])
def __call__(self, metricValueIn, slicer, userPlotDict, fignum=None, ): """ Plot the sky map of metricValue using healpy cartview plots in thin strips. raMin: Minimum RA to plot (deg) raMax: Max RA to plot (deg). Note raMin/raMax define the centers that will be plotted. raLen: Length of the plotted strips in degrees decMin: minimum dec value to plot decMax: max dec value to plot metricValueIn: metric values """ fig = plt.figure(fignum) plotDict = {} plotDict.update(self.defaultPlotDict) plotDict.update(userPlotDict) norm = None if plotDict['logScale']: norm = 'log' if plotDict['cmap'] is None: cmap = cm.cubehelix else: cmap = plotDict['cmap'] if type(cmap) == str: cmap = getattr(cm, cmap) # Make colormap compatible with healpy cmap = colors.LinearSegmentedColormap('cmap', cmap._segmentdata, cmap.N) cmap.set_over(cmap(1.0)) cmap.set_under('w') cmap.set_bad('gray') if plotDict['zp'] is not None: metricValue = metricValueIn - plotDict['zp'] elif plotDict['normVal'] is not None: metricValue = metricValueIn / plotDict['normVal'] else: metricValue = metricValueIn if plotDict['percentileClip'] is not None: pcMin, pcMax = percentileClipping(metricValue.compressed(), percentile=plotDict['percentileClip']) if plotDict['colorMin'] is None: plotDict['colorMin'] = pcMin if plotDict['colorMax'] is None: plotDict['colorMax'] = pcMax if (plotDict['colorMin'] is not None) or (plotDict['colorMax'] is not None): clims = [plotDict['colorMin'], plotDict['colorMax']] else: clims = None # Make sure there is some range on the colorbar if clims is None: if metricValue.compressed().size > 0: clims = [metricValue.compressed().min(), metricValue.compressed().max()] else: clims = [-1, 1] if clims[0] == clims[1]: clims[0] = clims[0] - 1 clims[1] = clims[1] + 1 racenters = np.arange(plotDict['raMin'], plotDict['raMax'], plotDict['raLen']) nframes = racenters.size for i, racenter in enumerate(racenters): if i == 0: useTitle = plotDict['title'] + ' /n' + '%i < RA < %i' % (racenter - plotDict['raLen'], racenter + plotDict['raLen']) else: useTitle = '%i < RA < %i' % (racenter - plotDict['raLen'], racenter + plotDict['raLen']) hp.cartview(metricValue.filled(slicer.badval), title=useTitle, cbar=False, min=clims[0], max=clims[1], flip='astro', rot=(racenter, 0, 0), cmap=cmap, norm=norm, lonra=[-plotDict['raLen'], plotDict['raLen']], latra=[plotDict['decMin'], plotDict['decMax']], sub=(nframes + 1, 1, i + 1), fig=fig) hp.graticule(dpar=20, dmer=20, verbose=False) # Add colorbar (not using healpy default colorbar because want more tickmarks). fig = plt.gcf() ax1 = fig.add_axes([0.1, .15, .8, .075]) # left, bottom, width, height # Add label. if plotDict['label'] is not None: plt.figtext(0.8, 0.9, '%s' % plotDict['label']) # Make the colorbar as a seperate figure, # from http: //matplotlib.org/examples/api/colorbar_only.html cnorm = colors.Normalize(vmin=clims[0], vmax=clims[1]) # supress silly colorbar warnings with warnings.catch_warnings(): warnings.simplefilter("ignore") cb1 = mpl.colorbar.ColorbarBase(ax1, cmap=cmap, norm=cnorm, orientation='horizontal', format=plotDict['cbarFormat']) cb1.set_label(plotDict['xlabel']) cb1.ax.tick_params(labelsize=plotDict['labelsize']) # If outputing to PDF, this fixes the colorbar white stripes if plotDict['cbar_edge']: cb1.solids.set_edgecolor("face") fig = plt.gcf() return fig.number
def __call__(self, metricValueIn, slicer, userPlotDict, fignum=None): """ Plot the sky map of metricValue for a generic spatial slicer. """ fig = plt.figure(fignum) plotDict = {} plotDict.update(self.defaultPlotDict) plotDict.update(userPlotDict) if plotDict['zp'] is not None: metricValue = metricValueIn - plotDict['zp'] elif plotDict['normVal'] is not None: metricValue = metricValueIn / plotDict['normVal'] else: metricValue = metricValueIn # other projections available include # ['aitoff', 'hammer', 'lambert', 'mollweide', 'polar', 'rectilinear'] ax = fig.add_subplot(111, projection=plotDict['projection']) # Set up valid datapoints and colormin/max values. if plotDict['plotMask']: # Plot all data points. mask = np.ones(len(metricValue), dtype='bool') else: # Only plot points which are not masked. Flip numpy ma mask where 'False' == 'good'. mask = ~metricValue.mask # Determine color min/max values. metricValue.compressed = non-masked points. if not plotDict['metricIsColor']: if plotDict['percentileClip'] is not None: pcMin, pcMax = percentileClipping(metricValue.compressed(), percentile=plotDict['percentileClip']) if plotDict['colorMin'] is None: if plotDict['percentileClip']: plotDict['colorMin'] = pcMin else: plotDict['colorMin'] = metricValue.compressed().min() if plotDict['colorMax'] is None: if plotDict['percentileClip']: plotDict['colorMax'] = pcMax else: plotDict['colorMax'] = metricValue.compressed().max() # Avoid colorbars with no range. if plotDict['colorMax'] == plotDict['colorMin']: plotDict['colorMax'] = plotDict['colorMax'] + 1 plotDict['colorMin'] = plotDict['colorMin'] - 1 # Combine to make clims: clims = [plotDict['colorMin'], plotDict['colorMax']] # Determine whether or not to use auto-log scale. if plotDict['logScale'] == 'auto': if plotDict['colorMin'] > 0: if np.log10(plotDict['colorMax']) - np.log10(plotDict['colorMin']) > 3: plotDict['logScale'] = True else: plotDict['logScale'] = False else: plotDict['logScale'] = False if plotDict['logScale']: # Move min/max values to things that can be marked on the colorbar. plotDict['colorMin'] = 10**(int(np.log10(plotDict['colorMin']))) plotDict['colorMax'] = 10**(int(np.log10(plotDict['colorMax']))) # Add ellipses at RA/Dec locations lon = -(slicer.slicePoints['ra'][mask] - plotDict['raCen'] - np.pi) % (np.pi * 2) - np.pi ellipses = self._plot_tissot_ellipse(lon, slicer.slicePoints['dec'][mask], plotDict['radius'], rasterized=True, ax=ax) if plotDict['metricIsColor']: current = None for ellipse, mVal in zip(ellipses, metricValue.data[mask]): if mVal[3] > 1: ellipse.set_alpha(1.0) ellipse.set_facecolor((mVal[0], mVal[1], mVal[2])) ellipse.set_edgecolor('k') current = ellipse else: ellipse.set_alpha(mVal[3]) ellipse.set_color((mVal[0], mVal[1], mVal[2])) ax.add_patch(ellipse) if current: ax.add_patch(current) else: if plotDict['logScale']: norml = colors.LogNorm() p = PatchCollection(ellipses, cmap=plotDict['cmap'], alpha=plotDict['alpha'], linewidth=0, edgecolor=None, norm=norml, rasterized=True) else: p = PatchCollection(ellipses, cmap=plotDict['cmap'], alpha=plotDict['alpha'], linewidth=0, edgecolor=None, rasterized=True) p.set_array(metricValue.data[mask]) p.set_clim(clims) ax.add_collection(p) # Add color bar (with optional setting of limits) if plotDict['cbar']: cb = plt.colorbar(p, aspect=25, extendrect=True, orientation='horizontal', format=plotDict['cbarFormat']) # If outputing to PDF, this fixes the colorbar white stripes if plotDict['cbar_edge']: cb.solids.set_edgecolor("face") cb.set_label(plotDict['xlabel']) cb.ax.tick_params(labelsize=plotDict['labelsize']) # Add ecliptic self._plot_ecliptic(plotDict['raCen'], ax=ax) if plotDict['mwZone']: self._plot_mwZone(plotDict['raCen'], ax=ax) ax.grid(True, zorder=1) ax.xaxis.set_ticklabels([]) if plotDict['bgcolor'] is not None: ax.set_axis_bgcolor(plotDict['bgcolor']) # Add label. if plotDict['label'] is not None: plt.figtext(0.75, 0.9, '%s' % plotDict['label']) if plotDict['title'] is not None: plt.text(0.5, 1.09, plotDict['title'], horizontalalignment='center', transform=ax.transAxes) return fig.number
def __call__(self, metricValueIn, slicer, userPlotDict, fignum=None): """ Parameters ---------- metricValue : numpy.ma.MaskedArray slicer : lsst.sims.maf.slicers.HealpixSlicer userPlotDict: dict Dictionary of plot parameters set by user (overrides default values). fignum : int Matplotlib figure number to use (default = None, starts new figure). Returns ------- int Matplotlib figure number used to create the plot. """ # Check that the slicer is a HealpixSlicer, or subclass thereof # Using the names rather than just comparing the classes themselves # to avoid circular dependency between slicers and plots classes = inspect.getmro(slicer.__class__) cnames = [cls.__name__ for cls in classes] if 'HealpixSlicer' not in cnames: raise ValueError('HealpixSkyMap is for use with healpix slicers') fig = plt.figure(fignum) # Override the default plotting parameters with user specified values. plotDict = {} plotDict.update(self.defaultPlotDict) plotDict.update(userPlotDict) # Generate a Mollweide full-sky plot. norm = None if plotDict['logScale']: norm = 'log' cmap = plotDict['cmap'] if type(cmap) == str: cmap = getattr(cm, cmap) # Set background and masked pixel colors default healpy white and gray. cmap.set_over(cmap(1.0)) cmap.set_under('w') cmap.set_bad('gray') if plotDict['zp'] is not None: metricValue = metricValueIn - plotDict['zp'] elif plotDict['normVal'] is not None: metricValue = metricValueIn / plotDict['normVal'] else: metricValue = metricValueIn # Set up color bar limits. colorMin = plotDict['colorMin'] colorMax = plotDict['colorMax'] if plotDict['percentileClip'] is not None: pcMin, pcMax = percentileClipping(metricValue.compressed(), percentile=plotDict['percentileClip']) if colorMin is None and plotDict['percentileClip']: colorMin = pcMin if colorMax is None and plotDict['percentileClip']: colorMax = pcMax if (colorMin is not None) or (colorMax is not None): clims = [colorMin, colorMax] else: clims = None # Make sure there is some range on the colorbar if clims is None: if metricValue.compressed().size > 0: clims = [metricValue.compressed().min(), metricValue.compressed().max()] else: clims = [-1, 1] if clims[0] == clims[1]: clims[0] = clims[0] - 1 clims[1] = clims[1] + 1 hp.mollview(metricValue.filled(slicer.badval), title=plotDict['title'], cbar=False, min=clims[0], max=clims[1], rot=plotDict['rot'], flip='astro', cmap=cmap, norm=norm, fig=fig.number) # This graticule call can fail with old versions of healpy and matplotlib 1.4.0. # Make sure the latest version of healpy in the stack is setup hp.graticule(dpar=20, dmer=20, verbose=False) # Add colorbar (not using healpy default colorbar because we want more tickmarks). ax = plt.gca() im = ax.get_images()[0] # Add label. if plotDict['label'] is not None: plt.figtext(0.8, 0.8, '%s' % (plotDict['label'])) # supress silly colorbar warnings with warnings.catch_warnings(): warnings.simplefilter("ignore") cb = plt.colorbar(im, shrink=0.75, aspect=25, orientation='horizontal', format=plotDict['cbarFormat'], extendrect=True) cb.set_label(plotDict['xlabel'], fontsize=plotDict['fontsize']) if plotDict['labelsize'] is not None: cb.ax.tick_params(labelsize=plotDict['labelsize']) if norm == 'log': tick_locator = ticker.LogLocator(numticks=plotDict['nTicks']) cb.locator = tick_locator cb.update_ticks() if (plotDict['nTicks'] is not None) & (norm != 'log'): tick_locator = ticker.MaxNLocator(nbins=plotDict['nTicks']) cb.locator = tick_locator cb.update_ticks() # If outputing to PDF, this fixes the colorbar white stripes if plotDict['cbar_edge']: cb.solids.set_edgecolor("face") return fig.number
def __call__(self, metricValueIn, slicer, userPlotDict, fignum=None): """ Plot a histogram of metricValues (such as would come from a spatial slicer). """ # Adjust metric values by zeropoint or normVal, and use 'compressed' version of masked array. plotDict = {} plotDict.update(self.defaultPlotDict) plotDict.update(userPlotDict) if plotDict['zp'] is not None: metricValue = metricValueIn.compressed() - plotDict['zp'] elif plotDict['normVal'] is not None: metricValue = metricValueIn.compressed() / plotDict['normVal'] else: metricValue = metricValueIn.compressed() # Determine percentile clipped X range, if set. (and xmin/max not set). if plotDict['xMin'] is None and plotDict['xMax'] is None: if plotDict['percentileClip']: plotDict['xMin'], plotDict['xMax'] = percentileClipping(metricValue, percentile=plotDict['percentileClip']) # Determine range for histogram. Note that if xmin/max are None, this will just be [None, None]. histRange = [plotDict['xMin'], plotDict['xMax']] # Should we use log scale on y axis? (if 'auto') if plotDict['logScale'] == 'auto': plotDict['logScale'] = False if np.min(histRange) > 0: if (np.log10(np.max(histRange) - np.log10(np.min(histRange))) > 3): plotDict['logScale'] = True # If binsize was specified, set up an array of bins for the histogram. if plotDict['binsize'] is not None: # If generating cumulative histogram, want to use full range of data (but with given binsize). # .. but if user set histRange to be wider than full range of data, then # extend bins to cover this range, so we can make prettier plots. if plotDict['cumulative'] is not False: if histRange[0] is not None: bmin = np.min([metricValue.min(), histRange[0]]) else: bmin = metricValue.min() if histRange[1] is not None: bmax = np.max([metricValue.max(), histRange[1]]) else: bmax = metricValue.max() bins = np.arange(bmin, bmax + plotDict['binsize'] / 2.0, plotDict['binsize']) # Catch edge-case where there is only 1 bin value if bins.size < 2: bins = np.arange(bmin, bmax + plotDict['binsize'], plotDict['binsize']) # Else try to set up bins using min/max values if specified, or full data range. else: if histRange[0] is not None: bmin = histRange[0] else: bmin = metricValue.min() if histRange[1] is not None: bmax = histRange[1] else: bmax = metricValue.max() bins = np.arange(bmin, bmax + plotDict['binsize'], plotDict['binsize']) # Otherwise, determine number of bins, if neither 'bins' or 'binsize' were specified. else: if plotDict['bins'] is None: bins = optimalBins(metricValue) else: bins = plotDict['bins'] # Generate plots. fig = plt.figure(fignum) if plotDict['cumulative'] is not False: # If cumulative is set, generate histogram without using histRange (to use full range of data). n, b, p = plt.hist(metricValue, bins=bins, histtype='step', log=plotDict['logScale'], cumulative=plotDict['cumulative'], label=plotDict['label'], color=plotDict['color']) else: # Plot non-cumulative histogram. # First, test if data falls within histRange, because otherwise histogram generation will fail. if np.min(histRange) is not None: if (histRange[0] is None) and (histRange[1] is not None): condition = (metricValue <= histRange[1]) elif (histRange[1] is None) and (histRange[0] is not None): condition = (metricValue >= histRange[0]) else: condition = ((metricValue >= histRange[0]) & (metricValue <= histRange[1])) plotValue = metricValue[condition] else: plotValue = metricValue # If there is only one value to histogram, need to set histRange, otherwise histogram will fail. rangePad = 20. if (np.unique(plotValue).size == 1) & (np.min(histRange) is None): warnings.warn('Only one metric value, making a guess at a good histogram range.') histRange = [plotValue.min() - rangePad, plotValue.max() + rangePad] if (plotValue.min() >= 0) & (histRange[0] < 0): # Reset histogram range if it went below 0. histRange[0] = 0. if 'binsize' in plotDict: bins = np.arange(histRange[0], histRange[1], plotDict['binsize']) else: bins = np.arange(histRange[0], histRange[1], (histRange[1] - histRange[0]) / 50.) # If there is no data within the histogram range, we will generate an empty plot. # If there is data, make the histogram. if plotValue.size > 0: # Generate histogram. if np.min(histRange) is None: histRange = None n, b, p = plt.hist(plotValue, bins=bins, histtype='step', log=plotDict['logScale'], cumulative=plotDict['cumulative'], range=histRange, label=plotDict['label'], color=plotDict['color']) # Fill in axes labels and limits. # Option to use 'scale' to turn y axis into area or other value. def mjrFormatter(y, pos): return plotDict['yaxisformat'] % (y * plotDict['scale']) ax = plt.gca() ax.yaxis.set_major_formatter(FuncFormatter(mjrFormatter)) # Set y limits. if 'yMin' in plotDict: if plotDict['yMin'] is not None: plt.ylim(ymin=plotDict['yMin']) else: # There is a bug in histype='step' that can screw up the ylim. # Comes up when running allSlicer.Cfg.py try: if plt.axis()[2] == max(n): plt.ylim([n.min(), n.max()]) except UnboundLocalError: # This happens if we were generating an empty plot (no histogram). # But in which case, the above error was probably not relevant. So skip it. pass if 'yMax' in plotDict: plt.ylim(ymax=plotDict['yMax']) # Set x limits. if plotDict['xMin'] is not None: plt.xlim(xmin=plotDict['xMin']) if plotDict['xMax'] is not None: plt.xlim(xmax=plotDict['xMax']) # Set/Add various labels. plt.xlabel(plotDict['xlabel'], fontsize=plotDict['fontsize']) plt.ylabel(plotDict['ylabel'], fontsize=plotDict['fontsize']) plt.title(plotDict['title']) if plotDict['labelsize'] is not None: plt.tick_params(axis='x', labelsize=plotDict['labelsize']) plt.tick_params(axis='y', labelsize=plotDict['labelsize']) # Return figure number return fig.number
def __call__(self, metricValues, slicer, userPlotDict, fignum=None): """ Plot a set of oneD binned metric data. """ if slicer.slicerName != 'OneDSlicer': raise ValueError( 'OneDBinnedData plotter is for use with OneDSlicer') if 'bins' not in slicer.slicePoints: errMessage = 'OneDSlicer must contain "bins" in slicePoints metadata.' errMessage += ' SlicePoints only contains keys %s.' % ( slicer.slicePoints.keys()) raise ValueError(errMessage) plotDict = {} plotDict.update(self.defaultPlotDict) plotDict.update(userPlotDict) fig = plt.figure(fignum, figsize=plotDict['figsize']) # Plot the histogrammed data. leftedge = slicer.slicePoints['bins'][:-1] width = np.diff(slicer.slicePoints['bins']) if plotDict['filled']: plt.bar(leftedge, metricValues.filled(), width, label=plotDict['label'], linewidth=0, alpha=plotDict['alpha'], log=plotDict['logScale'], color=plotDict['color']) else: good = np.where(metricValues.mask == False) x = np.ravel( list(zip(leftedge[good], leftedge[good] + width[good]))) y = np.ravel(list(zip(metricValues[good], metricValues[good]))) if plotDict['logScale']: plt.semilogy(x, y, label=plotDict['label'], color=plotDict['color'], linestyle=plotDict['linestyle'], linewidth=plotDict['linewidth'], alpha=plotDict['alpha']) else: plt.plot(x, y, label=plotDict['label'], color=plotDict['color'], linestyle=plotDict['linestyle'], linewidth=plotDict['linewidth'], alpha=plotDict['alpha']) if 'ylabel' in plotDict: plt.ylabel(plotDict['ylabel'], fontsize=plotDict['fontsize']) if 'xlabel' in plotDict: plt.xlabel(plotDict['xlabel'], fontsize=plotDict['fontsize']) # Set y limits (either from values in args, percentileClipping or compressed data values). if plotDict['percentileClip'] is not None: yMin, yMax = percentileClipping( metricValues.compressed(), percentile=plotDict['percentileClip']) if plotDict['yMin'] is None: plotDict['yMin'] = yMin if plotDict['yMax'] is None: plotDict['yMax'] = yMax plt.grid(plotDict['grid'], alpha=0.3) if plotDict['yMin'] is None and metricValues.filled().min() == 0: plotDict['yMin'] = 0 # Set y and x limits, if provided. if plotDict['yMin'] is not None: plt.ylim(bottom=plotDict['yMin']) if plotDict['yMax'] is not None: plt.ylim(top=plotDict['yMax']) if plotDict['xMin'] is not None: plt.xlim(left=plotDict['xMin']) if plotDict['xMax'] is not None: plt.xlim(right=plotDict['xMax']) plt.title(plotDict['title']) return fig.number
def plotSkyMap(self, metricValueIn, xlabel=None, title='', logScale=False, cbarFormat='%.2f', cmap=cm.jet, percentileClip=None, colorMin=None, colorMax=None, zp=None, normVal=None, cbar_edge=True, label=None, nTicks=None, rot1=0, rot2=0, rot3=0, **kwargs): """ Plot the sky map of metricValue using healpy Mollweide plot. metricValue = metric values units = units for metric color-bar label title = title for plot cbarFormat = format for color bar numerals (i.e. '%.2g', etc) (default to matplotlib default) rot1,2,3 = rotations passed to mollview. """ # Generate a Mollweide full-sky plot. norm = None if logScale: norm = 'log' if cmap is None: cmap = cm.jet if type(cmap) == str: cmap = getattr(cm,cmap) # Make colormap compatible with healpy cmap = colors.LinearSegmentedColormap('cmap', cmap._segmentdata, cmap.N) cmap.set_over(cmap(1.0)) cmap.set_under('w') cmap.set_bad('gray') if zp: metricValue = metricValueIn - zp elif normVal: metricValue = metricValueIn/normVal else: metricValue = metricValueIn if percentileClip: pcMin, pcMax = percentileClipping(metricValue.compressed(), percentile=percentileClip) if colorMin is None and percentileClip: colorMin = pcMin if colorMax is None and percentileClip: colorMax = pcMax if (colorMin is not None) or (colorMax is not None): clims = [colorMin, colorMax] else: clims = None # Make sure there is some range on the colorbar if clims is None: if metricValue.compressed().size > 0: clims=[metricValue.compressed().min(), metricValue.compressed().max()] else: clims = [-1,1] if clims[0] == clims[1]: clims[0] = clims[0]-1 clims[1] = clims[1]+1 rot = (rot1,rot2,rot3) hp.mollview(metricValue.filled(self.badval), title=title, cbar=False, min=clims[0], max=clims[1], rot=rot, flip='astro', cmap=cmap, norm=norm) # This graticule call can fail with old versions of healpy and matplotlib 1.4.0. # Make sure the latest version of healpy in the stack is setup hp.graticule(dpar=20, dmer=20, verbose=False) # Add colorbar (not using healpy default colorbar because want more tickmarks). ax = plt.gca() im = ax.get_images()[0] # Add label. if label is not None: plt.figtext(0.8, 0.8, '%s' %label) # supress silly colorbar warnings with warnings.catch_warnings(): warnings.simplefilter("ignore") cb = plt.colorbar(im, shrink=0.75, aspect=25, orientation='horizontal', extend='both', extendrect=True, format=cbarFormat) cb.set_label(xlabel) if nTicks is not None: tick_locator = ticker.MaxNLocator(nbins=nTicks) cb.locator = tick_locator cb.update_ticks() # If outputing to PDF, this fixes the colorbar white stripes if cbar_edge: cb.solids.set_edgecolor("face") fig = plt.gcf() return fig.number
def plotHistogram(self, metricValueIn, title=None, xlabel=None, units=None, ylabel=None, fignum=None, label=None, addLegend=False, legendloc='upper left', bins=None, binsize=None, cumulative=False, xMin=None, xMax=None, yMin=None, yMax=None, logScale='auto', scale=1.0, yaxisformat='%.3f', color='b', zp=None, normVal=None, percentileClip=None, **kwargs): """Plot a histogram of metricValue, labelled by metricLabel. title = the title for the plot (default None) fignum = the figure number to use (default None - will generate new figure) label = the label to use in the figure legend (default None) addLegend = flag for whether or not to add a legend (default False) legendloc = location for legend (default 'upper left') bins = bins for histogram (numpy array or # of bins) binsize = size of bins to use. Will override "bins" if both are set. (default None, uses Freedman-Diaconis rule to set binsize) cumulative = make histogram cumulative (default False) (<0 value makes cumulative the 'less than' way). xMin/Max = histogram range (default None, set by matplotlib hist) yMin/Max = histogram y range scale = scale y axis by 'scale' (i.e. to translate to area) zp = zeropoing to subtract off metricVals normVal = normalization value to divide metric values by (overrides zp). """ # Adjust metric values by zeropoint or normVal, and use 'compressed' version of masked array. if zp: metricValue = metricValueIn.compressed() - zp elif normVal: metricValue = metricValueIn.compressed()/normVal else: metricValue = metricValueIn.compressed() # Determine percentile clipped X range, if set. (and xmin/max not set). if xMin is None and xMax is None: if percentileClip: xMin, xMax = percentileClipping(metricValue, percentile=percentileClip) # Determine range for histogram. Note that if xmin/max are None, this will just be [None, None]. histRange = [xMin, xMax] # Should we use log scale on y axis? (if 'auto') if logScale == 'auto': logScale = False if np.min(histRange) > 0: if (np.log10(np.max(histRange)-np.log10(np.min(histRange))) > 3 ): logScale = True # If binsize was specified, set up an array of bins for the histogram. if binsize is not None: # If generating cumulative histogram, want to use full range of data (but with given binsize). # .. but if user set histRange to be wider than full range of data, then # extend bins to cover this range, so we can make prettier plots. if cumulative is not False: if histRange[0] is not None: bmin = np.min([metricValue.min(), histRange[0]]) else: bmin = metricValue.min() if histRange[1] is not None: bmax = np.max([metricValue.max(), histRange[1]]) else: bmax = metricValue.max() bins = np.arange(bmin, bmax+binsize/2.0, binsize) # Else try to set up bins using min/max values if specified, or full data range. else: if histRange[0] is not None: bmin = histRange[0] else: bmin = metricValue.min() if histRange[1] is not None: bmax = histRange[1] else: bmax = metricValue.max() bins = np.arange(bmin, bmax+binsize/2.0, binsize) # Otherwise, determine number of bins, if neither 'bins' or 'binsize' were specified. else: if bins is None: bins = optimalBins(metricValue) # Generate plots. fig = plt.figure(fignum) if cumulative is not False: # If cumulative is set, generate histogram without using histRange (to use full range of data). n, b, p = plt.hist(metricValue, bins=bins, histtype='step', log=logScale, cumulative=cumulative, label=label, color=color) else: # Plot non-cumulative histogram. # First, test if data falls within histRange, because otherwise histogram generation will fail. if np.min(histRange) is not None: if (histRange[0] is None) and (histRange[1] is not None): condition = (metricValue <= histRange[1]) elif (histRange[1] is None) and (histRange[0] is not None): condition = (metricValue >= histRange[0]) else: condition = ((metricValue >= histRange[0]) & (metricValue <= histRange[1])) plotValue = metricValue[condition] else: plotValue = metricValue # If there is only one value to histogram, need to set histRange, otherwise histogram will fail. rangePad = 20. if (np.unique(plotValue).size == 1) & (np.min(histRange) is None): warnings.warn('Only one metric value, making a guess at a good histogram range.') histRange = [plotValue.min()-rangePad, plotValue.max()+rangePad] if (plotValue.min() >= 0) & (histRange[0] < 0): # Reset histogram range if it went below 0. histRange[0] = 0. bins=np.arange(histRange[0], histRange[1], binsize) # If there is no data within the histogram range, we will generate an empty plot. # If there is data, make the histogram. if plotValue.size > 0: # Generate histogram. if np.min(histRange) is None: histRange = None n, b, p = plt.hist(plotValue, bins=bins, histtype='step', log=logScale, cumulative=cumulative, range=histRange, label=label, color=color) # Fill in axes labels and limits. # Option to use 'scale' to turn y axis into area or other value. def mjrFormatter(y, pos): return yaxisformat % (y * scale) ax = plt.gca() ax.yaxis.set_major_formatter(FuncFormatter(mjrFormatter)) # Set y limits. if yMin is not None: plt.ylim(ymin=yMin) else: # There is a bug in histype='step' that can screw up the ylim. Comes up when running allSlicer.Cfg.py try: if plt.axis()[2] == max(n): plt.ylim([n.min(),n.max()]) except UnboundLocalError: # This happens if we were generating an empty plot (no histogram). # But in which case, the above error was probably not relevant. So skip it. pass if yMax is not None: plt.ylim(ymax=yMax) # Set x limits. if xMin is not None: plt.xlim(xmin=xMin) if xMax is not None: plt.xlim(xmax=xMax) # Set/Add various labels. if not xlabel: xlabel = units if xlabel is not None: plt.xlabel(xlabel) if ylabel is not None: plt.ylabel(ylabel) if addLegend: plt.legend(fancybox=True, prop={'size':'smaller'}, loc=legendloc) if title!=None: plt.title(title) # Return figure number (so we can reuse this if desired). return fig.number
def __call__(self, metricValueIn, slicer, userPlotDict, fignum=None): if 'ra' not in slicer.slicePoints or 'dec' not in slicer.slicePoints: errMessage = 'SpatialSlicer must contain "ra" and "dec" in slicePoints metadata.' errMessage += ' SlicePoints only contains keys %s.' % ( slicer.slicePoints.keys()) raise ValueError(errMessage) plotDict = {} plotDict.update(self.defaultPlotDict) plotDict.update(userPlotDict) if plotDict['zp'] is not None: metricValue = metricValueIn - plotDict['zp'] elif plotDict['normVal'] is not None: metricValue = metricValueIn / plotDict['normVal'] else: metricValue = metricValueIn if plotDict['percentileClip'] is not None: pcMin, pcMax = percentileClipping( metricValue.compressed(), percentile=plotDict['percentileClip']) if plotDict['colorMin'] is None: plotDict['colorMin'] = pcMin if plotDict['colorMax'] is None: plotDict['colorMax'] = pcMax if (plotDict['colorMin'] is not None) or (plotDict['colorMax'] is not None): clims = [plotDict['colorMin'], plotDict['colorMax']] else: clims = None # Make sure there is some range on the colorbar if clims is None: if metricValue.compressed().size > 0: clims = [ metricValue.compressed().min(), metricValue.compressed().max() ] else: clims = [-1, 1] if clims[0] == clims[1]: clims[0] = clims[0] - 1 clims[1] = clims[1] + 1 # Calculate the levels to use for the contour if np.size(plotDict['levels']) > 1: levels = plotDict['levels'] else: step = (clims[1] - clims[0]) / plotDict['levels'] levels = np.arange(clims[0], clims[1] + step, step) fig = plt.figure(fignum, figsize=plotDict['figsize']) ax = fig.add_subplot(111) # Hide this extra dependency down here for now # if using anaconda, to get basemap: # conda install basemap # Note, this should be possible without basemap, but there are # matplotlib bugs: # http: //stackoverflow.com/questions/31975303/matplotlib-tricontourf-with-an-axis-projection from mpl_toolkits.basemap import Basemap m = Basemap(**plotDict['basemap']) good = np.where(metricValue != slicer.badval) # Contour the plot first to remove any anti-aliasing artifacts. Doesn't seem to work though. See: # http: //stackoverflow.com/questions/15822159/aliasing-when-saving-matplotlib\ # -filled-contour-plot-to-pdf-or-eps # tmpContour = m.contour(np.degrees(slicer.slicePoints['ra'][good]), # np.degrees(slicer.slicePoints['dec'][good]), # metricValue[good], levels, tri=True, # cmap=plotDict['cmap'], ax=ax, latlon=True, # lw=1) CS = m.contourf(np.degrees(slicer.slicePoints['ra'][good]), np.degrees(slicer.slicePoints['dec'][good]), metricValue[good], levels, tri=True, cmap=plotDict['cmap'], ax=ax, latlon=True) # Try to fix the ugly pdf contour problem for c in CS.collections: c.set_edgecolor("face") para = np.arange(0, 89, 20) m.drawparallels(para, labels=para) m.drawmeridians(np.arange(-180, 181, 60)) cb = plt.colorbar(CS, format=plotDict['cbarFormat']) cb.set_label(plotDict['xlabel']) if plotDict['labelsize'] is not None: cb.ax.tick_params(labelsize=plotDict['labelsize']) # Pop in an extra line to raise the title a bit ax.set_title(plotDict['title'] + '\n ') # If outputing to PDF, this fixes the colorbar white stripes if plotDict['cbar_edge']: cb.solids.set_edgecolor("face") return fig.number
def __call__( self, metricValueIn, slicer, userPlotDict, fignum=None, ): """ Plot the sky map of metricValue using healpy cartview plots in thin strips. raMin: Minimum RA to plot (deg) raMax: Max RA to plot (deg). Note raMin/raMax define the centers that will be plotted. raLen: Length of the plotted strips in degrees decMin: minimum dec value to plot decMax: max dec value to plot metricValueIn: metric values """ fig = plt.figure(fignum) plotDict = {} plotDict.update(self.defaultPlotDict) plotDict.update(userPlotDict) norm = None if plotDict['logScale']: norm = 'log' if plotDict['cmap'] is None: cmap = cm.cubehelix else: cmap = plotDict['cmap'] if type(cmap) == str: cmap = getattr(cm, cmap) # Make colormap compatible with healpy cmap = colors.LinearSegmentedColormap('cmap', cmap._segmentdata, cmap.N) cmap.set_over(cmap(1.0)) cmap.set_under('w') cmap.set_bad('gray') if plotDict['zp'] is not None: metricValue = metricValueIn - plotDict['zp'] elif plotDict['normVal'] is not None: metricValue = metricValueIn / plotDict['normVal'] else: metricValue = metricValueIn if plotDict['percentileClip'] is not None: pcMin, pcMax = percentileClipping( metricValue.compressed(), percentile=plotDict['percentileClip']) if plotDict['colorMin'] is None: plotDict['colorMin'] = pcMin if plotDict['colorMax'] is None: plotDict['colorMax'] = pcMax if (plotDict['colorMin'] is not None) or (plotDict['colorMax'] is not None): clims = [plotDict['colorMin'], plotDict['colorMax']] else: clims = None # Make sure there is some range on the colorbar if clims is None: if metricValue.compressed().size > 0: clims = [ metricValue.compressed().min(), metricValue.compressed().max() ] else: clims = [-1, 1] if clims[0] == clims[1]: clims[0] = clims[0] - 1 clims[1] = clims[1] + 1 racenters = np.arange(plotDict['raMin'], plotDict['raMax'], plotDict['raLen']) nframes = racenters.size for i, racenter in enumerate(racenters): if i == 0: useTitle = plotDict['title'] + ' /n' + '%i < RA < %i' % ( racenter - plotDict['raLen'], racenter + plotDict['raLen']) else: useTitle = '%i < RA < %i' % (racenter - plotDict['raLen'], racenter + plotDict['raLen']) hp.cartview(metricValue.filled(slicer.badval), title=useTitle, cbar=False, min=clims[0], max=clims[1], flip='astro', rot=(racenter, 0, 0), cmap=cmap, norm=norm, lonra=[-plotDict['raLen'], plotDict['raLen']], latra=[plotDict['decMin'], plotDict['decMax']], sub=(nframes + 1, 1, i + 1), fig=fig) hp.graticule(dpar=20, dmer=20, verbose=False) # Add colorbar (not using healpy default colorbar because want more tickmarks). fig = plt.gcf() ax1 = fig.add_axes([0.1, .15, .8, .075]) # left, bottom, width, height # Add label. if plotDict['label'] is not None: plt.figtext(0.8, 0.9, '%s' % plotDict['label']) # Make the colorbar as a seperate figure, # from http: //matplotlib.org/examples/api/colorbar_only.html cnorm = colors.Normalize(vmin=clims[0], vmax=clims[1]) # supress silly colorbar warnings with warnings.catch_warnings(): warnings.simplefilter("ignore") cb1 = mpl.colorbar.ColorbarBase(ax1, cmap=cmap, norm=cnorm, orientation='horizontal', format=plotDict['cbarFormat']) cb1.set_label(plotDict['xlabel']) cb1.ax.tick_params(labelsize=plotDict['labelsize']) # If outputing to PDF, this fixes the colorbar white stripes if plotDict['cbar_edge']: cb1.solids.set_edgecolor("face") fig = plt.gcf() return fig.number
def __call__(self, metricValueIn, slicer, userPlotDict, fignum=None): """ Parameters ---------- metricValue : numpy.ma.MaskedArray slicer : lsst.sims.maf.slicers.HealpixSlicer userPlotDict: dict Dictionary of plot parameters set by user (overrides default values). fignum : int Matplotlib figure number to use (default = None, starts new figure). Returns ------- int Matplotlib figure number used to create the plot. """ # Check that the slicer is a HealpixSlicer, or subclass thereof # Using the names rather than just comparing the classes themselves # to avoid circular dependency between slicers and plots classes = inspect.getmro(slicer.__class__) cnames = [cls.__name__ for cls in classes] if 'HealpixSlicer' not in cnames: raise ValueError('HealpixSkyMap is for use with healpix slicers') # Override the default plotting parameters with user specified values. plotDict = {} plotDict.update(self.defaultPlotDict) plotDict.update(userPlotDict) # Generate a Mollweide full-sky plot. fig = plt.figure(fignum, figsize=plotDict['figsize']) norm = None if plotDict['logScale']: norm = 'log' cmap = plotDict['cmap'] if type(cmap) == str: cmap = getattr(cm, cmap) # Set background and masked pixel colors default healpy white and gray. cmap.set_over(cmap(1.0)) cmap.set_under('w') cmap.set_bad('gray') if plotDict['zp'] is not None: metricValue = metricValueIn - plotDict['zp'] elif plotDict['normVal'] is not None: metricValue = metricValueIn / plotDict['normVal'] else: metricValue = metricValueIn # Set up color bar limits. colorMin = plotDict['colorMin'] colorMax = plotDict['colorMax'] if plotDict['percentileClip'] is not None: pcMin, pcMax = percentileClipping( metricValue.compressed(), percentile=plotDict['percentileClip']) if colorMin is None and plotDict['percentileClip']: colorMin = pcMin if colorMax is None and plotDict['percentileClip']: colorMax = pcMax if (colorMin is not None) or (colorMax is not None): clims = [colorMin, colorMax] else: clims = None # Make sure there is some range on the colorbar if clims is None: if metricValue.compressed().size > 0: clims = [ metricValue.compressed().min(), metricValue.compressed().max() ] else: clims = [-1, 1] if clims[0] == clims[1]: clims[0] = clims[0] - 1 clims[1] = clims[1] + 1 # Avoid trying to log scale when zero is in the range. if (norm == 'log') & ((clims[0] <= 0 <= clims[1]) or (clims[0] >= 0 >= clims[1])): # Try something simple above = metricValue[np.where(metricValue > 0)] if len(above) > 0: clims[0] = above.max() # If still bad, give up and turn off norm if ((clims[0] <= 0 <= clims[1]) or (clims[0] >= 0 >= clims[1])): norm = None warnings.warn( "Using norm was set to log, but color limits pass through 0. Adjusting so plotting doesn't fail" ) hp.mollview(metricValue.filled(slicer.badval), title=plotDict['title'], cbar=False, min=clims[0], max=clims[1], rot=plotDict['rot'], flip='astro', cmap=cmap, norm=norm, fig=fig.number) # This graticule call can fail with old versions of healpy and matplotlib 1.4.0. # Make sure the latest version of healpy in the stack is setup hp.graticule(dpar=20, dmer=20, verbose=False) # Add colorbar (not using healpy default colorbar because we want more tickmarks). ax = plt.gca() im = ax.get_images()[0] # Add label. if plotDict['label'] is not None: plt.figtext(0.8, 0.8, '%s' % (plotDict['label'])) # supress silly colorbar warnings with warnings.catch_warnings(): warnings.simplefilter("ignore") cb = plt.colorbar(im, shrink=0.75, aspect=25, orientation='horizontal', format=plotDict['cbarFormat'], extendrect=True) cb.set_label(plotDict['xlabel'], fontsize=plotDict['fontsize']) if plotDict['labelsize'] is not None: cb.ax.tick_params(labelsize=plotDict['labelsize']) if norm == 'log': tick_locator = ticker.LogLocator(numticks=plotDict['nTicks']) cb.locator = tick_locator cb.update_ticks() if (plotDict['nTicks'] is not None) & (norm != 'log'): tick_locator = ticker.MaxNLocator(nbins=plotDict['nTicks']) cb.locator = tick_locator cb.update_ticks() # If outputing to PDF, this fixes the colorbar white stripes if plotDict['cbar_edge']: cb.solids.set_edgecolor("face") return fig.number
def __call__(self, metricValueIn, slicer, userPlotDict, fignum=None): """ Plot the sky map of metricValue for a generic spatial slicer. """ if 'ra' not in slicer.slicePoints or 'dec' not in slicer.slicePoints: errMessage = 'SpatialSlicer must contain "ra" and "dec" in slicePoints metadata.' errMessage += ' SlicePoints only contains keys %s.' % ( slicer.slicePoints.keys()) raise ValueError(errMessage) plotDict = {} plotDict.update(self.defaultPlotDict) plotDict.update(userPlotDict) if plotDict['zp'] is not None: metricValue = metricValueIn - plotDict['zp'] elif plotDict['normVal'] is not None: metricValue = metricValueIn / plotDict['normVal'] else: metricValue = metricValueIn fig = plt.figure(fignum, figsize=plotDict['figsize']) # other projections available include # ['aitoff', 'hammer', 'lambert', 'mollweide', 'polar', 'rectilinear'] ax = fig.add_subplot(111, projection=plotDict['projection']) # Set up valid datapoints and colormin/max values. if plotDict['plotMask']: # Plot all data points. mask = np.ones(len(metricValue), dtype='bool') else: # Only plot points which are not masked. Flip numpy ma mask where 'False' == 'good'. mask = ~metricValue.mask # Determine color min/max values. metricValue.compressed = non-masked points. if not plotDict['metricIsColor']: if plotDict['percentileClip'] is not None: pcMin, pcMax = percentileClipping( metricValue.compressed(), percentile=plotDict['percentileClip']) if plotDict['colorMin'] is None: if plotDict['percentileClip']: plotDict['colorMin'] = pcMin else: plotDict['colorMin'] = metricValue.compressed().min() if plotDict['colorMax'] is None: if plotDict['percentileClip']: plotDict['colorMax'] = pcMax else: plotDict['colorMax'] = metricValue.compressed().max() # Avoid colorbars with no range. if plotDict['colorMax'] == plotDict['colorMin']: plotDict['colorMax'] = plotDict['colorMax'] + 1 plotDict['colorMin'] = plotDict['colorMin'] - 1 # Combine to make clims: clims = [plotDict['colorMin'], plotDict['colorMax']] # Determine whether or not to use auto-log scale. if plotDict['logScale'] == 'auto': if plotDict['colorMin'] > 0: if np.log10(plotDict['colorMax']) - np.log10( plotDict['colorMin']) > 3: plotDict['logScale'] = True else: plotDict['logScale'] = False else: plotDict['logScale'] = False if plotDict['logScale']: # Move min/max values to things that can be marked on the colorbar. plotDict['colorMin'] = 10**(int(np.log10( plotDict['colorMin']))) plotDict['colorMax'] = 10**(int(np.log10( plotDict['colorMax']))) # Add ellipses at RA/Dec locations lon = -(slicer.slicePoints['ra'][mask] - plotDict['raCen'] - np.pi) % ( np.pi * 2) - np.pi ellipses = self._plot_tissot_ellipse(lon, slicer.slicePoints['dec'][mask], plotDict['radius'], rasterized=True, ax=ax) if plotDict['metricIsColor']: current = None for ellipse, mVal in zip(ellipses, metricValue.data[mask]): if mVal[3] > 1: ellipse.set_alpha(1.0) ellipse.set_facecolor((mVal[0], mVal[1], mVal[2])) ellipse.set_edgecolor('k') current = ellipse else: ellipse.set_alpha(mVal[3]) ellipse.set_color((mVal[0], mVal[1], mVal[2])) ax.add_patch(ellipse) if current: ax.add_patch(current) else: if plotDict['logScale']: norml = colors.LogNorm() p = PatchCollection(ellipses, cmap=plotDict['cmap'], alpha=plotDict['alpha'], linewidth=0, edgecolor=None, norm=norml, rasterized=True) else: p = PatchCollection(ellipses, cmap=plotDict['cmap'], alpha=plotDict['alpha'], linewidth=0, edgecolor=None, rasterized=True) p.set_array(metricValue.data[mask]) p.set_clim(clims) ax.add_collection(p) # Add color bar (with optional setting of limits) if plotDict['cbar']: cb = plt.colorbar(p, aspect=25, extendrect=True, orientation='horizontal', format=plotDict['cbarFormat']) # If outputing to PDF, this fixes the colorbar white stripes if plotDict['cbar_edge']: cb.solids.set_edgecolor("face") cb.set_label(plotDict['xlabel'], fontsize=plotDict['fontsize']) cb.ax.tick_params(labelsize=plotDict['labelsize']) # Add ecliptic self._plot_ecliptic(plotDict['raCen'], ax=ax) if plotDict['mwZone']: self._plot_mwZone(plotDict['raCen'], ax=ax) ax.grid(True, zorder=1) ax.xaxis.set_ticklabels([]) if plotDict['bgcolor'] is not None: ax.set_axis_bgcolor(plotDict['bgcolor']) # Add label. if plotDict['label'] is not None: if plotDict['fontsize'] is not None: plt.figtext(0.75, 0.9, '%s' % plotDict['label'], fontsize=plotDict['fontsize']) else: plt.figtext(0.75, 0.9, '%s' % plotDict['label']) if plotDict['title'] is not None: if plotDict['fontsize'] is not None: plt.text(0.5, 1.09, plotDict['title'], horizontalalignment='center', transform=ax.transAxes, fontsize=plotDict['fontsize']) else: plt.text(0.5, 1.09, plotDict['title'], horizontalalignment='center', transform=ax.transAxes) return fig.number
def __call__(self, metricValueIn, slicer, userPlotDict, fignum=None): plotDict = {} plotDict.update(self.defaultPlotDict) plotDict.update(userPlotDict) if plotDict['zp'] is not None: metricValue = metricValueIn - plotDict['zp'] elif plotDict['normVal'] is not None: metricValue = metricValueIn / plotDict['normVal'] else: metricValue = metricValueIn if plotDict['percentileClip'] is not None: pcMin, pcMax = percentileClipping(metricValue.compressed(), percentile=plotDict['percentileClip']) if plotDict['colorMin'] is None: plotDict['colorMin'] = pcMin if plotDict['colorMax'] is None: plotDict['colorMax'] = pcMax if (plotDict['colorMin'] is not None) or (plotDict['colorMax'] is not None): clims = [plotDict['colorMin'], plotDict['colorMax']] else: clims = None # Make sure there is some range on the colorbar if clims is None: if metricValue.compressed().size > 0: clims = [metricValue.compressed().min(), metricValue.compressed().max()] else: clims = [-1, 1] if clims[0] == clims[1]: clims[0] = clims[0] - 1 clims[1] = clims[1] + 1 # Calculate the levels to use for the contour if np.size(plotDict['levels']) > 1: levels = plotDict['levels'] else: step = (clims[1] - clims[0]) / plotDict['levels'] levels = np.arange(clims[0], clims[1] + step, step) fig = plt.figure(fignum) ax = fig.add_subplot(111) # Hide this extra dependency down here for now # if using anaconda, to get basemap: # conda install basemap # Note, this should be possible without basemap, but there are # matplotlib bugs: # http: //stackoverflow.com/questions/31975303/matplotlib-tricontourf-with-an-axis-projection from mpl_toolkits.basemap import Basemap m = Basemap(**plotDict['basemap']) good = np.where(metricValue != slicer.badval) # Contour the plot first to remove any anti-aliasing artifacts. Doesn't seem to work though. See: # http: //stackoverflow.com/questions/15822159/aliasing-when-saving-matplotlib\ # -filled-contour-plot-to-pdf-or-eps # tmpContour = m.contour(np.degrees(slicer.slicePoints['ra'][good]), # np.degrees(slicer.slicePoints['dec'][good]), # metricValue[good], levels, tri=True, # cmap=plotDict['cmap'], ax=ax, latlon=True, # lw=1) CS = m.contourf(np.degrees(slicer.slicePoints['ra'][good]), np.degrees(slicer.slicePoints['dec'][good]), metricValue[good], levels, tri=True, cmap=plotDict['cmap'], ax=ax, latlon=True) # Try to fix the ugly pdf contour problem for c in CS.collections: c.set_edgecolor("face") para = np.arange(0, 89, 20) m.drawparallels(para, labels=para) m.drawmeridians(np.arange(-180, 181, 60)) cb = plt.colorbar(CS, format=plotDict['cbarFormat']) cb.set_label(plotDict['xlabel']) if plotDict['labelsize'] is not None: cb.ax.tick_params(labelsize=plotDict['labelsize']) # Pop in an extra line to raise the title a bit ax.set_title(plotDict['title']+'\n ') # If outputing to PDF, this fixes the colorbar white stripes if plotDict['cbar_edge']: cb.solids.set_edgecolor("face") return fig.number
def plotSkyMap(self, metricValueIn, xlabel=None, title='', raMin=-90, raMax=90, raLen=45., decMin=-2., decMax=2., logScale=False, cbarFormat='%.2f', cmap=cm.jet, percentileClip=None, colorMin=None, colorMax=None, plotMaskedValues=False, zp=None, normVal=None, cbar_edge=True, label=None, fignum=None, **kwargs): """ Plot the sky map of metricValue using healpy cartview plots in thin strips. raMin: Minimum RA to plot (deg) raMax: Max RA to plot (deg). Note raMin/raMax define the centers that will be plotted. raLen: Length of the plotted strips in degrees decMin: minimum dec value to plot decMax: max dec value to plot metricValueIn: metric values xlabel: units for metric color-bar label title: title for plot cbarFormat: format for color bar numerals (i.e. '%.2g', etc) (default to matplotlib default) plotMaskedValues: ignored, here to be consistent with OpsimFieldSlicer.""" if fignum: fig = plt.figue(fignum) else: fig=plt.figure() norm = None if logScale: norm = 'log' if cmap is None: cmap = cm.jet if type(cmap) == str: cmap = getattr(cm,cmap) # Make colormap compatible with healpy cmap = colors.LinearSegmentedColormap('cmap', cmap._segmentdata, cmap.N) cmap.set_over(cmap(1.0)) cmap.set_under('w') cmap.set_bad('gray') if zp: metricValue = metricValueIn - zp elif normVal: metricValue = metricValueIn/normVal else: metricValue = metricValueIn if percentileClip: pcMin, pcMax = percentileClipping(metricValue.compressed(), percentile=percentileClip) if colorMin is None and percentileClip: colorMin = pcMin if colorMax is None and percentileClip: colorMax = pcMax if (colorMin is not None) or (colorMax is not None): clims = [colorMin, colorMax] else: clims = None # Make sure there is some range on the colorbar if clims is None: if metricValue.compressed().size > 0: clims=[metricValue.compressed().min(), metricValue.compressed().max()] else: clims = [-1,1] if clims[0] == clims[1]: clims[0] = clims[0]-1 clims[1] = clims[1]+1 racenters=np.arange(raMin,raMax,raLen) nframes = racenters.size for i, racenter in enumerate(racenters): if i == 0: useTitle = title +' /n'+'%i < RA < %i'%(racenter-raLen, racenter+raLen) else: useTitle = '%i < RA < %i'%(racenter-raLen, racenter+raLen) hp.cartview(metricValue.filled(self.badval), title=useTitle, cbar=False, min=clims[0], max=clims[1], flip='astro', rot=(racenter,0,0), cmap=cmap, norm=norm, lonra=[-raLen,raLen], latra=[decMin,decMax], sub=(nframes+1,1,i+1), fig=fig) hp.graticule(dpar=20, dmer=20, verbose=False) # Add colorbar (not using healpy default colorbar because want more tickmarks). fig = plt.gcf() ax1 = fig.add_axes([0.1, .15,.8,.075]) #left, bottom, width, height # Add label. if label is not None: plt.figtext(0.8, 0.9, '%s' %label) # Make the colorbar as a seperate figure, # from http://matplotlib.org/examples/api/colorbar_only.html cnorm = colors.Normalize(vmin=clims[0], vmax=clims[1]) # supress silly colorbar warnings with warnings.catch_warnings(): warnings.simplefilter("ignore") cb1 = mpl.colorbar.ColorbarBase(ax1, cmap=cmap, norm=cnorm, orientation='horizontal', format=cbarFormat) cb1.set_label(xlabel) # If outputing to PDF, this fixes the colorbar white stripes if cbar_edge: cb1.solids.set_edgecolor("face") fig = plt.gcf() return fig.number
def plotSkyMap(self, metricValueIn, title=None, xlabel=None, units=None, projection='aitoff', radius=1.75/180.*np.pi, logScale='auto', cbar=True, cbarFormat=None, cmap=cm.jet, alpha=1, fignum=None, zp=None, normVal=None, colorMin=None, colorMax=None, percentileClip=None, cbar_edge=True, label=None, plotMask=False, metricIsColor=False, raCen=0.0, mwZone=True, **kwargs): """ Plot the sky map of metricValue. """ from matplotlib.collections import PatchCollection from matplotlib import colors if fignum is None: fig = plt.figure() else: fig = plt.figure(fignum) metricValue = metricValueIn if zp or normVal: if zp: metricValue = metricValue - zp if normVal: metricValue = metricValue/normVal # other projections available include # ['aitoff', 'hammer', 'lambert', 'mollweide', 'polar', 'rectilinear'] ax = fig.add_subplot(111, projection=projection) # Set up valid datapoints and colormin/max values. if plotMask: # Plot all data points. mask = np.ones(len(metricValue), dtype='bool') else: # Only plot points which are not masked. Flip numpy ma mask where 'False' == 'good'. mask = ~metricValue.mask # Determine color min/max values. metricValue.compressed = non-masked points. if percentileClip: pcMin, pcMax = percentileClipping(metricValue.compressed(), percentile=percentileClip) if colorMin is None: if percentileClip: colorMin = pcMin else: colorMin = metricValue.compressed().min() if colorMax is None: if percentileClip: colorMax = pcMax else: colorMax = metricValue.compressed().max() # Avoid colorbars with no range. if colorMax == colorMin: colorMax = colorMax+1 colorMin = colorMin-1 # Combine to make clims: clims = [colorMin, colorMax] # Determine whether or not to use auto-log scale. if logScale == 'auto': if colorMin > 0: if np.log10(colorMax)-np.log10(colorMin) > 3: logScale = True else: logScale = False else: logScale = False if logScale: # Move min/max values to things that can be marked on the colorbar. colorMin = 10**(int(np.log10(colorMin))) colorMax = 10**(int(np.log10(colorMax))) # Add ellipses at RA/Dec locations lon = -(self.slicePoints['ra'][mask] - raCen - np.pi) % (np.pi*2) - np.pi ellipses = self._plot_tissot_ellipse(lon, self.slicePoints['dec'][mask], radius, rasterized=True, ax=ax) if metricIsColor: current = None for ellipse, mVal in zip(ellipses, metricValue.data[mask]): if mVal[3] > 1: ellipse.set_alpha(1.0) ellipse.set_facecolor((mVal[0], mVal[1], mVal[2])) ellipse.set_edgecolor('k') current = ellipse else: ellipse.set_alpha(mVal[3]) ellipse.set_color((mVal[0], mVal[1], mVal[2])) ax.add_patch(ellipse) if current: ax.add_patch(current) else: if logScale: norml = colors.LogNorm() p = PatchCollection(ellipses, cmap=cmap, alpha=alpha, linewidth=0, edgecolor=None, norm=norml, rasterized=True) else: p = PatchCollection(ellipses, cmap=cmap, alpha=alpha, linewidth=0, edgecolor=None, rasterized=True) p.set_array(metricValue.data[mask]) p.set_clim(clims) ax.add_collection(p) # Add color bar (with optional setting of limits) if cbar: cb = plt.colorbar(p, aspect=25, extend='both', extendrect=True, orientation='horizontal', format=cbarFormat) # If outputing to PDF, this fixes the colorbar white stripes if cbar_edge: cb.solids.set_edgecolor("face") if xlabel is not None: cb.set_label(xlabel) elif units is not None: cb.set_label(units) # Add ecliptic self._plot_ecliptic(raCen, ax=ax) if mwZone: self._plot_mwZone(raCen, ax=ax) ax.grid(True, zorder=1) ax.xaxis.set_ticklabels([]) # Add label. if label is not None: plt.figtext(0.75, 0.9, '%s' %label) if title is not None: plt.text(0.5, 1.09, title, horizontalalignment='center', transform=ax.transAxes) return fig.number
def plotBinnedData(self, metricValues, fignum=None, title=None, units=None, label=None, addLegend=False, legendloc='upper left', filled=False, alpha=0.5, logScale=False, percentileClip=None, ylabel=None, xlabel=None, xMin=None, xMax=None, yMin=None, yMax=None, color='b', linestyle='-', **kwargs): """ Plot a set of oneD binned metric data. metricValues = the values to be plotted at each bin title = title for the plot (default None) xlabel = x axis label (default None) ylabel = y axis label (default None) fignum = the figure number to use (default None - will generate new figure) label = the label to use for the figure legend (default None) addLegend = flag for whether or not to add a legend (default False) legendloc = location for legend (default 'upper left') filled = flag to plot histogram as filled bars or lines (default False = lines) alpha = alpha value for plot bins if filled (default 0.5). logScale = make the y-axis log (default False) percentileClip = percentile clip hi/low outliers before setting the y axis limits yMin/Max = min/max for y-axis (overrides percentileClip) xMin/Max = min/max for x-axis (typically set by bin values though) """ if color is None: color = 'b' # Plot the histogrammed data. fig = plt.figure(fignum) leftedge = self.slicePoints['bins'][:-1] width = np.diff(self.slicePoints['bins']) if filled: plt.bar(leftedge, metricValues.filled(), width, label=label, linewidth=0, alpha=alpha, log=logScale, color=color) else: good = np.where(metricValues.mask == False) x = np.ravel(zip(leftedge[good], leftedge[good]+width[good])) y = np.ravel(zip(metricValues[good], metricValues[good])) if logScale: plt.semilogy(x, y, label=label, color=color, linestyle=linestyle, alpha=alpha) else: plt.plot(x, y, label=label, color=color, linestyle=linestyle, alpha=alpha) # The ylabel will always be built by the sliceMetric. if ylabel is not None: plt.ylabel(ylabel) # The xlabel will always be built by the SliceMetric, so this will generally # be ignored, but is provided for users who may be working directly with Slicer. if xlabel is None: xlabel=self.sliceColName if units != None: xlabel += ' (' + self.sliceColUnits + ')' plt.xlabel(xlabel) # Set y limits (either from values in args, percentileClipping or compressed data values). if (yMin is None) or (yMax is None): if percentileClip: yMin, yMax = percentileClipping(metricValues.compressed(), percentile=percentileClip) if yMin is not None and yMax is not None: plt.ylim(yMin, yMax) # Set x limits if given in kwargs. if (xMin is not None) or (xMax is not None): plt.xlim(xMin, xMax) if (addLegend): plt.legend(fancybox=True, prop={'size':'smaller'}, loc=legendloc, numpoints=1) if (title!=None): plt.title(title) return fig.number
def __call__(self, metricValues, slicer, userPlotDict, fignum=None): """ Plot a set of oneD binned metric data. """ if slicer.slicerName != 'OneDSlicer': raise ValueError( 'OneDBinnedData plotter is for use with OneDSlicer') fig = plt.figure(fignum) plotDict = {} plotDict.update(self.defaultPlotDict) plotDict.update(userPlotDict) # Plot the histogrammed data. if 'bins' not in slicer.slicePoints: raise ValueError( 'OneDSlicer has to contain bins in slicePoints metadata') leftedge = slicer.slicePoints['bins'][:-1] width = np.diff(slicer.slicePoints['bins']) if plotDict['filled']: plt.bar(leftedge, metricValues.filled(), width, label=plotDict['label'], linewidth=0, alpha=plotDict['alpha'], log=plotDict['logScale'], color=plotDict['color']) else: good = np.where(metricValues.mask == False) x = np.ravel(zip(leftedge[good], leftedge[good] + width[good])) y = np.ravel(zip(metricValues[good], metricValues[good])) if plotDict['logScale']: plt.semilogy(x, y, label=plotDict['label'], color=plotDict['color'], linestyle=plotDict['linestyle'], linewidth=plotDict['linewidth'], alpha=plotDict['alpha']) else: plt.plot(x, y, label=plotDict['label'], color=plotDict['color'], linestyle=plotDict['linestyle'], linewidth=plotDict['linewidth'], alpha=plotDict['alpha']) if 'ylabel' in plotDict: plt.ylabel(plotDict['ylabel'], fontsize=plotDict['fontsize']) if 'xlabel' in plotDict: plt.xlabel(plotDict['xlabel'], fontsize=plotDict['fontsize']) # Set y limits (either from values in args, percentileClipping or compressed data values). if (plotDict['yMin'] is None) or (plotDict['yMax'] is None): if plotDict['percentileClip'] is not None: plotDict['yMin'], plotDict['yMax'] = percentileClipping( metricValues.compressed(), percentile=plotDict['percentileClip']) # Set y and x limits, if provided. if 'yMin' in plotDict: if plotDict['yMin'] is not None: plt.ylim(ymin=plotDict['yMin']) if 'yMax' in plotDict: if plotDict['yMax'] is not None: plt.ylim(ymax=plotDict['yMax']) if 'xMin' in plotDict: if plotDict['xMin'] is not None: plt.xlim(xmin=plotDict['xMin']) if 'xMax' in plotDict: if plotDict['xMax'] is not None: plt.xlim(xmax=plotDict['xMax']) if 'title' in plotDict: plt.title(plotDict['title']) return fig.number
def __call__(self, metricValueIn, slicer, userPlotDict, fignum=None): """ Plot a histogram of metricValues (such as would come from a spatial slicer). """ # Adjust metric values by zeropoint or normVal, and use 'compressed' version of masked array. plotDict = {} plotDict.update(self.defaultPlotDict) plotDict.update(userPlotDict) metricValue = applyZPNorm(metricValueIn, plotDict) metricValue = metricValue.compressed() # Toss any NaNs or infs metricValue = metricValue[np.isfinite(metricValue)] # Determine percentile clipped X range, if set. (and xmin/max not set). if plotDict['xMin'] is None and plotDict['xMax'] is None: if plotDict['percentileClip']: plotDict['xMin'], plotDict['xMax'] = percentileClipping( metricValue, percentile=plotDict['percentileClip']) # Set the histogram range values, to avoid cases of trying to histogram single-valued data. # First we try to use the range specified by a user, if there is one. Then use the data if not. # all of this only works if plotDict is not cumulative. histRange = [plotDict['xMin'], plotDict['xMax']] if histRange[0] is None: histRange[0] = metricValue.min() if histRange[1] is None: histRange[1] = metricValue.max() # Need to have some range of values on the histogram, or it will fail. if histRange[0] == histRange[1]: warnings.warn( 'Histogram range was single-valued; expanding default range.') histRange[1] = histRange[0] + 1.0 # Set up the bins for the histogram. User specified 'bins' overrides 'binsize'. # Note that 'bins' could be a single number or an array, simply passed to plt.histogram. if plotDict['bins'] is not None: bins = plotDict['bins'] elif plotDict['binsize'] is not None: # If generating a cumulative histogram, want to use full range of data (but with given binsize). # .. but if user set histRange to be wider than full range of data, then # extend bins to cover this range, so we can make prettier plots. if plotDict['cumulative']: if plotDict['xMin'] is not None: # Potentially, expand the range for the cumulative histogram. bmin = np.min([metricValue.min(), plotDict['xMin']]) else: bmin = metricValue.min() if plotDict['xMax'] is not None: bmax = np.max([metricValue.max(), plotDict['xMax']]) else: bmax = metricValue.max() bins = np.arange(bmin, bmax + plotDict['binsize'] / 2.0, plotDict['binsize']) # Otherwise, not cumulative so just use metric values, without potential expansion. else: bins = np.arange(histRange[0], histRange[1] + plotDict['binsize'] / 2.0, plotDict['binsize']) # Catch edge-case where there is only 1 bin value if bins.size < 2: bins = np.arange(bins.min() - plotDict['binsize'] * 2.0, bins.max() + plotDict['binsize'] * 2.0, plotDict['binsize']) else: # If user did not specify bins or binsize, then we try to figure out a good number of bins. bins = optimalBins(metricValue) # Generate plots. fig = plt.figure(fignum, figsize=plotDict['figsize']) ax = fig.add_subplot(plotDict['subplot']) # Check if any data falls within histRange, because otherwise histogram generation will fail. if isinstance(bins, np.ndarray): condition = ((metricValue >= bins.min()) & (metricValue <= bins.max())) else: condition = ((metricValue >= histRange[0]) & (metricValue <= histRange[1])) plotValue = metricValue[condition] if len(plotValue) == 0: # No data is within histRange/bins. So let's just make a simple histogram anyway. n, b, p = plt.hist(metricValue, bins=50, histtype='step', cumulative=plotDict['cumulative'], log=plotDict['logScale'], label=plotDict['label'], color=plotDict['color']) else: # There is data to plot, and we've already ensured histRange/bins are more than single value. n, b, p = plt.hist(metricValue, bins=bins, range=histRange, histtype='step', log=plotDict['logScale'], cumulative=plotDict['cumulative'], label=plotDict['label'], color=plotDict['color']) hist_ylims = plt.ylim() if n.max() > hist_ylims[1]: plt.ylim(top=n.max()) if n.min() < hist_ylims[0] and not plotDict['logScale']: plt.ylim(bottom=n.min()) # Fill in axes labels and limits. # Option to use 'scale' to turn y axis into area or other value. def mjrFormatter(y, pos): if not isinstance(plotDict['scale'], numbers.Number): raise ValueError( 'plotDict["scale"] must be a number to scale the y axis.') return plotDict['yaxisformat'] % (y * plotDict['scale']) ax.yaxis.set_major_formatter(FuncFormatter(mjrFormatter)) # Set optional x, y limits. if 'xMin' in plotDict: plt.xlim(left=plotDict['xMin']) if 'xMax' in plotDict: plt.xlim(right=plotDict['xMax']) if 'yMin' in plotDict: plt.ylim(bottom=plotDict['yMin']) if 'yMax' in plotDict: plt.ylim(top=plotDict['yMax']) # Set/Add various labels. plt.xlabel(plotDict['xlabel'], fontsize=plotDict['fontsize']) plt.ylabel(plotDict['ylabel'], fontsize=plotDict['fontsize']) plt.title(plotDict['title']) if plotDict['labelsize'] is not None: plt.tick_params(axis='x', labelsize=plotDict['labelsize']) plt.tick_params(axis='y', labelsize=plotDict['labelsize']) # Return figure number return fig.number
def __call__(self, metricValueIn, slicer, userPlotDict, fignum=None): """ Plot a histogram of metricValues (such as would come from a spatial slicer). """ # Adjust metric values by zeropoint or normVal, and use 'compressed' version of masked array. plotDict = {} plotDict.update(self.defaultPlotDict) plotDict.update(userPlotDict) metricValue = applyZPNorm(metricValueIn, plotDict) metricValue = metricValue.compressed() # Toss any NaNs or infs metricValue = metricValue[np.isfinite(metricValue)] # Determine percentile clipped X range, if set. (and xmin/max not set). if plotDict['xMin'] is None and plotDict['xMax'] is None: if plotDict['percentileClip']: plotDict['xMin'], plotDict['xMax'] = percentileClipping(metricValue, percentile=plotDict['percentileClip']) # Set the histogram range values, to avoid cases of trying to histogram single-valued data. # First we try to use the range specified by a user, if there is one. Then use the data if not. # all of this only works if plotDict is not cumulative. histRange = [plotDict['xMin'], plotDict['xMax']] if histRange[0] is None: histRange[0] = metricValue.min() if histRange[1] is None: histRange[1] = metricValue.max() # Need to have some range of values on the histogram, or it will fail. if histRange[0] == histRange[1]: warnings.warn('Histogram range was single-valued; expanding default range.') histRange[1] = histRange[0] + 1.0 # Set up the bins for the histogram. User specified 'bins' overrides 'binsize'. # Note that 'bins' could be a single number or an array, simply passed to plt.histogram. if plotDict['bins'] is not None: bins = plotDict['bins'] elif plotDict['binsize'] is not None: # If generating a cumulative histogram, want to use full range of data (but with given binsize). # .. but if user set histRange to be wider than full range of data, then # extend bins to cover this range, so we can make prettier plots. if plotDict['cumulative']: if plotDict['xMin'] is not None: # Potentially, expand the range for the cumulative histogram. bmin = np.min([metricValue.min(), plotDict['xMin']]) else: bmin = metricValue.min() if plotDict['xMax'] is not None: bmax = np.max([metricValue.max(), plotDict['xMax']]) else: bmax = metricValue.max() bins = np.arange(bmin, bmax + plotDict['binsize'] / 2.0, plotDict['binsize']) # Otherwise, not cumulative so just use metric values, without potential expansion. else: bins = np.arange(histRange[0], histRange[1] + plotDict['binsize'] / 2.0, plotDict['binsize']) # Catch edge-case where there is only 1 bin value if bins.size < 2: bins = np.arange(bins.min() - plotDict['binsize'] * 2.0, bins.max() + plotDict['binsize'] * 2.0, plotDict['binsize']) else: # If user did not specify bins or binsize, then we try to figure out a good number of bins. bins = optimalBins(metricValue) # Generate plots. fig = plt.figure(fignum, figsize=plotDict['figsize']) ax = fig.add_subplot(plotDict['subplot']) # Check if any data falls within histRange, because otherwise histogram generation will fail. if isinstance(bins, np.ndarray): condition = ((metricValue >= bins.min()) & (metricValue <= bins.max())) else: condition = ((metricValue >= histRange[0]) & (metricValue <= histRange[1])) plotValue = metricValue[condition] if len(plotValue) == 0: # No data is within histRange/bins. So let's just make a simple histogram anyway. n, b, p = plt.hist(metricValue, bins=50, histtype='step', cumulative=plotDict['cumulative'], log=plotDict['logScale'], label=plotDict['label'], color=plotDict['color']) else: # There is data to plot, and we've already ensured histRange/bins are more than single value. n, b, p = plt.hist(metricValue, bins=bins, range=histRange, histtype='step', log=plotDict['logScale'], cumulative=plotDict['cumulative'], label=plotDict['label'], color=plotDict['color']) hist_ylims = plt.ylim() if n.max() > hist_ylims[1]: plt.ylim(ymax = n.max()) if n.min() < hist_ylims[0] and not plotDict['logScale']: plt.ylim(ymin = n.min()) # Fill in axes labels and limits. # Option to use 'scale' to turn y axis into area or other value. def mjrFormatter(y, pos): if not isinstance(plotDict['scale'], numbers.Number): raise ValueError('plotDict["scale"] must be a number to scale the y axis.') return plotDict['yaxisformat'] % (y * plotDict['scale']) ax.yaxis.set_major_formatter(FuncFormatter(mjrFormatter)) # Set optional x, y limits. if 'xMin' in plotDict: plt.xlim(xmin=plotDict['xMin']) if 'xMax' in plotDict: plt.xlim(xmax=plotDict['xMax']) if 'yMin' in plotDict: plt.ylim(ymin=plotDict['yMin']) if 'yMax' in plotDict: plt.ylim(ymax=plotDict['yMax']) # Set/Add various labels. plt.xlabel(plotDict['xlabel'], fontsize=plotDict['fontsize']) plt.ylabel(plotDict['ylabel'], fontsize=plotDict['fontsize']) plt.title(plotDict['title']) if plotDict['labelsize'] is not None: plt.tick_params(axis='x', labelsize=plotDict['labelsize']) plt.tick_params(axis='y', labelsize=plotDict['labelsize']) # Return figure number return fig.number