Hide keyboard shortcuts

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

from builtins import zip 

import numpy as np 

import healpy as hp 

import matplotlib.pyplot as plt 

 

import lsst.sims.maf.metrics as metrics 

 

from .plotHandler import BasePlotter 

 

__all__ = ['FOPlot', 'SummaryHistogram'] 

 

class FOPlot(BasePlotter): 

""" 

Special plotter to generate and label fO plots. 

""" 

def __init__(self): 

self.plotType = 'FO' 

self.objectPlotter = False 

self.defaultPlotDict = {'title': None, 'xlabel': 'Number of visits', 

'ylabel': 'Area (1000s of square degrees)', 

'scale': None, 'Asky': 18000., 'Nvisits': 825, 

'xMin': 0, 'xMax': None, 'yMin': 0, 'yMax': None, 

'linewidth': 2, 'reflinewidth': 2} 

 

def __call__(self, metricValue, slicer, userPlotDict, fignum=None): 

""" 

Parameters 

---------- 

metricValue : numpy.ma.MaskedArray 

The metric values calculated with the 'Count' metric and a healpix slicer. 

slicer : lsst.sims.maf.slicers.HealpixSlicer 

userPlotDict: dict 

Dictionary of plot parameters set by user (overrides default values). 

Note that Asky and Nvisits values set here and in the slicer should be consistent, 

for plot labels and summary statistic values to be consistent. 

fignum : int 

Matplotlib figure number to use (default = None, starts new figure). 

 

Returns 

------- 

int 

Matplotlib figure number used to create the plot. 

""" 

if not hasattr(slicer, 'nside'): 

raise ValueError('FOPlot to be used with healpix or healpix derived slicers.') 

fig = plt.figure(fignum) 

plotDict = {} 

plotDict.update(self.defaultPlotDict) 

plotDict.update(userPlotDict) 

 

if plotDict['scale'] is None: 

plotDict['scale'] = (hp.nside2pixarea(slicer.nside, degrees=True) / 1000.0) 

 

# Expect metricValue to be something like number of visits 

cumulativeArea = np.arange(1, metricValue.compressed().size + 1)[::-1] * plotDict['scale'] 

plt.plot(np.sort(metricValue.compressed()), cumulativeArea, 'k-', 

linewidth=plotDict['linewidth'], zorder=0) 

# This is breaking the rules and calculating the summary stats in two places. 

# Could just calculate summary stats and pass in labels. 

rarr = np.array(list(zip(metricValue.compressed())), 

dtype=[('fO', metricValue.dtype)]) 

fOArea = metrics.fOArea(col='fO', Asky=plotDict['Asky'], norm=False, 

nside=slicer.nside).run(rarr) 

fONv = metrics.fONv(col='fO', Nvisit=plotDict['Nvisits'], norm=False, 

nside=slicer.nside).run(rarr) 

 

plt.axvline(x=plotDict['Nvisits'], linewidth=plotDict['reflinewidth'], color='b') 

plt.axhline(y=plotDict['Asky'] / 1000., linewidth=plotDict['reflinewidth'], color='r') 

# Add lines for Nvis_median and fOArea: note if these are -666 (badval), 

# the default xMin/yMin values will just leave them off the edges of the plot. 

Nvis_median = fONv['value'][np.where(fONv['name'] == 'MedianNvis')] 

plt.axhline(y=Nvis_median / 1000., linewidth=plotDict['reflinewidth'], color='b', 

alpha=.5, label=r'f$_0$ Median Nvisits=%.3g' % Nvis_median) 

plt.axvline(x=fOArea, linewidth=plotDict['reflinewidth'], color='r', 

alpha=.5, label='f$_0$ Area=%.3g' % fOArea) 

plt.legend(loc='lower left', fontsize='small', numpoints=1) 

 

plt.xlabel(plotDict['xlabel']) 

plt.ylabel(plotDict['ylabel']) 

plt.title(plotDict['title']) 

 

xMin = plotDict['xMin'] 

xMax = plotDict['xMax'] 

yMin = plotDict['yMin'] 

yMax = plotDict['yMax'] 

if (xMin is not None) or (xMax is not None): 

plt.xlim([xMin, xMax]) 

if (yMin is not None) or (yMax is not None): 

plt.ylim([yMin, yMax]) 

