LSST Applications  21.0.0-147-g0e635eb1+1acddb5be5,22.0.0+052faf71bd,22.0.0+1ea9a8b2b2,22.0.0+6312710a6c,22.0.0+729191ecac,22.0.0+7589c3a021,22.0.0+9f079a9461,22.0.1-1-g7d6de66+b8044ec9de,22.0.1-1-g87000a6+536b1ee016,22.0.1-1-g8e32f31+6312710a6c,22.0.1-10-gd060f87+016f7cdc03,22.0.1-12-g9c3108e+df145f6f68,22.0.1-16-g314fa6d+c825727ab8,22.0.1-19-g93a5c75+d23f2fb6d8,22.0.1-19-gb93eaa13+aab3ef7709,22.0.1-2-g8ef0a89+b8044ec9de,22.0.1-2-g92698f7+9f079a9461,22.0.1-2-ga9b0f51+052faf71bd,22.0.1-2-gac51dbf+052faf71bd,22.0.1-2-gb66926d+6312710a6c,22.0.1-2-gcb770ba+09e3807989,22.0.1-20-g32debb5+b8044ec9de,22.0.1-23-gc2439a9a+fb0756638e,22.0.1-3-g496fd5d+09117f784f,22.0.1-3-g59f966b+1e6ba2c031,22.0.1-3-g849a1b8+f8b568069f,22.0.1-3-gaaec9c0+c5c846a8b1,22.0.1-32-g5ddfab5d3+60ce4897b0,22.0.1-4-g037fbe1+64e601228d,22.0.1-4-g8623105+b8044ec9de,22.0.1-5-g096abc9+d18c45d440,22.0.1-5-g15c806e+57f5c03693,22.0.1-7-gba73697+57f5c03693,master-g6e05de7fdc+c1283a92b8,master-g72cdda8301+729191ecac,w.2021.39
LSST Data Management Base Package
optimizerDisplay.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008-2013 LSST Corporation.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <http://www.lsstcorp.org/LegalNotices/>.
21 #
22 
23 import numpy
24 import matplotlib
25 import matplotlib.colors
26 from mpl_toolkits.axes_grid1 import make_axes_locatable
27 
28 from .densityPlot import hide_xticklabels, hide_yticklabels
29 from .. import modelfitLib
30 
31 __all__ = ("OptimizerDisplay", )
32 
33 
35 
36  def __init__(self, parent, sample):
37  self.parentparent = parent
38  self.samplesample = sample
39  # scale unit grid by trust radius
40  self.gridgrid = parent.unitGrid * sample.get(parent.recorder.trust)
41  # offset grid to center it on the current parameter point
42  self.gridgrid += sample.get(parent.recorder.parameters).reshape((1,)*parent.ndim + (parent.ndim,))
43  self._objectiveValues_objectiveValues = None
44  self._objectiveModel_objectiveModel = None
45  self.rejectedrejected = []
46 
47  def __getattr__(self, name):
48  # look for keys on the recorder and lookup fields for unknown attributes
49  return self.samplesample.get(getattr(self.parentparent.recorder, name))
50 
51  @property
52  def objectiveValues(self):
53  if self._objectiveValues_objectiveValues is None:
54  self._objectiveValues_objectiveValues = numpy.zeros(self.gridgrid.shape[:-1], dtype=float)
55  self.parentparent.objective.fillObjectiveValueGrid(self.gridgrid.reshape(-1, self.parentparent.ndim),
56  self._objectiveValues_objectiveValues.reshape(-1))
57  good = numpy.isfinite(self._objectiveValues_objectiveValues)
58  self._objectiveValues_objectiveValues[numpy.logical_not(good)] = self._objectiveValues_objectiveValues[good].max()
59  return self._objectiveValues_objectiveValues
60 
61  @property
62  def objectiveModel(self):
63  if self._objectiveModel_objectiveModel is None:
64  self._objectiveModel_objectiveModel = numpy.zeros(self.gridgrid.shape[:-1], dtype=float)
65  self.parentparent.recorder.fillObjectiveModelGrid(self.samplesample,
66  self.gridgrid.reshape(-1, self.parentparent.ndim),
67  self._objectiveModel_objectiveModel.reshape(-1))
68  return self._objectiveModel_objectiveModel
69 
70 
72 
73  def __init__(self, history, model, objective, steps=11):
74  self.recorderrecorder = modelfitLib.OptimizerHistoryRecorder(history.schema)
75  # len(dimensions) == N in comments below
76  self.dimensionsdimensions = list(model.getNonlinearNames()) + list(model.getAmplitudeNames())
77  self.ndimndim = len(self.dimensionsdimensions)
78  self.tracktrack = []
79  self.objectiveobjective = objective
80  # This creates a array with shape [steps, ..., steps, N] (a total of N+1 array dimensions):
81  # this is an N-dimensional grid, with the last dimension of the grid array giving the coordinates
82  # of each grid point.
83  # We slice mgrid to generate the basic grid, which is [N, steps, ..., steps]
84  mgridArgs = (slice(-1.0, 1.0, steps*1j),) * self.ndimndim
85  # We'll index the result of mgrid with these args to make first dimension last
86  transposeArgs = tuple(list(range(1, self.ndimndim+1)) + [0])
87  self.unitGridunitGrid = numpy.mgrid[mgridArgs].transpose(transposeArgs).copy()
88  current = None
89  for sample in history:
90  if sample.get(self.recorderrecorder.state) & modelfitLib.Optimizer.STATUS_STEP_REJECTED:
91  assert current is not None
92  current.rejected.append(sample)
93  continue
94  current = OptimizerIterationDisplay(self, sample)
95  self.tracktrack.append(current)
96 
97  def plot(self, xDim, yDim, n=0):
98  return OptimizerDisplayFigure(self, xDim=xDim, yDim=yDim, n=n)
99 
100 
102 
103  def __init__(self, parent, xDim, yDim, n=0):
104  self.parentparent = parent
105  self.xDimxDim = xDim
106  self.yDimyDim = yDim
107  self.jj = self.parentparent.dimensions.index(self.xDimxDim)
108  self.ii = self.parentparent.dimensions.index(self.yDimyDim)
109  self.yKeyyKey = self.parentparent.recorder.parameters[self.ii]
110  self.xKeyxKey = self.parentparent.recorder.parameters[self.jj]
111  self.zKeyzKey = self.parentparent.recorder.objective
112  # grid slice indices corresponding to the dimensions we're plotting
113  self.slice2dslice2d = [s//2 for s in self.parentparent.unitGrid.shape[:-1]]
114  self.slice2dslice2d[self.ii] = slice(None)
115  self.slice2dslice2d[self.jj] = slice(None)
116  self.slice2dslice2d = tuple(self.slice2dslice2d)
117  self.sliceXsliceX = [s//2 for s in self.parentparent.unitGrid.shape[:-1]]
118  self.sliceXsliceX[self.jj] = slice(None)
119  self.sliceXsliceX = tuple(self.sliceXsliceX)
120  self.sliceYsliceY = [s//2 for s in self.parentparent.unitGrid.shape[:-1]]
121  self.sliceYsliceY[self.ii] = slice(None)
122  self.sliceYsliceY = tuple(self.sliceYsliceY)
123  self.tracktrack = dict(
124  x=numpy.array([iteration.sample.get(self.xKeyxKey) for iteration in self.parentparent.track]),
125  y=numpy.array([iteration.sample.get(self.yKeyyKey) for iteration in self.parentparent.track]),
126  z=numpy.array([iteration.sample.get(self.zKeyzKey) for iteration in self.parentparent.track]),
127  )
128  self.nn = n
129  self.figurefigure = matplotlib.pyplot.figure(f"{xDim} vs {yDim}", figsize=(16, 8))
130  self.figurefigure.subplots_adjust(left=0.025, right=0.975, bottom=0.08, top=0.95, wspace=0.12)
131  self.axes3daxes3d = self.figurefigure.add_subplot(1, 2, 1, projection='3d')
132  self.axes3daxes3d.autoscale(False)
133  self.axes3daxes3d.set_xlabel(self.xDimxDim)
134  self.axes3daxes3d.set_ylabel(self.yDimyDim)
135  self.axes2daxes2d = self.figurefigure.add_subplot(1, 2, 2)
136  self.axes2daxes2d.set_xlabel(self.xDimxDim)
137  self.axes2daxes2d.set_ylabel(self.yDimyDim)
138  self.axes2daxes2d.autoscale(False)
139  divider = make_axes_locatable(self.axes2daxes2d)
140  self.axesXaxesX = divider.append_axes("top", 1.5, pad=0.1, sharex=self.axes2daxes2d)
141  self.axesXaxesX.autoscale(False, axis='x')
142  hide_xticklabels(self.axesXaxesX)
143  self.axesYaxesY = divider.append_axes("right", 1.5, pad=0.1, sharey=self.axes2daxes2d)
144  self.axesYaxesY.autoscale(False, axis='y')
145  hide_yticklabels(self.axesYaxesY)
146  self.artistsartists = []
147  self.guessExtentguessExtent()
148  self.plotTrackplotTrack()
149  self.plotRejectedplotRejected()
150  self.plotSurfacesplotSurfaces()
151 
152  @property
153  def xlim(self):
154  return self._extent_extent[:2]
155 
156  @property
157  def ylim(self):
158  return self._extent_extent[2:4]
159 
160  @property
161  def zlim(self):
162  return self._extent_extent[4:]
163 
164  def guessExtent(self):
165  current = self.parentparent.track[self.nn]
166  x = current.sample.get(self.xKeyxKey)
167  y = current.sample.get(self.yKeyyKey)
168  zMin1 = current.objectiveValues[self.slice2dslice2d].min()
169  zMax1 = current.objectiveValues[self.slice2dslice2d].max()
170  zMin2 = current.objectiveModel[self.slice2dslice2d].min()
171  zMax2 = current.objectiveModel[self.slice2dslice2d].max()
172  self.setExtentsetExtent(x0=x - current.trust, x1=x + current.trust,
173  y0=y - current.trust, y1=y + current.trust,
174  z0=min(zMin1, zMin2), z1=max(zMax1, zMax2), lock=False)
175 
176  def setExtent(self, x0=None, x1=None, y0=None, y1=None, z0=None, z1=None, lock=True):
177  if x0 is None:
178  x0 = self._extent_extent[0]
179  if x1 is None:
180  x1 = self._extent_extent[1]
181  if y0 is None:
182  y0 = self._extent_extent[2]
183  if y1 is None:
184  y1 = self._extent_extent[3]
185  if z0 is None:
186  z0 = self._extent_extent[4]
187  if z1 is None:
188  z1 = self._extent_extent[5]
189  self._extent_extent = (x0, x1, y0, y1, z0, z1)
190  self._lock_lock = lock
191  self.axes3daxes3d.set_xlim(*self.xlimxlim)
192  self.axes3daxes3d.set_ylim(*self.ylimylim)
193  self.axes3daxes3d.set_zlim(*self.zlimzlim)
194  self.axes2daxes2d.set_xlim(*self.xlimxlim)
195  self.axes2daxes2d.set_ylim(*self.ylimylim)
196  self.axesXaxesX.set_ylim(*self.zlimzlim)
197  self.axesYaxesY.set_xlim(*self.zlimzlim)
198 
199  def _clipZ(self, x, y, z):
200  # clipping is currently disabled; more trouble than it's worth
201  if False:
202  mask = numpy.logical_or.reduce([x < self.xlimxlim[0], x > self.xlimxlim[1],
203  y < self.ylimylim[0], y > self.ylimylim[1],
204  z < self.zlimzlim[0], z > self.zlimzlim[1]],
205  axis=0)
206 
207  z[mask] = numpy.nan
208  return numpy.logical_not(mask).astype(int).sum() > 4
209  return True
210 
211  def _contour(self, axes, *args, **kwds):
212  self.artistsartists.extend(axes.contour(*args, **kwds).collections)
213 
214  def plotTrack(self):
215  kwds = dict(markeredgewidth=0, markerfacecolor='g', color='g', marker='o')
216  self.axes3daxes3d.plot(self.tracktrack['x'], self.tracktrack['y'], self.tracktrack['z'], **kwds)
217  self.axes2daxes2d.plot(self.tracktrack['x'], self.tracktrack['y'], **kwds)
218  self.axesXaxesX.plot(self.tracktrack['x'], self.tracktrack['z'], **kwds)
219  self.axesYaxesY.plot(self.tracktrack['z'], self.tracktrack['y'], **kwds)
220 
221  def plotRejected(self):
222  kwds = dict(markeredgewidth=0, markerfacecolor='r', color='r', marker='v')
223  current = self.parentparent.track[self.nn]
224  cx = current.sample.get(self.xKeyxKey)
225  cy = current.sample.get(self.yKeyyKey)
226  cz = current.sample.get(self.zKeyzKey)
227  for r in current.rejected:
228  x = [cx, r.get(self.xKeyxKey)]
229  y = [cy, r.get(self.yKeyyKey)]
230  z = [cz, r.get(self.zKeyzKey)]
231  self.artistsartists.extend(self.axes3daxes3d.plot(x, y, z, **kwds))
232  self.artistsartists.extend(self.axes2daxes2d.plot(x, y, **kwds))
233  self.artistsartists.extend(self.axesXaxesX.plot(x, z, **kwds))
234  self.artistsartists.extend(self.axesYaxesY.plot(z, y, **kwds))
235 
236  def plotSurfaces(self):
237  current = self.parentparent.track[self.nn]
238 
239  # Start with 2-d and 3-d surfaces
240  x = current.grid[self.slice2dslice2d + (self.jj,)]
241  y = current.grid[self.slice2dslice2d + (self.ii,)]
242  z1 = current.objectiveValues[self.slice2dslice2d].copy()
243  z2 = current.objectiveModel[self.slice2dslice2d].copy()
244  norm = matplotlib.colors.Normalize(vmin=self.zlimzlim[0], vmax=self.zlimzlim[1])
245 
246  self._contour_contour(self.axes2daxes2d, x, y, z1, cmap=matplotlib.cm.spring, norm=norm)
247  self._contour_contour(self.axes2daxes2d, x, y, z2, cmap=matplotlib.cm.winter, norm=norm)
248 
249  # matplotlib doesn't do clipping in 3d, so we'll do that manually
250  if self._clipZ_clipZ(x, y, z1):
251  self._contour_contour(self.axes3daxes3d, x, y, z1, cmap=matplotlib.cm.spring, norm=norm)
252  self.artistsartists.append(self.axes3daxes3d.plot_surface(x, y, z1, rstride=1, cstride=1,
253  cmap=matplotlib.cm.spring, norm=norm,
254  linewidth=0, antialiased=1, alpha=0.5))
255  if self._clipZ_clipZ(x, y, z2):
256  self._contour_contour(self.axes3daxes3d, x, y, z2, cmap=matplotlib.cm.winter, norm=norm)
257  self.artistsartists.append(self.axes3daxes3d.plot_surface(x, y, z2, rstride=1, cstride=1,
258  cmap=matplotlib.cm.winter, norm=norm,
259  linewidth=0, antialiased=1, alpha=0.5))
260 
261  # Now the 1-d surfaces
262  self.artistsartists.extend(self.axesXaxesX.plot(current.grid[self.sliceXsliceX + (self.jj,)],
263  current.objectiveValues[self.sliceXsliceX], 'm-'))
264  self.artistsartists.extend(self.axesXaxesX.plot(current.grid[self.sliceXsliceX + (self.jj,)],
265  current.objectiveModel[self.sliceXsliceX], 'c-'))
266  self.artistsartists.extend(self.axesYaxesY.plot(current.objectiveValues[self.sliceYsliceY],
267  current.grid[self.sliceYsliceY + (self.ii,)], 'm-'))
268  self.artistsartists.extend(self.axesYaxesY.plot(current.objectiveModel[self.sliceYsliceY],
269  current.grid[self.sliceYsliceY + (self.ii,)], 'c-'))
270 
271  def move(self, n):
272  self.nn = n
273  if not self._lock_lock:
274  self.guessExtentguessExtent()
275  for artist in self.artistsartists:
276  try:
277  artist.remove()
278  except TypeError:
279  # sometimes matplotlib throws an exception even though everything worked fine
280  pass
281  self.artistsartists = []
282  self.plotSurfacesplotSurfaces()
283  self.plotRejectedplotRejected()
284  self.figurefigure.canvas.draw()
int min
int max
def setExtent(self, x0=None, x1=None, y0=None, y1=None, z0=None, z1=None, lock=True)
def __init__(self, history, model, objective, steps=11)
daf::base::PropertyList * list
Definition: fits.cc:913
std::shared_ptr< FrameSet > append(FrameSet const &first, FrameSet const &second)
Construct a FrameSet that performs two transformations in series.
Definition: functional.cc:33
def plot(mag, width, centers, clusterId, marker="o", markersize=2, markeredgewidth=0, ltype='-', magType="model", clear=True)