Coverage for python/lsst/sims/maf/plots/specialPlotters.py : 11%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from builtins import zip
2import numpy as np
3import healpy as hp
4import matplotlib.pyplot as plt
6import lsst.sims.maf.metrics as metrics
8from .plotHandler import BasePlotter
10__all__ = ['FOPlot', 'SummaryHistogram']
12class FOPlot(BasePlotter):
13 """
14 Special plotter to generate and label fO plots.
15 """
16 def __init__(self):
17 self.plotType = 'FO'
18 self.objectPlotter = False
19 self.defaultPlotDict = {'title': None, 'xlabel': 'Number of visits',
20 'ylabel': 'Area (1000s of square degrees)',
21 'scale': None, 'Asky': 18000., 'Nvisits': 825,
22 'xMin': 0, 'xMax': None, 'yMin': 0, 'yMax': None,
23 'linewidth': 2, 'reflinewidth': 2}
25 def __call__(self, metricValue, slicer, userPlotDict, fignum=None):
26 """
27 Parameters
28 ----------
29 metricValue : numpy.ma.MaskedArray
30 The metric values calculated with the 'Count' metric and a healpix slicer.
31 slicer : lsst.sims.maf.slicers.HealpixSlicer
32 userPlotDict: dict
33 Dictionary of plot parameters set by user (overrides default values).
34 Note that Asky and Nvisits values set here and in the slicer should be consistent,
35 for plot labels and summary statistic values to be consistent.
36 fignum : int
37 Matplotlib figure number to use (default = None, starts new figure).
39 Returns
40 -------
41 int
42 Matplotlib figure number used to create the plot.
43 """
44 if not hasattr(slicer, 'nside'):
45 raise ValueError('FOPlot to be used with healpix or healpix derived slicers.')
46 fig = plt.figure(fignum)
47 plotDict = {}
48 plotDict.update(self.defaultPlotDict)
49 plotDict.update(userPlotDict)
51 if plotDict['scale'] is None:
52 plotDict['scale'] = (hp.nside2pixarea(slicer.nside, degrees=True) / 1000.0)
54 # Expect metricValue to be something like number of visits
55 cumulativeArea = np.arange(1, metricValue.compressed().size + 1)[::-1] * plotDict['scale']
56 plt.plot(np.sort(metricValue.compressed()), cumulativeArea, 'k-',
57 linewidth=plotDict['linewidth'], zorder=0)
58 # This is breaking the rules and calculating the summary stats in two places.
59 # Could just calculate summary stats and pass in labels.
60 rarr = np.array(list(zip(metricValue.compressed())),
61 dtype=[('fO', metricValue.dtype)])
62 fOArea = metrics.fOArea(col='fO', Asky=plotDict['Asky'], norm=False,
63 nside=slicer.nside).run(rarr)
64 fONv = metrics.fONv(col='fO', Nvisit=plotDict['Nvisits'], norm=False,
65 nside=slicer.nside).run(rarr)
67 plt.axvline(x=plotDict['Nvisits'], linewidth=plotDict['reflinewidth'], color='b')
68 plt.axhline(y=plotDict['Asky'] / 1000., linewidth=plotDict['reflinewidth'], color='r')
69 # Add lines for Nvis_median and fOArea: note if these are -666 (badval),
70 # the default xMin/yMin values will just leave them off the edges of the plot.
71 Nvis_median = fONv['value'][np.where(fONv['name'] == 'MedianNvis')]
72 plt.axhline(y=Nvis_median / 1000., linewidth=plotDict['reflinewidth'], color='b',
73 alpha=.5, label=r'f$_0$ Median Nvisits=%.3g' % Nvis_median)
74 plt.axvline(x=fOArea, linewidth=plotDict['reflinewidth'], color='r',
75 alpha=.5, label='f$_0$ Area=%.3g' % fOArea)
76 plt.legend(loc='lower left', fontsize='small', numpoints=1)
78 plt.xlabel(plotDict['xlabel'])
79 plt.ylabel(plotDict['ylabel'])
80 plt.title(plotDict['title'])
82 xMin = plotDict['xMin']
83 xMax = plotDict['xMax']
84 yMin = plotDict['yMin']
85 yMax = plotDict['yMax']
86 if (xMin is not None) or (xMax is not None):
87 plt.xlim([xMin, xMax])
88 if (yMin is not None) or (yMax is not None):
89 plt.ylim([yMin, yMax])
90 return fig.number
93class SummaryHistogram(BasePlotter):
94 """
95 Special plotter to summarize metrics which return a set of values at each slicepoint,
96 such as if a histogram was calculated at each slicepoint
97 (e.g. with the lsst.sims.maf.metrics.TgapsMetric).
98 Effectively marginalizes the calculated values over the sky, and plots the a summarized
99 version (reduced to a single according to the plotDict['metricReduce'] metric).
100 """
102 def __init__(self):
103 self.plotType = 'SummaryHistogram'
104 self.objectPlotter = True
105 self.defaultPlotDict = {'title': None, 'xlabel': None, 'ylabel': 'Count', 'label': None,
106 'cumulative': False, 'xMin': None, 'xMax': None, 'yMin': None, 'yMax': None,
107 'color': 'b', 'linestyle': '-', 'histStyle': True, 'grid': True,
108 'metricReduce': metrics.SumMetric(), 'bins': None}
110 def __call__(self, metricValue, slicer, userPlotDict, fignum=None):
111 """
112 Parameters
113 ----------
114 metricValue : numpy.ma.MaskedArray
115 Handles 'object' datatypes for the masked array.
116 slicer : lsst.sims.maf.slicers
117 Any MAF slicer.
118 userPlotDict: dict
119 Dictionary of plot parameters set by user (overrides default values).
120 'metricReduce' (an lsst.sims.maf.metric) indicates how to marginalize the metric values
121 calculated at each point to a single series of values over the sky.
122 'histStyle' (True/False) indicates whether to plot the results as a step histogram (True)
123 or as a series of values (False)
124 'bins' (np.ndarray) sets the x values for the resulting plot and should generally match
125 the bins used with the metric.
126 fignum : int
127 Matplotlib figure number to use (default = None, starts new figure).
129 Returns
130 -------
131 int
132 Matplotlib figure number used to create the plot.
133 """
134 fig = plt.figure(fignum)
135 plotDict = {}
136 plotDict.update(self.defaultPlotDict)
137 plotDict.update(userPlotDict)
138 # Combine the metric values across all slicePoints.
139 if not isinstance(plotDict['metricReduce'], metrics.BaseMetric):
140 raise ValueError('Expected plotDict[metricReduce] to be a MAF metric object.')
141 # Get the data type
142 dt = metricValue.compressed()[0].dtype
143 # Change an array of arrays (dtype=object) to a 2-d array of correct dtype
144 mV = np.array(metricValue.compressed().tolist(), dtype=[('metricValue', dt)])
145 # Make an array to hold the combined result
146 finalHist = np.zeros(mV.shape[1], dtype=float)
147 metric = plotDict['metricReduce']
148 metric.colname = 'metricValue'
149 # Loop over each bin and use the selected metric to combine the results
150 for i in np.arange(finalHist.size):
151 finalHist[i] = metric.run(mV[:, i])
152 bins = plotDict['bins']
153 if plotDict['histStyle']:
154 width = np.diff(bins)
155 leftedge = bins[:-1] - width/2.0
156 rightedge = bins[:-1] + width/2.0
157 #x = np.ravel(list(zip(bins[:-1], bins[1:])))
158 x = np.ravel(list(zip(leftedge, rightedge)))
159 y = np.ravel(list(zip(finalHist, finalHist)))
160 else:
161 # Could use this to plot things like FFT
162 x = bins[:-1]
163 y = finalHist
164 # Make the plot.
165 plt.plot(x, y, linestyle=plotDict['linestyle'],
166 label=plotDict['label'], color=plotDict['color'])
167 # Add labels.
168 plt.xlabel(plotDict['xlabel'])
169 plt.ylabel(plotDict['ylabel'])
170 plt.title(plotDict['title'])
171 plt.grid(plotDict['grid'], alpha=0.3)
172 # Set y and x limits, if provided.
173 if plotDict['xMin'] is not None:
174 plt.xlim(left=plotDict['xMin'])
175 elif bins[0] == 0:
176 plt.xlim(left=0)
177 if plotDict['xMax'] is not None:
178 plt.xlim(right=plotDict['xMax'])
179 if plotDict['yMin'] is not None:
180 plt.ylim(bottom=plotDict['yMin'])
181 elif finalHist.min() == 0:
182 plotDict['yMin'] = 0
183 if plotDict['yMax'] is not None:
184 plt.ylim(top=plotDict['yMax'])
186 return fig.number