From 7a599261680593869bc2708a2a0697f5696f9f48 Mon Sep 17 00:00:00 2001 From: Dan Lipsa Date: Tue, 26 Apr 2016 16:34:06 -0400 Subject: [PATCH] ENH #1885: Show info at clicked point for point datasets --- Packages/vcs/vcs/VTKPlots.py | 197 ++++++++++---------- Packages/vcs/vcs/vcs2vtk.py | 1 + Packages/vcs/vcs/vcsvtk/boxfillpipeline.py | 3 - Packages/vcs/vcs/vcsvtk/isofillpipeline.py | 3 - Packages/vcs/vcs/vcsvtk/isolinepipeline.py | 3 - Packages/vcs/vcs/vcsvtk/meshfillpipeline.py | 3 - Packages/vcs/vcs/vcsvtk/pipeline2d.py | 32 +++- Packages/vcs/vcs/vcsvtk/vectorpipeline.py | 124 ++++-------- testing/vcs/CMakeLists.txt | 41 ++-- testing/vcs/test_vcs_click_info.py | 26 ++- 10 files changed, 197 insertions(+), 236 deletions(-) diff --git a/Packages/vcs/vcs/VTKPlots.py b/Packages/vcs/vcs/VTKPlots.py index 8cfe83a286..37382c0e92 100644 --- a/Packages/vcs/vcs/VTKPlots.py +++ b/Packages/vcs/vcs/VTKPlots.py @@ -46,18 +46,16 @@ def __init__(self, canvas, renWin=None, debug=False, bg=None, geometry=None): self._renderers = {} self._plot_keywords = [ 'cdmsfile', - 'cell_coordinates' - # used to render the continents - 'continents_renderer', + 'cell_coordinates', # dataset bounds in lon/lat coordinates 'dataset_bounds', # This may be smaller than the data viewport. It is used # if autot is passed 'ratio_autot_viewport', - # used to render the dataset - 'dataset_renderer', - # dataset scale: (xScale, yScale) - 'dataset_scale', + # used to render the dataset for clicked point info (hardware selection) + 'surface_renderer', + # (xScale, yScale) - datasets can be scaled using the window ratio + 'surface_scale', # the same as vcs.utils.getworldcoordinates for now. getworldcoordinates uses # gm.datawc_... or, if that is not set, it uses data axis margins (without bounds). 'plotting_dataset_bounds', @@ -138,99 +136,92 @@ def leftButtonPressEvent(self, obj, event): d = vcs.elements["display"][dnm] if d.array[0] is None: continue - t = vcs.elements["template"][d.template] - gm = vcs.elements[d.g_type][d.g_name] - # for non-linear projection or for meshfill. Meshfill is wrapped at - # VTK level, so vcs calculations do not work. - if gm.projection != "linear" or gm.g_name == 'Gfm': - selector = vtk.vtkHardwareSelector() - datasetRenderer = d.backend['dataset_renderer'] - continentsRenderer = d.backend.get('continents_renderer') - dataset = d.backend['vtk_backend_grid'] - if (datasetRenderer and dataset): - selector.SetRenderer(datasetRenderer) - selector.SetArea(xy[0], xy[1], xy[0], xy[1]) - selector.SetFieldAssociation(vtk.vtkDataObject.FIELD_ASSOCIATION_CELLS) - # We want to be able see information behind continents - if (continentsRenderer): - continentsRenderer.SetDraw(False) - selection = selector.Select() - if (continentsRenderer): - continentsRenderer.SetDraw(True) - if (selection.GetNumberOfNodes() > 0): - selectionNode = selection.GetNode(0) - prop = selectionNode.GetProperties().Get(selectionNode.PROP()) - if (prop): - cellIds = prop.GetMapper().GetInput().GetCellData().GetGlobalIds() - if (cellIds): - # scalar value - a = selectionNode.GetSelectionData().GetArray(0) - geometryId = a.GetValue(0) - cellId = cellIds.GetValue(geometryId) - scalars = dataset.GetCellData().GetScalars() - value = scalars.GetValue(cellId) - geoTransform = d.backend['vtk_backend_geo'] - if (geoTransform): - geoTransform.Inverse() - # Use the world picker to get world coordinates - # we deform the dataset, so we need to fix the - # world picker using xScale, yScale - xScale, yScale = d.backend['dataset_scale'] - worldPicker = vtk.vtkWorldPointPicker() - worldPicker.Pick(xy[0], xy[1], 0, datasetRenderer) - worldPosition = list(worldPicker.GetPickPosition()) - if (xScale > yScale): - worldPosition[0] /= (xScale/yScale) - else: - worldPosition[1] /= (yScale/xScale) - lonLat = worldPosition - if (geoTransform): - geoTransform.InternalTransformPoint(worldPosition, lonLat) - geoTransform.Inverse() - st += "Var: %s\n" % d.array[0].id - if (float("inf") not in lonLat): - st += "X=%4.1f\nY=%4.1f\n" % (lonLat[0], lonLat[1]) - st += "Value: %g" % value - else: - if t.data.x1 <= x <= t.data.x2 and t.data.y1 <= y <= t.data.y2: - x1, x2, y1, y2 = vcs.utils.getworldcoordinates(gm, - d.array[0].getAxis(-1), - d.array[0].getAxis(-2)) - - X = (x - t.data.x1) / (t.data.x2 - t.data.x1) * (x2 - x1) + x1 - Y = (y - t.data.y1) / (t.data.y2 - t.data.y1) * (y2 - y1) + y1 - - # Ok we now have the X/Y values we need to figure out the - # indices - try: - I = d.array[0].getAxis(-1).mapInterval((X, X, 'cob'))[0] - try: - J = d.array[ - 0].getAxis(-2).mapInterval((Y, Y, 'cob'))[0] - # Values at that point - V = d.array[0][..., J, I] - except: - V = d.array[0][..., I] - if isinstance(V, numpy.ndarray): - # Grab the appropriate time slice - if self.canvas.animate.created(): - t = self.canvas.animate.frame_num - try: - taxis = V.getTime() - V = V(time=taxis[t % len(taxis)]).flat[0] - except: - V = V.flat[0] + # Use the hardware selector to determine the cell id we clicked on + selector = vtk.vtkHardwareSelector() + surfaceRenderer = d.backend['surface_renderer'] + dataset = d.backend['vtk_backend_grid'] + if (surfaceRenderer and dataset): + selector.SetRenderer(surfaceRenderer) + selector.SetArea(xy[0], xy[1], xy[0], xy[1]) + selector.SetFieldAssociation(vtk.vtkDataObject.FIELD_ASSOCIATION_CELLS) + # We only want to render the surface for selection + renderers = self.renWin.GetRenderers() + renderers.InitTraversal() + while(True): + renderer = renderers.GetNextItem() + if (renderer is None): + break + renderer.SetDraw(False) + surfaceRenderer.SetDraw(True) + selection = selector.Select() + renderers.InitTraversal() + while(True): + renderer = renderers.GetNextItem() + if (renderer is None): + break + renderer.SetDraw(True) + surfaceRenderer.SetDraw(False) + if (selection.GetNumberOfNodes() > 0): + selectionNode = selection.GetNode(0) + prop = selectionNode.GetProperties().Get(selectionNode.PROP()) + if (prop): + cellIds = prop.GetMapper().GetInput().GetCellData().GetGlobalIds() + if (cellIds): + st += "Var: %s\n" % d.array[0].id + # cell attribute + a = selectionNode.GetSelectionData().GetArray(0) + geometryId = a.GetValue(0) + cellId = cellIds.GetValue(geometryId) + attributes = dataset.GetCellData().GetScalars() + if (attributes is None): + attributes = dataset.GetCellData().GetVectors() + elementId = cellId + + geoTransform = d.backend['vtk_backend_geo'] + if (geoTransform): + geoTransform.Inverse() + # Use the world picker to get world coordinates + # we deform the dataset, so we need to fix the + # world picker using xScale, yScale + xScale, yScale = d.backend['surface_scale'] + worldPicker = vtk.vtkWorldPointPicker() + worldPicker.Pick(xy[0], xy[1], 0, surfaceRenderer) + worldPosition = list(worldPicker.GetPickPosition()) + if (xScale > yScale): + worldPosition[0] /= (xScale/yScale) else: - V = V.flat[0] - try: - st += "Var: %s\nX[%i] = %4.1f\nY[%i] = %4.1f\nValue: %g" % ( - d.array[0].id, I, X, J, Y, V) - except: - st += "Var: %s\nX = %4.1f\nY[%i] = %4.1f\nValue: %g" % ( - d.array[0].id, X, I, Y, V) - except: - st += "Var: %s\nX=%g\nY=%g\nValue = N/A" % ( - d.array[0].id, X, Y) + worldPosition[1] /= (yScale/xScale) + lonLat = worldPosition + if (attributes is None): + # if point dataset, return the value for the closest point + cell = dataset.GetCell(cellId) + closestPoint = [0, 0, 0] + subId = vtk.mutable(0) + pcoords = [0, 0, 0] + dist2 = vtk.mutable(0) + weights = [0] * cell.GetNumberOfPoints() + cell.EvaluatePosition(worldPosition, closestPoint, + subId, pcoords, dist2, weights) + indexMax = numpy.argmax(weights) + pointId = cell.GetPointId(indexMax) + attributes = dataset.GetPointData().GetScalars() + if (attributes is None): + attributes = dataset.GetPointData().GetVectors() + elementId = pointId + if (geoTransform): + geoTransform.InternalTransformPoint(worldPosition, lonLat) + geoTransform.Inverse() + if (float("inf") not in lonLat): + st += "X=%4.1f\nY=%4.1f\n" % (lonLat[0], lonLat[1]) + # get the cell value or the closest point value + if (attributes): + if (attributes.GetNumberOfComponents() > 1): + v = attributes.GetTuple(elementId) + st += "Value: (%g, %g)" % (v[0], v[1]) + else: + value = attributes.GetValue(elementId) + st += "Value: %g" % value + if st == "": return ren = vtk.vtkRenderer() @@ -859,9 +850,9 @@ def renderTemplate(self, tmpl, data, gm, taxis, zaxis, **kargs): ren = self.createRenderer() self.renWin.AddRenderer(ren) self.setLayer(ren, 1) - self._renderers[(None, None, None)] = ren + self._renderers[(None, None, None)] = (ren, 1, 1) else: - ren = self._renderers[(None, None, None)] + ren, xratio, yratio = self._renderers[(None, None, None)] tt, to = crdate.name.split(":::") tt = vcs.elements["texttable"][tt] to = vcs.elements["textorientation"][to] @@ -896,9 +887,9 @@ def renderTemplate(self, tmpl, data, gm, taxis, zaxis, **kargs): ren = self.createRenderer() self.renWin.AddRenderer(ren) self.setLayer(ren, 1) - self._renderers[(None, None, None)] = ren + self._renderers[(None, None, None)] = (ren, 1, 1) else: - ren = self._renderers[(None, None, None)] + ren, xratio, yratio = self._renderers[(None, None, None)] tt, to = zname.name.split(":::") tt = vcs.elements["texttable"][tt] to = vcs.elements["textorientation"][to] diff --git a/Packages/vcs/vcs/vcs2vtk.py b/Packages/vcs/vcs/vcs2vtk.py index 86cfcfd0ab..aa4a228ac4 100644 --- a/Packages/vcs/vcs/vcs2vtk.py +++ b/Packages/vcs/vcs/vcs2vtk.py @@ -809,6 +809,7 @@ def doWrap(Act, wc, wrap=[0., 360], fastClip=True): if wrap is None: return Act Mapper = Act.GetMapper() + Mapper.Update() data = Mapper.GetInput() # insure that GLOBALIDS are not removed by the append filter attributes = data.GetCellData() diff --git a/Packages/vcs/vcs/vcsvtk/boxfillpipeline.py b/Packages/vcs/vcs/vcsvtk/boxfillpipeline.py index 1ea81febbb..f2a3ea6020 100644 --- a/Packages/vcs/vcs/vcsvtk/boxfillpipeline.py +++ b/Packages/vcs/vcs/vcsvtk/boxfillpipeline.py @@ -130,8 +130,6 @@ def _plotInternal(self): geo=self._vtkGeoTransform, priority=self._template.data.priority, create_renderer=(dataset_renderer is None)) - self._resultDict['dataset_renderer'] = dataset_renderer - self._resultDict['dataset_scale'] = (xScale, yScale) for act in patternActors: if self._vtkGeoTransform is None: @@ -211,7 +209,6 @@ def _plotInternal(self): vp, self._template.data.priority, vtk_backend_grid=self._vtkDataSet, dataset_bounds=self._vtkDataSetBounds) - self._resultDict['continents_renderer'] = continents_renderer def _plotInternalBoxfill(self): """Implements the logic to render a non-custom boxfill.""" diff --git a/Packages/vcs/vcs/vcsvtk/isofillpipeline.py b/Packages/vcs/vcs/vcsvtk/isofillpipeline.py index af3b037a86..55098f9e5c 100644 --- a/Packages/vcs/vcs/vcsvtk/isofillpipeline.py +++ b/Packages/vcs/vcs/vcsvtk/isofillpipeline.py @@ -158,8 +158,6 @@ def _plotInternal(self): geo=self._vtkGeoTransform, priority=self._template.data.priority, create_renderer=(dataset_renderer is None)) - self._resultDict['dataset_renderer'] = dataset_renderer - self._resultDict['dataset_scale'] = (xScale, yScale) for act in patternActors: self._context().fitToViewport( act, vp, @@ -226,4 +224,3 @@ def _plotInternal(self): vp, self._template.data.priority, vtk_backend_grid=self._vtkDataSet, dataset_bounds=self._vtkDataSetBounds) - self._resultDict['continents_renderer'] = continents_renderer diff --git a/Packages/vcs/vcs/vcsvtk/isolinepipeline.py b/Packages/vcs/vcs/vcsvtk/isolinepipeline.py index 2d9b66472e..1560de7c15 100644 --- a/Packages/vcs/vcs/vcsvtk/isolinepipeline.py +++ b/Packages/vcs/vcs/vcsvtk/isolinepipeline.py @@ -273,8 +273,6 @@ def _plotInternal(self): create_renderer=(dataset_renderer is None)) countLevels += len(l) - self._resultDict['dataset_renderer'] = dataset_renderer - self._resultDict['dataset_scale'] = (xScale, yScale) if len(textprops) > 0: self._resultDict["vtk_backend_contours_labels_text_properties"] = \ textprops @@ -332,4 +330,3 @@ def _plotInternal(self): vp, self._template.data.priority, vtk_backend_grid=self._vtkDataSet, dataset_bounds=self._vtkDataSetBounds) - self._resultDict['continents_renderer'] = continents_renderer diff --git a/Packages/vcs/vcs/vcsvtk/meshfillpipeline.py b/Packages/vcs/vcs/vcsvtk/meshfillpipeline.py index 7101a4729f..64a95c4e31 100644 --- a/Packages/vcs/vcs/vcsvtk/meshfillpipeline.py +++ b/Packages/vcs/vcs/vcsvtk/meshfillpipeline.py @@ -195,8 +195,6 @@ def _plotInternal(self): geo=self._vtkGeoTransform, priority=self._template.data.priority, create_renderer=(dataset_renderer is None)) - self._resultDict['dataset_renderer'] = dataset_renderer - self._resultDict['dataset_scale'] = (xScale, yScale) for act in self._patternActors: if self._vtkGeoTransform is None: # If using geofilter on wireframed does not get wrapped not sure @@ -270,7 +268,6 @@ def _plotInternal(self): vp, self._template.data.priority, vtk_backend_grid=self._vtkDataSet, dataset_bounds=self._vtkDataSetBounds) - self._resultDict['continents_renderer'] = continents_renderer def getPlottingBounds(self): """gm.datawc if it is set or dataset_bounds diff --git a/Packages/vcs/vcs/vcsvtk/pipeline2d.py b/Packages/vcs/vcs/vcsvtk/pipeline2d.py index baa2f89154..dc12f3f5cd 100644 --- a/Packages/vcs/vcs/vcsvtk/pipeline2d.py +++ b/Packages/vcs/vcs/vcsvtk/pipeline2d.py @@ -50,6 +50,7 @@ class IPipeline2D(Pipeline): applied to points. - _needsCellData: True if the plot needs cell scalars, false if the plot needs point scalars + - _needsVectors: True if the plot needs vectors, false if it needs scalars - _scalarRange: The range of _data1 as tuple(float min, float max) - _maskedDataMapper: The mapper used to render masked data. """ @@ -79,6 +80,7 @@ def __init__(self, gm, context_): self._dataWrapModulo = None self._hasCellData = None self._needsCellData = None + self._needsVectors = False self._scalarRange = None self._maskedDataMapper = None @@ -276,6 +278,8 @@ def plot(self, data1, data2, tmpl, grid, transform, **kargs): # Preprocess the input scalar data: self._updateScalarData() + self._min = self._data1.min() + self._max = self._data1.max() self._scalarRange = vcs.minmax(self._data1) # Create/update the VTK dataset. @@ -313,8 +317,6 @@ def _updateScalarData(self): """Overrides baseclass implementation.""" self._data1 = self._context().trimData2D(self._originalData1) self._data2 = self._context().trimData2D(self._originalData2) - self._min = self._data1.min() - self._max = self._data1.max() def _updateVTKDataSet(self, plotBasedDualGrid): """ @@ -327,8 +329,10 @@ def _updateVTKDataSet(self, plotBasedDualGrid): genGridDict = vcs2vtk.genGrid(self._data1, self._data2, self._gm, deep=False, grid=self._vtkDataSet, - geo=self._vtkGeoTransform, dualGrid=dualGrid) + geo=self._vtkGeoTransform, genVectors=self._needsVectors, + dualGrid=dualGrid) self._data1 = genGridDict["data"] + self._data2 = genGridDict["data2"] self._updateFromGenGridDict(genGridDict) def _createPolyDataFilter(self): @@ -339,6 +343,7 @@ def _createPolyDataFilter(self): elif self._hasCellData: # use cells but needs points c2p = vtk.vtkCellDataToPointData() + c2p.PassCellDataOn() c2p.SetInputData(self._vtkDataSet) self._vtkPolyDataFilter.SetInputConnection(c2p.GetOutputPort()) else: @@ -349,6 +354,27 @@ def _createPolyDataFilter(self): self._vtkPolyDataFilter.SetInputConnection(p2c.GetOutputPort()) self._vtkPolyDataFilter.Update() self._resultDict["vtk_backend_filter"] = self._vtkPolyDataFilter + # create an actor and a renderer for the surface mesh. + # this is used for displaying point information using the hardware selection + mapper = vtk.vtkPolyDataMapper() + mapper.SetInputConnection(self._vtkPolyDataFilter.GetOutputPort()) + act = vtk.vtkActor() + act.SetMapper(mapper) + vp = self._resultDict.get( + 'ratio_autot_viewport', + [self._template.data.x1, self._template.data.x2, + self._template.data.y1, self._template.data.y2]) + plotting_dataset_bounds = self.getPlottingBounds() + surface_renderer, xScale, yScale = self._context().fitToViewport( + act, vp, + wc=plotting_dataset_bounds, geoBounds=self._vtkDataSet.GetBounds(), + geo=self._vtkGeoTransform, + priority=self._template.data.priority, + create_renderer=True) + self._resultDict['surface_renderer'] = surface_renderer + self._resultDict['surface_scale'] = (xScale, yScale) + if (surface_renderer): + surface_renderer.SetDraw(False) def _updateFromGenGridDict(self, genGridDict): """Overrides baseclass implementation.""" diff --git a/Packages/vcs/vcs/vcsvtk/vectorpipeline.py b/Packages/vcs/vcs/vcsvtk/vectorpipeline.py index bc34e3c9ea..0badc60b48 100644 --- a/Packages/vcs/vcs/vcsvtk/vectorpipeline.py +++ b/Packages/vcs/vcs/vcsvtk/vectorpipeline.py @@ -1,75 +1,47 @@ -from .pipeline import Pipeline +from .pipeline2d import Pipeline2D import vcs from vcs import vcs2vtk import vtk -class VectorPipeline(Pipeline): +class VectorPipeline(Pipeline2D): """Implementation of the Pipeline interface for VCS vector plots.""" def __init__(self, gm, context_): super(VectorPipeline, self).__init__(gm, context_) + self._needsCellData = False + self._needsVectors = True - def plot(self, data1, data2, tmpl, grid, transform, **kargs): + def _plotInternal(self): """Overrides baseclass implementation.""" # Preserve time and z axis for plotting these inof in rendertemplate - geo = None # to make flake8 happy projection = vcs.elements["projection"][self._gm.projection] - returned = {} - taxis = data1.getTime() - if data1.ndim > 2: - zaxis = data1.getAxis(-3) + taxis = self._originalData1.getTime() + if self._originalData1.ndim > 2: + zaxis = self._originalData1.getAxis(-3) else: zaxis = None - # Ok get3 only the last 2 dims - data1 = self._context().trimData2D(data1) - data2 = self._context().trimData2D(data2) - scale = 1.0 lat = None lon = None - latAccessor = data1.getLatitude() - lonAccessor = data1.getLongitude() + latAccessor = self._data1.getLatitude() + lonAccessor = self._data1.getLongitude() if latAccessor: lat = latAccessor[:] if lonAccessor: lon = lonAccessor[:] - plotBasedDualGrid = kargs.get('plot_based_dual_grid', True) - if (plotBasedDualGrid): - hasCellData = data1.hasCellData() - dualGrid = hasCellData - else: - dualGrid = False - gridGenDict = vcs2vtk.genGrid(data1, data2, self._gm, deep=False, grid=grid, - geo=transform, genVectors=True, - dualGrid=dualGrid) - - data1 = gridGenDict["data"] - data2 = gridGenDict["data2"] - geo = gridGenDict["geo"] - - grid = gridGenDict['vtk_backend_grid'] - xm = gridGenDict['xm'] - xM = gridGenDict['xM'] - ym = gridGenDict['ym'] - yM = gridGenDict['yM'] - continents = gridGenDict['continents'] - self._dataWrapModulo = gridGenDict['wrap'] - geo = gridGenDict['geo'] - cellData = gridGenDict['cellData'] - - if geo is not None: + if self._vtkGeoTransform is not None: newv = vtk.vtkDoubleArray() newv.SetNumberOfComponents(3) newv.InsertTupleValue(0, [lon.min(), lat.min(), 0]) newv.InsertTupleValue(1, [lon.max(), lat.max(), 0]) - vcs2vtk.projectArray(newv, projection, [xm, xM, ym, yM]) + vcs2vtk.projectArray(newv, projection, self._vtkDataSetBounds) dimMin = [0, 0, 0] dimMax = [0, 0, 0] @@ -89,22 +61,6 @@ def plot(self, data1, data2, tmpl, grid, transform, **kargs): else: scale = 1.0 - returned["vtk_backend_grid"] = grid - returned["vtk_backend_geo"] = geo - missingMapper = vcs2vtk.putMaskOnVTKGrid(data1, grid, actorColor=None, - cellData=cellData, deep=False) - - # None/False are for color and cellData - # (sent to vcs2vtk.putMaskOnVTKGrid) - returned["vtk_backend_missing_mapper"] = (missingMapper, None, False) - - # convert to point data - if cellData: - c2p = vtk.vtkCellDataToPointData() - c2p.SetInputData(grid) - c2p.Update() - grid = c2p.GetOutput() - # Vector attempt l = self._gm.line if l is None: @@ -129,7 +85,7 @@ def plot(self, data1, data2, tmpl, grid, transform, **kargs): arrow.FilledOff() glyphFilter = vtk.vtkGlyph2D() - glyphFilter.SetInputData(grid) + glyphFilter.SetInputConnection(self._vtkPolyDataFilter.GetOutputPort()) glyphFilter.SetInputArrayToProcess(1, 0, 0, 0, "vector") glyphFilter.SetSourceConnection(arrow.GetOutputPort()) glyphFilter.SetVectorModeToUseVector() @@ -163,22 +119,20 @@ def plot(self, data1, data2, tmpl, grid, transform, **kargs): plotting_dataset_bounds = vcs2vtk.getPlottingBounds( vcs.utils.getworldcoordinates(self._gm, - data1.getAxis(-1), - data1.getAxis(-2)), - [xm, xM, ym, yM], geo) + self._data1.getAxis(-1), + self._data1.getAxis(-2)), + self._vtkDataSetBounds, self._vtkGeoTransform) x1, x2, y1, y2 = plotting_dataset_bounds - if geo is None: + if self._vtkGeoTransform is None: wc = plotting_dataset_bounds else: xrange = list(act.GetXRange()) yrange = list(act.GetYRange()) wc = [xrange[0], xrange[1], yrange[0], yrange[1]] - if (transform and kargs.get('ratio', '0') == 'autot'): - returned['ratio_autot_viewport'] = self._processRatioAutot(tmpl, grid) - - vp = returned.get('ratio_autot_viewport', - [tmpl.data.x1, tmpl.data.x2, tmpl.data.y1, tmpl.data.y2]) + vp = self._resultDict.get('ratio_autot_viewport', + [self._template.data.x1, self._template.data.x2, + self._template.data.y1, self._template.data.y2]) # look for previous dataset_bounds different than ours and # modify the viewport so that the datasets are alligned # Hack to fix the case when the user does not specify gm.datawc_... @@ -200,31 +154,29 @@ def plot(self, data1, data2, tmpl, grid, transform, **kargs): dataset_renderer, xScale, yScale = self._context().fitToViewport( act, vp, wc=wc, - priority=tmpl.data.priority, + priority=self._template.data.priority, create_renderer=True) - returned['dataset_renderer'] = dataset_renderer - returned['dataset_scale'] = (xScale, yScale) - bounds = [min(xm, xM), max(xm, xM), min(ym, yM), max(ym, yM)] - kwargs = {'vtk_backend_grid': grid, - 'dataset_bounds': bounds, + kwargs = {'vtk_backend_grid': self._vtkDataSet, + 'dataset_bounds': self._vtkDataSetBounds, 'plotting_dataset_bounds': plotting_dataset_bounds} - if ('ratio_autot_viewport' in returned): + if ('ratio_autot_viewport' in self._resultDict): kwargs["ratio_autot_viewport"] = vp - returned.update(self._context().renderTemplate( - tmpl, data1, + self._resultDict.update(self._context().renderTemplate( + self._template, self._data1, self._gm, taxis, zaxis, **kwargs)) if self._context().canvas._continents is None: - continents = False - if continents: + self._useContinents = False + if self._useContinents: continents_renderer, xScale, yScale = self._context().plotContinents( plotting_dataset_bounds, projection, - self._dataWrapModulo, vp, tmpl.data.priority, - vtk_backend_grid=grid, - dataset_bounds=bounds) - returned["continents_renderer"] = continents_renderer - returned["vtk_backend_actors"] = [[act, plotting_dataset_bounds]] - returned["vtk_backend_glyphfilters"] = [glyphFilter] - returned["vtk_backend_luts"] = [[None, None]] - - return returned + self._dataWrapModulo, vp, self._template.data.priority, + vtk_backend_grid=self._vtkDataSet, + dataset_bounds=self._vtkDataSetBounds) + self._resultDict["vtk_backend_actors"] = [[act, plotting_dataset_bounds]] + self._resultDict["vtk_backend_glyphfilters"] = [glyphFilter] + self._resultDict["vtk_backend_luts"] = [[None, None]] + + def _updateContourLevelsAndColors(self): + """Overrides baseclass implementation.""" + pass diff --git a/testing/vcs/CMakeLists.txt b/testing/vcs/CMakeLists.txt index 9e8cf78e30..fd253ac230 100644 --- a/testing/vcs/CMakeLists.txt +++ b/testing/vcs/CMakeLists.txt @@ -947,33 +947,22 @@ cdat_add_test(test_vcs_colorpicker_appearance ${BASELINE_DIR}/test_vcs_colorpicker_appearance.png ) -cdat_add_test(test_vcs_click_info - "${PYTHON_EXECUTABLE}" - ${cdat_SOURCE_DIR}/testing/vcs/test_vcs_click_info.py - ${BASELINE_DIR}/test_vcs_click_info.png - a_boxfill -) - -cdat_add_test(test_vcs_click_info_mollweide_boxfill - "${PYTHON_EXECUTABLE}" - ${cdat_SOURCE_DIR}/testing/vcs/test_vcs_click_info.py - ${BASELINE_DIR}/test_vcs_click_info_mollweide_boxfill.png - a_mollweide_boxfill -) - -cdat_add_test(test_vcs_click_info_meshfill - "${PYTHON_EXECUTABLE}" - ${cdat_SOURCE_DIR}/testing/vcs/test_vcs_click_info.py - ${BASELINE_DIR}/test_vcs_click_info_meshfill.png - a_meshfill -) -cdat_add_test(test_vcs_click_info_robinson_meshfill - "${PYTHON_EXECUTABLE}" - ${cdat_SOURCE_DIR}/testing/vcs/test_vcs_click_info.py - ${BASELINE_DIR}/test_vcs_click_info_robinson_meshfill.png - a_robinson_meshfill -) +foreach(plot a_boxfill a_mollweide_boxfill a_meshfill a_robinson_meshfill + a_isofill a_isoline vector_default) + string(SUBSTRING ${plot} 0 2 plot_prefix) + if (${plot_prefix} STREQUAL "a_") + string(SUBSTRING ${plot} 2 -1 plot_name) + else () + string(REGEX MATCH "[^_]+" plot_name ${plot}) + endif () + cdat_add_test(test_vcs_click_info_${plot_name} + "${PYTHON_EXECUTABLE}" + ${cdat_SOURCE_DIR}/testing/vcs/test_vcs_click_info.py + "${BASELINE_DIR}/test_vcs_click_info_${plot_name}.png" + ${plot} + ) +endforeach() cdat_add_test(test_vcs_mercator_edge diff --git a/testing/vcs/test_vcs_click_info.py b/testing/vcs/test_vcs_click_info.py index f37ee651a7..8d55e77c65 100644 --- a/testing/vcs/test_vcs_click_info.py +++ b/testing/vcs/test_vcs_click_info.py @@ -2,6 +2,9 @@ testConfig = {'a_boxfill': ('clt.nc', 'clt', (200, 200)), 'a_mollweide_boxfill': ('clt.nc', 'clt', (222, 322)), + 'a_isofill': ('clt.nc', 'clt', (200, 200)), + 'a_isoline': ('clt.nc', 'clt', (200, 200)), + 'vector_default': ('clt.nc', ('u', 'v'), (200, 200)), 'a_meshfill': ('sampleCurveGrid4.nc', 'sample', (222, 322)), 'a_robinson_meshfill': ('sampleCurveGrid4.nc', 'sample', (222, 322))} @@ -10,21 +13,32 @@ plot = sys.argv[2] x = regression.init(bg=False, geometry=(800, 600)) -# data -f = cdms2.open(vcs.sample_data + "/" + testConfig[plot][0]) -s = f(testConfig[plot][1]) - +vector = False # graphics method if (plot.find('boxfill') != -1): gm = x.getboxfill(plot) elif (plot.find('meshfill') != -1): gm = x.getmeshfill(plot) +elif (plot.find('isofill') != -1): + gm = x.getisofill(plot) +elif (plot.find('isoline') != -1): + gm = x.getisoline(plot) +elif (plot.find('vector') != -1): + gm = x.getvector(plot[plot.index('_') + 1:]) + vector = True else: print "Invalid plot" sys.exit(13) -# Has to plot in foreground to simulate a click -x.plot(s, gm) +# data +f = cdms2.open(vcs.sample_data + "/" + testConfig[plot][0]) +if (vector): + u = f(testConfig[plot][1][0]) + v = f(testConfig[plot][1][1]) + x.plot(u, v, gm) +else: + s = f(testConfig[plot][1]) + x.plot(s, gm) # Simulate a click -- VTK Specific location = testConfig[plot][2]