return fig.number 

 

 

class SummaryHistogram(BasePlotter): 

""" 

Special plotter to summarize metrics which return a set of values at each slicepoint, 

such as if a histogram was calculated at each slicepoint 

(e.g. with the lsst.sims.maf.metrics.TgapsMetric). 

Effectively marginalizes the calculated values over the sky, and plots the a summarized 

version (reduced to a single according to the plotDict['metricReduce'] metric). 

""" 

 

def __init__(self): 

self.plotType = 'SummaryHistogram' 

self.objectPlotter = True 

self.defaultPlotDict = {'title': None, 'xlabel': None, 'ylabel': 'Count', 'label': None, 

'cumulative': False, 'xMin': None, 'xMax': None, 'yMin': None, 'yMax': None, 

'color': 'b', 'linestyle': '-', 'histStyle': True, 'grid': True, 

'metricReduce': metrics.SumMetric(), 'bins': None} 

 

def __call__(self, metricValue, slicer, userPlotDict, fignum=None): 

""" 

Parameters 

---------- 

metricValue : numpy.ma.MaskedArray 

Handles 'object' datatypes for the masked array. 

slicer : lsst.sims.maf.slicers 

Any MAF slicer. 

userPlotDict: dict 

Dictionary of plot parameters set by user (overrides default values). 

'metricReduce' (an lsst.sims.maf.metric) indicates how to marginalize the metric values 

calculated at each point to a single series of values over the sky. 

'histStyle' (True/False) indicates whether to plot the results as a step histogram (True) 

or as a series of values (False) 

'bins' (np.ndarray) sets the x values for the resulting plot and should generally match 

the bins used with the metric. 

fignum : int 

Matplotlib figure number to use (default = None, starts new figure). 

 

Returns 

------- 

int 

Matplotlib figure number used to create the plot. 

""" 

fig = plt.figure(fignum) 

plotDict = {} 

plotDict.update(self.defaultPlotDict) 

plotDict.update(userPlotDict) 

# Combine the metric values across all slicePoints. 

if not isinstance(plotDict['metricReduce'], metrics.BaseMetric): 

raise ValueError('Expected plotDict[metricReduce] to be a MAF metric object.') 

# Get the data type 

dt = metricValue.compressed()[0].dtype 

# Change an array of arrays (dtype=object) to a 2-d array of correct dtype 

mV = np.array(metricValue.compressed().tolist(), dtype=[('metricValue', dt)]) 

# Make an array to hold the combined result 

finalHist = np.zeros(mV.shape[1], dtype=float) 

metric = plotDict['metricReduce'] 

metric.colname = 'metricValue' 

# Loop over each bin and use the selected metric to combine the results 

for i in np.arange(finalHist.size): 

finalHist[i] = metric.run(mV[:, i]) 

bins = plotDict['bins'] 

if plotDict['histStyle']: 

width = np.diff(bins) 

leftedge = bins[:-1] - width/2.0 

rightedge = bins[:-1] + width/2.0 

#x = np.ravel(list(zip(bins[:-1], bins[1:]))) 

x = np.ravel(list(zip(leftedge, rightedge))) 

y = np.ravel(list(zip(finalHist, finalHist))) 

else: 

# Could use this to plot things like FFT 

x = bins[:-1] 

y = finalHist 

# Make the plot. 

plt.plot(x, y, linestyle=plotDict['linestyle'], 

label=plotDict['label'], color=plotDict['color']) 

# Add labels. 

plt.xlabel(plotDict['xlabel']) 

plt.ylabel(plotDict['ylabel']) 

plt.title(plotDict['title']) 

plt.grid(plotDict['grid'], alpha=0.3) 

# Set y and x limits, if provided. 

if plotDict['xMin'] is not None: 

plt.xlim(xmin=plotDict['xMin']) 

elif bins[0] == 0: 

plt.xlim(xmin=0) 

if plotDict['xMax'] is not None: 

plt.xlim(xmax=plotDict['xMax']) 

if plotDict['yMin'] is not None: 

plt.ylim(ymin=plotDict['yMin']) 

elif finalHist.min() == 0: 

plotDict['yMin'] = 0 

if plotDict['yMax'] is not None: 

plt.ylim(ymax=plotDict['yMax']) 

 

return fig.number