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 # Note that Nvis is the number of visits (it's not an area) - so goes on number axis
73 plt.axvline(x=Nvis_median, linewidth=plotDict['reflinewidth'], color='b',
74 alpha=.5, linestyle=':', label=r'f$_0$ Median Nvisits=%.0f' % Nvis_median)
75 plt.axhline(y=fOArea / 1000., linewidth=plotDict['reflinewidth'], color='r',
76 alpha=.5, linestyle=':', label='f$_0$ Area=%.0f' % fOArea)
77 plt.legend(loc='lower left', fontsize='small', numpoints=1)
79 plt.xlabel(plotDict['xlabel'])
80 plt.ylabel(plotDict['ylabel'])
81 plt.title(plotDict['title'])
83 xMin = plotDict['xMin']
84 xMax = plotDict['xMax']
85 yMin = plotDict['yMin']
86 yMax = plotDict['yMax']
87 if (xMin is not None) or (xMax is not None):
88 plt.xlim([xMin, xMax])
89 if (yMin is not None) or (yMax is not None):
90 plt.ylim([yMin, yMax])
91 return fig.number
94class SummaryHistogram(BasePlotter):
95 """
96 Special plotter to summarize metrics which return a set of values at each slicepoint,
97 such as if a histogram was calculated at each slicepoint
98 (e.g. with the lsst.sims.maf.metrics.TgapsMetric).
99 Effectively marginalizes the calculated values over the sky, and plots the a summarized
100 version (reduced to a single according to the plotDict['metricReduce'] metric).
101 """
103 def __init__(self):
104 self.plotType = 'SummaryHistogram'
105 self.objectPlotter = True
106 self.defaultPlotDict = {'title': None, 'xlabel': None, 'ylabel': 'Count', 'label': None,
107 'cumulative': False, 'xMin': None, 'xMax': None, 'yMin': None, 'yMax': None,
108 'color': 'b', 'linestyle': '-', 'histStyle': True, 'grid': True,
109 'metricReduce': metrics.SumMetric(), 'bins': None}
111 def __call__(self, metricValue, slicer, userPlotDict, fignum=None):
112 """
113 Parameters
114 ----------
115 metricValue : numpy.ma.MaskedArray
116 Handles 'object' datatypes for the masked array.
117 slicer : lsst.sims.maf.slicers
118 Any MAF slicer.
119 userPlotDict: dict
120 Dictionary of plot parameters set by user (overrides default values).
121 'metricReduce' (an lsst.sims.maf.metric) indicates how to marginalize the metric values
122 calculated at each point to a single series of values over the sky.
123 'histStyle' (True/False) indicates whether to plot the results as a step histogram (True)
124 or as a series of values (False)
125 'bins' (np.ndarray) sets the x values for the resulting plot and should generally match
126 the bins used with the metric.
127 fignum : int
128 Matplotlib figure number to use (default = None, starts new figure).
130 Returns
131 -------
132 int
133 Matplotlib figure number used to create the plot.
134 """
135 fig = plt.figure(fignum)
136 plotDict = {}
137 plotDict.update(self.defaultPlotDict)
138 plotDict.update(userPlotDict)
139 # Combine the metric values across all slicePoints.
140 if not isinstance(plotDict['metricReduce'], metrics.BaseMetric):
141 raise ValueError('Expected plotDict[metricReduce] to be a MAF metric object.')
142 # Get the data type
143 dt = metricValue.compressed()[0].dtype
144 # Change an array of arrays (dtype=object) to a 2-d array of correct dtype
145 mV = np.array(metricValue.compressed().tolist(), dtype=[('metricValue', dt)])
146 # Make an array to hold the combined result
147 finalHist = np.zeros(mV.shape[1], dtype=float)
148 metric = plotDict['metricReduce']
149 metric.colname = 'metricValue'
150 # Loop over each bin and use the selected metric to combine the results
151 for i in np.arange(finalHist.size):
152 finalHist[i] = metric.run(mV[:, i])
153 bins = plotDict['bins']
154 if plotDict['histStyle']:
155 width = np.diff(bins)
156 leftedge = bins[:-1] - width/2.0
157 rightedge = bins[:-1] + width/2.0
158 #x = np.ravel(list(zip(bins[:-1], bins[1:])))
159 x = np.ravel(list(zip(leftedge, rightedge)))
160 y = np.ravel(list(zip(finalHist, finalHist)))
161 else:
162 # Could use this to plot things like FFT
163 x = bins[:-1]
164 y = finalHist
165 # Make the plot.
166 plt.plot(x, y, linestyle=plotDict['linestyle'],
167 label=plotDict['label'], color=plotDict['color'])
168 # Add labels.
169 plt.xlabel(plotDict['xlabel'])
170 plt.ylabel(plotDict['ylabel'])
171 plt.title(plotDict['title'])
172 plt.grid(plotDict['grid'], alpha=0.3)
173 # Set y and x limits, if provided.
174 if plotDict['xMin'] is not None:
175 plt.xlim(left=plotDict['xMin'])
176 elif bins[0] == 0:
177 plt.xlim(left=0)
178 if plotDict['xMax'] is not None:
179 plt.xlim(right=plotDict['xMax'])
180 if plotDict['yMin'] is not None:
181 plt.ylim(bottom=plotDict['yMin'])
182 elif finalHist.min() == 0:
183 plotDict['yMin'] = 0
184 if plotDict['yMax'] is not None:
185 plt.ylim(top=plotDict['yMax'])
187 return fig.number