def in_display_plot(self, point, dp): #Normalize the point x, y = point w, h = self.interactor.GetRenderWindow().GetSize() if x > 1 or y > 1: point = (x / float(w), y / float(h)) x, y = point if dp.g_type == "fillarea": fill = vcs.getfillarea(dp.g_name) info = editors.fillarea.inside_fillarea(fill, *point) if info is not None: self.clicked_info = info return fill elif dp.g_type == "line": l = vcs.getline(dp.g_name) # Uses screen_height to determine how much buffer space there is around the line info = editors.line.inside_line(l, *point, screen_height=h) if info is not None: self.clicked_info = info return l elif dp.g_type == "marker": m = vcs.getmarker(dp.g_name) info = editors.marker.inside_marker(m, point[0], point[1], w, h) if info is not None: self.clicked_info = info return m elif dp.g_type == "text": tc = vcs.gettextcombined(dp.g_name) info = editors.text.inside_text(tc, point[0], point[1], w, h) if info is not None: self.clicked_info = info return tc else: fudge = 5 / float(w) return in_template(point, t(dp.template), dp, (w, h), fudge=fudge)
def plot(self, data1, data2, tmpl, gm, grid, transform): """Overrides baseclass implementation.""" # Preserve time and z axis for plotting these inof in rendertemplate geo = None # to make flake8 happy returned = {} taxis = data1.getTime() if data1.ndim > 2: zaxis = data1.getAxis(-3) else: zaxis = None # Ok get3 only the last 2 dims data1 = self._context().trimData2D(data1) data2 = self._context().trimData2D(data2) gridGenDict = vcs2vtk.genGridOnPoints(data1, gm, deep=False, grid=grid, geo=transform) for k in ['vtk_backend_grid', 'xm', 'xM', 'ym', 'yM', 'continents', 'wrap', 'geo']: exec("%s = gridGenDict['%s']" % (k, k)) grid = gridGenDict['vtk_backend_grid'] self._dataWrapModulo = gridGenDict['wrap'] returned["vtk_backend_grid"] = grid returned["vtk_backend_geo"] = geo missingMapper = vcs2vtk.putMaskOnVTKGrid(data1, grid, None, False, deep=False) # None/False are for color and cellData # (sent to vcs2vtk.putMaskOnVTKGrid) returned["vtk_backend_missing_mapper"] = (missingMapper, None, False) w = vcs2vtk.generateVectorArray(data1, data2, grid) grid.GetPointData().AddArray(w) # Vector attempt l = gm.line if l is None: l = "default" try: l = vcs.getline(l) lwidth = l.width[0] # noqa lcolor = l.color[0] lstyle = l.type[0] # noqa except: lstyle = "solid" # noqa lwidth = 1. # noqa lcolor = 0 if gm.linewidth is not None: lwidth = gm.linewidth # noqa if gm.linecolor is not None: lcolor = gm.linecolor arrow = vtk.vtkGlyphSource2D() arrow.SetGlyphTypeToArrow() arrow.FilledOff() glyphFilter = vtk.vtkGlyph2D() glyphFilter.SetInputData(grid) glyphFilter.SetInputArrayToProcess(1, 0, 0, 0, "vectors") glyphFilter.SetSourceConnection(arrow.GetOutputPort()) glyphFilter.SetVectorModeToUseVector() # Rotate arrows to match vector data: glyphFilter.OrientOn() # Scale to vector magnitude: glyphFilter.SetScaleModeToScaleByVector() glyphFilter.SetScaleFactor(2. * gm.scale) # These are some unfortunately named methods. It does *not* clamp the # scale range to [min, max], but rather remaps the range # [min, max] --> [0, 1]. glyphFilter.ClampingOn() glyphFilter.SetRange(0.01, 1.0) mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(glyphFilter.GetOutputPort()) act = vtk.vtkActor() act.SetMapper(mapper) cmap = self._context().canvas.getcolormapname() cmap = vcs.elements["colormap"][cmap] r, g, b = cmap.index[lcolor] act.GetProperty().SetColor(r / 100., g / 100., b / 100.) x1, x2, y1, y2 = vcs.utils.getworldcoordinates(gm, data1.getAxis(-1), data1.getAxis(-2)) act = vcs2vtk.doWrap(act, [x1, x2, y1, y2], self._dataWrapModulo) self._context().fitToViewport(act, [tmpl.data.x1, tmpl.data.x2, tmpl.data.y1, tmpl.data.y2], [x1, x2, y1, y2], priority=tmpl.data.priority, create_renderer=True) returned.update( self._context().renderTemplate(tmpl, data1, gm, taxis, zaxis)) if self._context().canvas._continents is None: continents = False if continents: projection = vcs.elements["projection"][gm.projection] self._context().plotContinents(x1, x2, y1, y2, projection, self._dataWrapModulo, tmpl) returned["vtk_backend_actors"] = [[act, [x1, x2, y1, y2]]] returned["vtk_backend_glyphfilters"] = [glyphFilter] returned["vtk_backend_luts"] = [[None, None]] return returned
def _plotInternal(self): """Overrides baseclass implementation.""" # Preserve time and z axis for plotting these inof in rendertemplate projection = vcs.elements["projection"][self._gm.projection] taxis = self._originalData1.getTime() if self._originalData1.ndim > 2: zaxis = self._originalData1.getAxis(-3) else: zaxis = None # Streamline color if (not self._gm.coloredbyvector): ln_tmp = self._gm.linetype if ln_tmp is None: ln_tmp = "default" try: ln_tmp = vcs.getline(ln_tmp) lwidth = ln_tmp.width[0] # noqa lcolor = ln_tmp.color[0] lstyle = ln_tmp.type[0] # noqa except Exception: lstyle = "solid" # noqa lwidth = 1. # noqa lcolor = [0., 0., 0., 100.] if self._gm.linewidth is not None: lwidth = self._gm.linewidth # noqa if self._gm.linecolor is not None: lcolor = self._gm.linecolor self._vtkPolyDataFilter.Update() polydata = self._vtkPolyDataFilter.GetOutput() dataLength = polydata.GetLength() if (not self._gm.evenlyspaced): # generate random seeds in a circle centered in the center of # the bounding box for the data. # by default vtkPointSource uses a global random source in vtkMath which is # seeded only once. It makes more sense to seed a random sequence each time you draw # the streamline plot. pointSequence = vtk.vtkMinimalStandardRandomSequence() pointSequence.SetSeedOnly(1177) # replicate the seed from vtkMath seed = vtk.vtkPointSource() seed.SetNumberOfPoints(self._gm.numberofseeds) seed.SetCenter(polydata.GetCenter()) seed.SetRadius(dataLength / 2.0) seed.SetRandomSequence(pointSequence) seed.Update() seedData = seed.GetOutput() # project all points to Z = 0 plane points = seedData.GetPoints() for i in range(0, points.GetNumberOfPoints()): p = list(points.GetPoint(i)) p[2] = 0 points.SetPoint(i, p) if (self._gm.integratortype == 0): integrator = vtk.vtkRungeKutta2() elif (self._gm.integratortype == 1): integrator = vtk.vtkRungeKutta4() else: if (self._gm.evenlyspaced): warnings.warn( "You cannot use RungeKutta45 for evenly spaced streamlines." "Using RungeKutta4 instead") integrator = vtk.vtkRungeKutta4() else: integrator = vtk.vtkRungeKutta45() if (self._gm.evenlyspaced): streamer = vtk.vtkEvenlySpacedStreamlines2D() streamer.SetStartPosition(self._gm.startseed) streamer.SetSeparatingDistance(self._gm.separatingdistance) streamer.SetSeparatingDistanceRatio( self._gm.separatingdistanceratio) streamer.SetClosedLoopMaximumDistance( self._gm.closedloopmaximumdistance) else: # integrate streamlines on normalized vector so that # IntegrationTime stores distance streamer = vtk.vtkStreamTracer() streamer.SetSourceData(seedData) streamer.SetIntegrationDirection(self._gm.integrationdirection) streamer.SetMinimumIntegrationStep(self._gm.minimumsteplength) streamer.SetMaximumIntegrationStep(self._gm.maximumsteplength) streamer.SetMaximumError(self._gm.maximumerror) streamer.SetMaximumPropagation(dataLength * self._gm.maximumstreamlinelength) streamer.SetInputData(polydata) streamer.SetInputArrayToProcess(0, 0, 0, 0, "vector") streamer.SetIntegrationStepUnit(self._gm.integrationstepunit) streamer.SetInitialIntegrationStep(self._gm.initialsteplength) streamer.SetMaximumNumberOfSteps(self._gm.maximumsteps) streamer.SetTerminalSpeed(self._gm.terminalspeed) streamer.SetIntegrator(integrator) # add arc_length to streamlines arcLengthFilter = vtk.vtkAppendArcLength() arcLengthFilter.SetInputConnection(streamer.GetOutputPort()) arcLengthFilter.Update() streamlines = arcLengthFilter.GetOutput() # glyph seed points contour = vtk.vtkContourFilter() contour.SetInputConnection(arcLengthFilter.GetOutputPort()) contour.SetValue(0, 0.001) if (streamlines.GetNumberOfPoints()): r = streamlines.GetPointData().GetArray("arc_length").GetRange() numberofglyphsoneside = self._gm.numberofglyphs // 2 for i in range(1, numberofglyphsoneside): contour.SetValue(i, r[1] / numberofglyphsoneside * i) else: warnings.warn( "No streamlines created. " "The 'startseed' parameter needs to be inside the domain and " "not over masked data.") contour.SetInputArrayToProcess(0, 0, 0, 0, "arc_length") # arrow glyph source glyph2DSource = vtk.vtkGlyphSource2D() glyph2DSource.SetGlyphTypeToTriangle() glyph2DSource.SetRotationAngle(-90) glyph2DSource.SetFilled(self._gm.filledglyph) # arrow glyph adjustment transform = vtk.vtkTransform() transform.Scale(1., self._gm.glyphbasefactor, 1.) transformFilter = vtk.vtkTransformFilter() transformFilter.SetInputConnection(glyph2DSource.GetOutputPort()) transformFilter.SetTransform(transform) transformFilter.Update() glyphLength = transformFilter.GetOutput().GetLength() # drawing the glyphs at the seed points glyph = vtk.vtkGlyph2D() glyph.SetInputConnection(contour.GetOutputPort()) glyph.SetInputArrayToProcess(1, 0, 0, 0, "vector") glyph.SetSourceData(transformFilter.GetOutput()) glyph.SetScaleModeToDataScalingOff() glyph.SetScaleFactor(dataLength * self._gm.glyphscalefactor / glyphLength) glyph.SetColorModeToColorByVector() glyphMapper = vtk.vtkPolyDataMapper() glyphMapper.SetInputConnection(glyph.GetOutputPort()) glyphActor = vtk.vtkActor() glyphActor.SetMapper(glyphMapper) mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(streamer.GetOutputPort()) act = vtk.vtkActor() act.SetMapper(mapper) # color the streamlines and glyphs cmap = self.getColorMap() if (self._gm.coloredbyvector): numLevels = len(self._contourLevels) - 1 while len(self._contourColors) < numLevels: self._contourColors.append(self._contourColors[-1]) lut = vtk.vtkLookupTable() lut.SetNumberOfTableValues(numLevels) for i in range(numLevels): r, g, b, a = self.getColorIndexOrRGBA(cmap, self._contourColors[i]) lut.SetTableValue(i, r / 100., g / 100., b / 100., a / 100.) lut.SetVectorModeToMagnitude() if numpy.allclose(self._contourLevels[0], -1.e20): lmn = self._vectorRange[0] else: lmn = self._contourLevels[0][0] if numpy.allclose(self._contourLevels[-1], 1.e20): lmx = self._vectorRange[1] else: lmx = self._contourLevels[-1][-1] lut.SetRange(lmn, lmx) mapper.ScalarVisibilityOn() mapper.SetLookupTable(lut) mapper.UseLookupTableScalarRangeOn() mapper.SetScalarModeToUsePointFieldData() mapper.SelectColorArray("vector") glyphMapper.ScalarVisibilityOn() glyphMapper.SetLookupTable(lut) glyphMapper.UseLookupTableScalarRangeOn() glyphMapper.SetScalarModeToUsePointFieldData() glyphMapper.SelectColorArray("VectorMagnitude") else: mapper.ScalarVisibilityOff() glyphMapper.ScalarVisibilityOff() if isinstance(lcolor, (list, tuple)): r, g, b, a = lcolor else: r, g, b, a = cmap.index[lcolor] act.GetProperty().SetColor(r / 100., g / 100., b / 100.) glyphActor.GetProperty().SetColor(r / 100., g / 100., b / 100.) plotting_dataset_bounds = self.getPlottingBounds() vp = self._resultDict.get('ratio_autot_viewport', [ self._template.data.x1, self._template.data.x2, self._template.data.y1, self._template.data.y2 ]) dataset_renderer, xScale, yScale = self._context().fitToViewport( act, vp, wc=plotting_dataset_bounds, geoBounds=self._vtkDataSetBoundsNoMask, geo=self._vtkGeoTransform, priority=self._template.data.priority, create_renderer=True) glyph_renderer, xScale, yScale = self._context().fitToViewport( glyphActor, vp, wc=plotting_dataset_bounds, geoBounds=self._vtkDataSetBoundsNoMask, geo=self._vtkGeoTransform, priority=self._template.data.priority, create_renderer=False) kwargs = { 'vtk_backend_grid': self._vtkDataSet, 'dataset_bounds': self._vtkDataSetBounds, 'plotting_dataset_bounds': plotting_dataset_bounds, "vtk_dataset_bounds_no_mask": self._vtkDataSetBoundsNoMask, 'vtk_backend_geo': self._vtkGeoTransform } if ('ratio_autot_viewport' in self._resultDict): kwargs["ratio_autot_viewport"] = vp self._resultDict.update(self._context().renderTemplate( self._template, self._data1, self._gm, taxis, zaxis, **kwargs)) if (self._gm.coloredbyvector): self._resultDict.update(self._context().renderColorBar( self._template, self._contourLevels, self._contourColors, None, self.getColorMap())) if self._context().canvas._continents is None: self._useContinents = False if self._useContinents: continents_renderer, xScale, yScale = self._context( ).plotContinents(plotting_dataset_bounds, projection, self._dataWrapModulo, vp, self._template.data.priority, **kwargs) self._resultDict["vtk_backend_actors"] = [[ act, plotting_dataset_bounds ]] self._resultDict["vtk_backend_luts"] = [[None, None]]
def plot(self, data1, data2, tmpl, grid, transform): """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) 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() lonAccesrsor = data1.getLongitude() if latAccessor: lat = latAccessor[:] if lonAccesrsor: lon = lonAccesrsor[:] gridGenDict = vcs2vtk.genGridOnPoints(data1, self._gm, deep=False, grid=grid, geo=transform, data2=data2) data1 = gridGenDict["data"] data2 = gridGenDict["data2"] geo = gridGenDict["geo"] for k in ['vtk_backend_grid', 'xm', 'xM', 'ym', 'yM', 'continents', 'wrap', 'geo']: exec("%s = gridGenDict['%s']" % (k, k)) grid = gridGenDict['vtk_backend_grid'] self._dataWrapModulo = gridGenDict['wrap'] if geo 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, [gridGenDict['xm'], gridGenDict['xM'], gridGenDict['ym'], gridGenDict['yM']]) dimMin = [0, 0, 0] dimMax = [0, 0, 0] newv.GetTupleValue(0, dimMin) newv.GetTupleValue(1, dimMax) maxDimX = max(dimMin[0], dimMax[0]) maxDimY = max(dimMin[1], dimMax[1]) if lat.max() != 0.0: scale = abs((maxDimY / lat.max())) if lon.max() != 0.0: temp = abs((maxDimX / lon.max())) if scale < temp: scale = temp else: scale = 1.0 returned["vtk_backend_grid"] = grid returned["vtk_backend_geo"] = geo missingMapper = vcs2vtk.putMaskOnVTKGrid(data1, grid, None, False, deep=False) # None/False are for color and cellData # (sent to vcs2vtk.putMaskOnVTKGrid) returned["vtk_backend_missing_mapper"] = (missingMapper, None, False) w = vcs2vtk.generateVectorArray(data1, data2, grid) grid.GetPointData().AddArray(w) # Vector attempt l = self._gm.line if l is None: l = "default" try: l = vcs.getline(l) lwidth = l.width[0] # noqa lcolor = l.color[0] lstyle = l.type[0] # noqa except: lstyle = "solid" # noqa lwidth = 1. # noqa lcolor = 0 if self._gm.linewidth is not None: lwidth = self._gm.linewidth # noqa if self._gm.linecolor is not None: lcolor = self._gm.linecolor arrow = vtk.vtkGlyphSource2D() arrow.SetGlyphTypeToArrow() arrow.SetOutputPointsPrecision(vtk.vtkAlgorithm.DOUBLE_PRECISION) arrow.FilledOff() glyphFilter = vtk.vtkGlyph2D() glyphFilter.SetInputData(grid) glyphFilter.SetInputArrayToProcess(1, 0, 0, 0, "vectors") glyphFilter.SetSourceConnection(arrow.GetOutputPort()) glyphFilter.SetVectorModeToUseVector() # Rotate arrows to match vector data: glyphFilter.OrientOn() # Scale to vector magnitude: glyphFilter.SetScaleModeToScaleByVector() glyphFilter.SetScaleFactor(scale * 2.0 * self._gm.scale) # These are some unfortunately named methods. It does *not* clamp the # scale range to [min, max], but rather remaps the range # [min, max] --> [0, 1]. glyphFilter.ClampingOn() glyphFilter.SetRange(0.01, 1.0) mapper = vtk.vtkPolyDataMapper() glyphFilter.Update() data = glyphFilter.GetOutput() mapper.SetInputData(data) act = vtk.vtkActor() act.SetMapper(mapper) cmap = self.getColorMap() r, g, b, a = cmap.index[lcolor] act.GetProperty().SetColor(r / 100., g / 100., b / 100.) x1, x2, y1, y2 = vcs.utils.getworldcoordinates(self._gm, data1.getAxis(-1), data1.getAxis(-2)) if geo is None: wc = [x1, x2, y1, y2] else: xrange = list(act.GetXRange()) yrange = list(act.GetYRange()) wc = [xrange[0], xrange[1], yrange[0], yrange[1]] act = vcs2vtk.doWrap(act, wc, self._dataWrapModulo) self._context().fitToViewport(act, [tmpl.data.x1, tmpl.data.x2, tmpl.data.y1, tmpl.data.y2], wc=wc, priority=tmpl.data.priority, create_renderer=True) returned.update(self._context().renderTemplate(tmpl, data1, self._gm, taxis, zaxis)) if self._context().canvas._continents is None: continents = False if continents: self._context().plotContinents(x1, x2, y1, y2, projection, self._dataWrapModulo, tmpl) returned["vtk_backend_actors"] = [[act, [x1, x2, y1, y2]]] returned["vtk_backend_glyphfilters"] = [glyphFilter] returned["vtk_backend_luts"] = [[None, None]] return returned
def _plotInternal(self): """Overrides baseclass implementation.""" # Preserve time and z axis for plotting these inof in rendertemplate projection = vcs.elements["projection"][self._gm.projection] taxis = self._originalData1.getTime() scaleFactor = 1.0 if self._originalData1.ndim > 2: zaxis = self._originalData1.getAxis(-3) else: zaxis = None scale = 1.0 lat = None lon = None latAccessor = self._data1.getLatitude() lonAccessor = self._data1.getLongitude() if latAccessor: lat = latAccessor[:] if lonAccessor: lon = lonAccessor[:] if self._vtkGeoTransform is not None: newv = vtk.vtkDoubleArray() newv.SetNumberOfComponents(3) newv.InsertTypedTuple(0, [lon.min(), lat.min(), 0]) newv.InsertTypedTuple(1, [lon.max(), lat.max(), 0]) vcs2vtk.projectArray(newv, projection, self._vtkDataSetBounds) dimMin = [0, 0, 0] dimMax = [0, 0, 0] newv.GetTypedTuple(0, dimMin) newv.GetTypedTuple(1, dimMax) maxDimX = max(dimMin[0], dimMax[0]) maxDimY = max(dimMin[1], dimMax[1]) if lat.max() != 0.0: scale = abs((maxDimY / lat.max())) if lon.max() != 0.0: temp = abs((maxDimX / lon.max())) if scale < temp: scale = temp else: scale = 1.0 # Vector attempt l = self._gm.line if l is None: l = "default" try: l = vcs.getline(l) lwidth = l.width[0] # noqa lcolor = l.color[0] lstyle = l.type[0] # noqa except: lstyle = "solid" # noqa lwidth = 1. # noqa lcolor = 0 if self._gm.linewidth is not None: lwidth = self._gm.linewidth # noqa if self._gm.linecolor is not None: lcolor = self._gm.linecolor arrow = vtk.vtkGlyphSource2D() arrow.SetGlyphTypeToArrow() arrow.SetOutputPointsPrecision(vtk.vtkAlgorithm.DOUBLE_PRECISION) arrow.FilledOff() polydata = self._vtkPolyDataFilter.GetOutput() vectors = polydata.GetPointData().GetVectors() if self._gm.scaletype == 'constant' or\ self._gm.scaletype == 'constantNNormalize' or\ self._gm.scaletype == 'constantNLinear': scaleFactor = scale * 2.0 * self._gm.scale else: scaleFactor = 1.0 glyphFilter = vtk.vtkGlyph2D() glyphFilter.SetInputData(polydata) glyphFilter.SetInputArrayToProcess(1, 0, 0, 0, "vector") glyphFilter.SetSourceConnection(arrow.GetOutputPort()) glyphFilter.SetVectorModeToUseVector() # Rotate arrows to match vector data: glyphFilter.OrientOn() glyphFilter.ScalingOn() glyphFilter.SetScaleModeToScaleByVector() if self._gm.scaletype == 'normalize' or self._gm.scaletype == 'linear' or\ self._gm.scaletype == 'constantNNormalize' or self._gm.scaletype == 'constantNLinear': # Find the min and max vector magnitudes maxNorm = vectors.GetMaxNorm() if maxNorm == 0: maxNorm = 1.0 if self._gm.scaletype == 'normalize' or self._gm.scaletype == 'constantNNormalize': scaleFactor /= maxNorm if self._gm.scaletype == 'linear' or self._gm.scaletype == 'constantNLinear': minNorm = None maxNorm = None noOfComponents = vectors.GetNumberOfComponents() for i in range(0, vectors.GetNumberOfTuples()): norm = vtk.vtkMath.Norm(vectors.GetTuple(i), noOfComponents) if (minNorm is None or norm < minNorm): minNorm = norm if (maxNorm is None or norm > maxNorm): maxNorm = norm if maxNorm == 0: maxNorm = 1.0 scalarArray = vtk.vtkDoubleArray() scalarArray.SetNumberOfComponents(1) scalarArray.SetNumberOfValues(vectors.GetNumberOfTuples()) oldRange = maxNorm - minNorm oldRange = 1.0 if oldRange == 0.0 else oldRange # New range min, max. newRangeValues = self._gm.scalerange newRange = newRangeValues[1] - newRangeValues[0] for i in range(0, vectors.GetNumberOfTuples()): norm = vtk.vtkMath.Norm(vectors.GetTuple(i), noOfComponents) newValue = (((norm - minNorm) * newRange) / oldRange) + newRangeValues[0] scalarArray.SetValue(i, newValue) polydata.GetPointData().SetScalars(scalarArray) # Scale to vector magnitude: # NOTE: Currently we compute our own scaling factor since VTK does # it by clamping the values > max to max and values < min to min # and not remap the range. glyphFilter.SetScaleModeToScaleByScalar() glyphFilter.SetScaleFactor(scaleFactor) mapper = vtk.vtkPolyDataMapper() glyphFilter.Update() data = glyphFilter.GetOutput() mapper.SetInputData(data) mapper.ScalarVisibilityOff() act = vtk.vtkActor() act.SetMapper(mapper) cmap = self.getColorMap() r, g, b, a = cmap.index[lcolor] act.GetProperty().SetColor(r / 100., g / 100., b / 100.) plotting_dataset_bounds = vcs2vtk.getPlottingBounds( vcs.utils.getworldcoordinates(self._gm, self._data1.getAxis(-1), self._data1.getAxis(-2)), self._vtkDataSetBounds, self._vtkGeoTransform) x1, x2, y1, y2 = plotting_dataset_bounds 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]] 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_... # if geo is None: # for dp in vcs.elements['display'].values(): # if (hasattr(dp, 'backend')): # prevWc = dp.backend.get('dataset_bounds', None) # if (prevWc): # middleX = float(vp[0] + vp[1]) / 2.0 # middleY = float(vp[2] + vp[3]) / 2.0 # sideX = float(vp[1] - vp[0]) / 2.0 # sideY = float(vp[3] - vp[2]) / 2.0 # ratioX = float(prevWc[1] - prevWc[0]) / float(wc[1] - wc[0]) # ratioY = float(prevWc[3] - prevWc[2]) / float(wc[3] - wc[2]) # sideX = sideX / ratioX # sideY = sideY / ratioY # vp = [middleX - sideX, middleX + sideX, middleY - sideY, middleY + sideY] dataset_renderer, xScale, yScale = self._context().fitToViewport( act, vp, wc=wc, priority=self._template.data.priority, create_renderer=True) kwargs = {'vtk_backend_grid': self._vtkDataSet, 'dataset_bounds': self._vtkDataSetBounds, 'plotting_dataset_bounds': plotting_dataset_bounds, 'vtk_backend_geo': self._vtkGeoTransform} if ('ratio_autot_viewport' in self._resultDict): kwargs["ratio_autot_viewport"] = vp self._resultDict.update(self._context().renderTemplate( self._template, self._data1, self._gm, taxis, zaxis, **kwargs)) if self._context().canvas._continents is None: self._useContinents = False if self._useContinents: continents_renderer, xScale, yScale = self._context().plotContinents( plotting_dataset_bounds, projection, 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 plot(self, data1, data2, tmpl, gm, grid, transform): """Overrides baseclass implementation.""" #Preserve time and z axis for plotting these inof in rendertemplate returned = {} taxis = data1.getTime() if data1.ndim > 2: zaxis = data1.getAxis(-3) else: zaxis = None data1 = self._context.trimData2D(data1) # Ok get3 only the last 2 dims data2 = self._context.trimData2D(data2) gridGenDict = vcs2vtk.genGridOnPoints(data1, gm, deep=False, grid=grid, geo=transform) for k in ['vtk_backend_grid', 'xm', 'xM', 'ym', 'yM', 'continents', 'wrap', 'geo']: exec("%s = gridGenDict['%s']" % (k, k)) grid = gridGenDict['vtk_backend_grid'] returned["vtk_backend_grid"] = grid returned["vtk_backend_geo"] = geo missingMapper = vcs2vtk.putMaskOnVTKGrid(data1, grid, None, False, deep=False) # None/False are for color and cellData # (sent to vcs2vtk.putMaskOnVTKGrid) returned["vtk_backend_missing_mapper"] = (missingMapper, None, False) w = vcs2vtk.generateVectorArray(data1, data2, grid) grid.GetPointData().AddArray(w) ## Vector attempt l = gm.line if l is None: l = "default" try: l = vcs.getline(l) lwidth = l.width[0] lcolor = l.color[0] lstyle = l.type[0] except: lstyle = "solid" lwidth = 1. lcolor = 0 if gm.linewidth is not None: lwidth = gm.linewidth if gm.linecolor is not None: lcolor = gm.linecolor grid = vcs2vtk.stripGrid(grid) arrow = vtk.vtkGlyphSource2D() arrow.SetGlyphTypeToArrow() arrow.FilledOff() glyphFilter = vtk.vtkGlyph2D() glyphFilter.SetInputData(grid) glyphFilter.SetInputArrayToProcess(1, 0, 0, 0, "vectors") glyphFilter.SetSourceConnection(arrow.GetOutputPort()) glyphFilter.SetVectorModeToUseVector() # Rotate arrows to match vector data: glyphFilter.OrientOn() # Scale to vector magnitude: glyphFilter.SetScaleModeToScaleByVector() glyphFilter.SetScaleFactor(2. * gm.scale) # These are some unfortunately named methods. It does *not* clamp the # scale range to [min, max], but rather remaps the range # [min, max] --> [0, 1]. glyphFilter.ClampingOn() glyphFilter.SetRange(0.01, 1.0) mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(glyphFilter.GetOutputPort()) act = vtk.vtkActor() act.SetMapper(mapper) cmap = vcs.elements["colormap"][self._context.canvas.getcolormapname()] r, g, b = cmap.index[lcolor] act.GetProperty().SetColor(r / 100.,g / 100.,b / 100.) x1, x2, y1, y2 = vcs.utils.getworldcoordinates(gm, data1.getAxis(-1), data1.getAxis(-2)) act = vcs2vtk.doWrap(act, [x1,x2,y1,y2], wrap) ren = self._context.fitToViewport(act, [tmpl.data.x1, tmpl.data.x2, tmpl.data.y1, tmpl.data.y2], [x1, x2, y1, y2], priority=tmpl.data.priority) returned.update( self._context.renderTemplate(tmpl, data1, gm, taxis, zaxis)) if self._context.canvas._continents is None: continents = False if continents: projection = vcs.elements["projection"][gm.projection] self._context.plotContinents(x1, x2, y1, y2, projection, wrap, tmpl) returned["vtk_backend_actors"] = [[act, [x1,x2,y1,y2]],] returned["vtk_backend_glyphfilters"] = [glyphFilter,] returned["vtk_backend_luts"] = [[None, None],] return returned
def _plotInternal(self): """Overrides baseclass implementation.""" # Preserve time and z axis for plotting these inof in rendertemplate projection = vcs.elements["projection"][self._gm.projection] zaxis, taxis = self.getZandT() scale = 1.0 if self._vtkGeoTransform is not None: lat = None lon = None latAccessor = self._data1.getLatitude() lonAccessor = self._data1.getLongitude() if latAccessor: lat = latAccessor[:] if lonAccessor: lon = lonAccessor[:] newv = vtk.vtkDoubleArray() newv.SetNumberOfComponents(3) newv.InsertTypedTuple(0, [lon.min(), lat.min(), 0]) newv.InsertTypedTuple(1, [lon.max(), lat.max(), 0]) vcs2vtk.projectArray(newv, projection, self._vtkDataSetBounds) dimMin = [0, 0, 0] dimMax = [0, 0, 0] newv.GetTypedTuple(0, dimMin) newv.GetTypedTuple(1, dimMax) maxDimX = max(dimMin[0], dimMax[0]) maxDimY = max(dimMin[1], dimMax[1]) if lat.max() != 0.0: scale = abs((maxDimY / lat.max())) if lon.max() != 0.0: temp = abs((maxDimX / lon.max())) if scale < temp: scale = temp else: scale = 1.0 # Vector attempt ltp_tmp = self._gm.linetype if ltp_tmp is None: ltp_tmp = "default" try: ltp_tmp = vcs.getline(ltp_tmp) lwidth = ltp_tmp.width[0] # noqa lcolor = ltp_tmp.color[0] lstyle = ltp_tmp.type[0] # noqa except Exception: lstyle = "solid" # noqa lwidth = 1. # noqa lcolor = [0., 0., 0., 100.] if self._gm.linewidth is not None: lwidth = self._gm.linewidth # noqa if self._gm.linecolor is not None: lcolor = self._gm.linecolor arrow = vtk.vtkGlyphSource2D() arrow.SetGlyphTypeToArrow() arrow.SetOutputPointsPrecision(vtk.vtkAlgorithm.DOUBLE_PRECISION) arrow.FilledOff() plotting_dataset_bounds = self.getPlottingBounds() x1, x2, y1, y2 = plotting_dataset_bounds vp = self._resultDict.get('ratio_autot_viewport', [ self._template.data.x1, self._template.data.x2, self._template.data.y1, self._template.data.y2 ]) # The unscaled continent bounds were fine in the presence of axis # conversion, so save them here adjusted_plotting_bounds = vcs2vtk.getProjectedBoundsForWorldCoords( plotting_dataset_bounds, self._gm.projection) continentBounds = vcs2vtk.computeDrawAreaBounds( adjusted_plotting_bounds) # Transform the input data T = vtk.vtkTransform() T.Scale(self._context_xScale, self._context_yScale, 1.) self._vtkDataSetFittedToViewport = vcs2vtk.applyTransformationToDataset( T, self._vtkDataSetFittedToViewport) self._vtkDataSetBoundsNoMask = self._vtkDataSetFittedToViewport.GetBounds( ) polydata = self._vtkDataSetFittedToViewport # view and interactive area view = self._context().contextView area = vtk.vtkInteractiveArea() view.GetScene().AddItem(area) drawAreaBounds = vcs2vtk.computeDrawAreaBounds( self._vtkDataSetBoundsNoMask, self._context_flipX, self._context_flipY) [renWinWidth, renWinHeight] = self._context().renWin.GetSize() geom = vtk.vtkRecti(int(round(vp[0] * renWinWidth)), int(round(vp[2] * renWinHeight)), int(round((vp[1] - vp[0]) * renWinWidth)), int(round((vp[3] - vp[2]) * renWinHeight))) vcs2vtk.configureContextArea(area, drawAreaBounds, geom) # polydata = tmpMapper.GetInput() plotting_dataset_bounds = self.getPlottingBounds() vectors = polydata.GetPointData().GetVectors() if self._gm.scaletype == 'constant' or\ self._gm.scaletype == 'constantNNormalize' or\ self._gm.scaletype == 'constantNLinear': scaleFactor = scale * self._gm.scale else: scaleFactor = 1.0 glyphFilter = vtk.vtkGlyph2D() glyphFilter.SetInputArrayToProcess(1, 0, 0, 0, "vector") glyphFilter.SetSourceConnection(arrow.GetOutputPort()) glyphFilter.SetVectorModeToUseVector() # Rotate arrows to match vector data: glyphFilter.OrientOn() glyphFilter.ScalingOn() glyphFilter.SetScaleModeToScaleByVector() maxNormInVp = None minNormInVp = None # Find the min and max vector magnitudes (minNorm, maxNorm) = vectors.GetRange(-1) if maxNorm == 0: maxNorm = 1.0 if self._gm.scaletype == 'normalize' or self._gm.scaletype == 'linear' or\ self._gm.scaletype == 'constantNNormalize' or self._gm.scaletype == 'constantNLinear': if self._gm.scaletype == 'normalize' or self._gm.scaletype == 'constantNNormalize': scaleFactor /= maxNorm if self._gm.scaletype == 'linear' or self._gm.scaletype == 'constantNLinear': noOfComponents = vectors.GetNumberOfComponents() scalarArray = vtk.vtkDoubleArray() scalarArray.SetNumberOfComponents(1) scalarArray.SetNumberOfValues(vectors.GetNumberOfTuples()) oldRange = maxNorm - minNorm oldRange = 1.0 if oldRange == 0.0 else oldRange # New range min, max. newRangeValues = self._gm.scalerange newRange = newRangeValues[1] - newRangeValues[0] for i in range(0, vectors.GetNumberOfTuples()): norm = vtk.vtkMath.Norm(vectors.GetTuple(i), noOfComponents) newValue = (((norm - minNorm) * newRange) / oldRange) + newRangeValues[0] scalarArray.SetValue(i, newValue) polydata.GetPointData().SetScalars(scalarArray) maxNormInVp = newRangeValues[1] * scaleFactor minNormInVp = newRangeValues[0] * scaleFactor # Scale to vector magnitude: # NOTE: Currently we compute our own scaling factor since VTK does # it by clamping the values > max to max and values < min to min # and not remap the range. glyphFilter.SetScaleModeToScaleByScalar() if (maxNormInVp is None): maxNormInVp = maxNorm * scaleFactor # minNormInVp is left None, as it is displayed only for linear scaling. cmap = self.getColorMap() if isinstance(lcolor, (list, tuple)): r, g, b, a = lcolor else: r, g, b, a = cmap.index[lcolor] # act.GetProperty().SetColor(r / 100., g / 100., b / 100.) vtk_color = [int((c / 100.) * 255) for c in [r, g, b, a]] # Using the scaled data, set the glyph filter input glyphFilter.SetScaleFactor(scaleFactor) glyphFilter.SetInputData(polydata) glyphFilter.Update() # and set the arrows to be rendered. data = glyphFilter.GetOutput() floatValue = vtk.vtkFloatArray() floatValue.SetNumberOfComponents(1) floatValue.SetName("LineWidth") floatValue.InsertNextValue(lwidth) data.GetFieldData().AddArray(floatValue) item = vtk.vtkPolyDataItem() item.SetPolyData(data) item.SetScalarMode(vtk.VTK_SCALAR_MODE_USE_CELL_DATA) colorArray = vtk.vtkUnsignedCharArray() colorArray.SetNumberOfComponents(4) for i in range(data.GetNumberOfCells()): colorArray.InsertNextTypedTuple(vtk_color) item.SetMappedColors(colorArray) area.GetDrawAreaItem().AddItem(item) kwargs = { 'vtk_backend_grid': self._vtkDataSet, 'dataset_bounds': self._vtkDataSetBounds, 'plotting_dataset_bounds': plotting_dataset_bounds, "vtk_dataset_bounds_no_mask": self._vtkDataSetBoundsNoMask, 'vtk_backend_geo': self._vtkGeoTransform, "vtk_backend_draw_area_bounds": continentBounds, "vtk_backend_viewport_scale": [self._context_xScale, self._context_yScale] } if ('ratio_autot_viewport' in self._resultDict): kwargs["ratio_autot_viewport"] = vp self._resultDict.update(self._context().renderTemplate( self._template, self._data1, self._gm, taxis, zaxis, **kwargs)) # assume that self._data1.units has the proper vector units unitString = None if (hasattr(self._data1, 'units')): unitString = self._data1.units if self._vtkGeoTransform: worldWidth = self._vtkDataSetBoundsNoMask[ 1] - self._vtkDataSetBoundsNoMask[0] else: worldWidth = self._vtkDataSetBounds[1] - self._vtkDataSetBounds[0] worldToViewportXScale = (vp[1] - vp[0]) / worldWidth maxNormInVp *= worldToViewportXScale if (minNormInVp): minNormInVp *= worldToViewportXScale vcs.utils.drawVectorLegend(self._context().canvas, self._template.legend, lcolor, lstyle, lwidth, unitString, maxNormInVp, maxNorm, minNormInVp, minNorm, reference=self._gm.reference) kwargs['xaxisconvert'] = self._gm.xaxisconvert kwargs['yaxisconvert'] = self._gm.yaxisconvert if self._data1.getAxis(-1).isLongitude() and self._data1.getAxis( -2).isLatitude(): self._context().plotContinents( self._plot_kargs.get("continents", self._useContinents), plotting_dataset_bounds, projection, self._dataWrapModulo, vp, self._template.data.priority, **kwargs) self._resultDict["vtk_backend_actors"] = [[ item, plotting_dataset_bounds ]] self._resultDict["vtk_backend_glyphfilters"] = [glyphFilter] self._resultDict["vtk_backend_luts"] = [[None, None]]
def spaghetti_plot(variables, template=None, min_y=None, max_y=None, left_label=None, right_label=None, tick_sides=None, line="default", marker="default", x_labels="*", y_labels="*", canvas=None): """ This file is ready to be imported by your scripts, and you can just call this function. Sample usage is below. variables: List of variables to plot template: The template to use as the base for the plot. min_y: If you want to adjust the y axis bounds, you can set a minimum value. Will be derived from data if not specified. max_y: If you want to adjust the y axis bounds, you can set a maximum value. Will be derived from data if not specified. left_label: Text to put on the left Y axis right_label: Text to put on the right Y axis tick_sides: A list of "left" or "right" values indicating which side of the chart you want the variable axes to be displayed. line: A line object or name of a line object used to describe the lines plotted. Set to None to hide. marker: A marker object or name of a marker object used to describe the markers plotted. Set to None to hide. x_labels: Dictionary for setting axis tick labels y_labels: Dictionary for setting axis tick labels """ if canvas is None: canvas = vcs.init() if isinstance(template, (str, unicode)): template = vcs.gettemplate(template) if template is None: # Use our custom default template for 1ds template = vcs.createtemplate() # Shrink the template a bit template.scale(.78, "x") template.move(.02, "x") template.yname.x = .01 template.data.y1 = .1 template.box1.y1 = .1 ticlen = template.xtic1.y2 - template.xtic1.y1 template.xtic1.y1 = template.data.y1 template.xtic1.y2 = template.xtic1.y1 + ticlen template.xtic2.priority = 0 template.xlabel1.y = template.xtic1.y2 - .01 template.legend.x1 = template.data.x2 + (1 - template.data.x2) / 3. template.legend.x2 = .95 template.legend.y1 = template.data.y1 template.legend.y2 = template.data.y2 template.yname.y = (template.data.y1 + template.data.y2) / 2. template.xname.y = template.xlabel1.y - .05 # The labels don't make any sense with multiple values; hide them. template.min.priority = 0 template.max.priority = 0 template.mean.priority = 0 template.dataname.priority = 0 templates = EzTemplate.oneD(len(variables), template=template) templates.x = canvas if tick_sides is None: tick_sides = ["left"] * len(variables) clean_ticks = [] for t in tick_sides: if t.lower() not in ('left', 'right'): raise ValueError( "tick_sides must be a list of 'left' or 'right' values; found '%s'." % t) clean_ticks.append(t.lower()) tick_sides = clean_ticks if len(tick_sides) < len(variables): tick_sides += tick_sides[-1:] * len(variables) # Store min/max per side for appropriate scaling min_vals = {"left": min_y, "right": min_y} if min_y is None: for i, var in enumerate(variables): v_min = min(var) min_y = min_vals[tick_sides[i]] if min_y is None or min_y > v_min: min_vals[tick_sides[i]] = v_min max_vals = {"left": max_y, "right": max_y} if max_y is None: for i, var in enumerate(variables): v_max = max(var) max_y = max_vals[tick_sides[i]] if max_y is None or max_y < v_max: max_vals[tick_sides[i]] = v_max if isinstance(line, (str, unicode)): line = vcs.getline(line) if isinstance(marker, (str, unicode)): marker = vcs.getmarker(marker) to_pad = [] if line is not None: widths = line.width to_pad.append(widths) styles = line.type to_pad.append(styles) colors = line.color to_pad.append(colors) if marker is not None: markers = marker.type to_pad.append(markers) marker_colors = marker.color to_pad.append(marker_colors) marker_sizes = marker.size to_pad.append(marker_sizes) for padded in to_pad: if len(padded) < len(variables): padded += padded[-1:] * (len(variables) - len(padded)) for n in range(len(variables)): gm = vcs.create1d() if line is not None: gm.line = styles[n] gm.linewidth = widths[n] gm.linecolor = colors[n] else: gm.linewidth = 0 if marker is not None: gm.marker = markers[n] gm.markersize = marker_sizes[n] gm.markercolor = marker_colors[n] else: gm.marker = None gm.datawc_y1 = min_vals[tick_sides[n]] gm.datawc_y2 = max_vals[tick_sides[n]] template = templates.get(n) gm.xticlabels1 = x_labels if tick_sides[n] == "left": if tick_sides.index("left") == n: template.ylabel1.priority = 1 if left_label is not None: template.yname.priority = 0 left_text = vcs.createtext( Tt_source=template.yname.texttable, To_source=template.yname.textorientation) left_text.x = template.yname.x left_text.y = template.yname.y left_text.string = [left_label] templates.x.plot(left_text) else: template.ylabel1.priority = 0 template.yname.priority = 0 template.ylabel2.priority = 0 gm.yticlabels1 = y_labels gm.yticlabels2 = "" else: template.ylabel1.priority = 0 if tick_sides.index("right") == n: template.ylabel2.priority = 1 if right_label is not None: right_text = vcs.createtext( Tt_source=template.yname.texttable, To_source=template.yname.textorientation) right_text.x = template.data.x2 + (template.data.x1 - template.yname.x) right_text.y = template.yname.y right_text.string = [right_label] templates.x.plot(right_text) else: template.ylabel2.priority = 0 gm.yticlabels1 = "" gm.yticlabels2 = y_labels if n != 0: template.xlabel1.priority = 0 template.xname.priority = 0 var = variables[n] templates.x.plot(var, gm, template) return templates.x
def _plotInternal(self): """Overrides baseclass implementation.""" # Preserve time and z axis for plotting these inof in rendertemplate projection = vcs.elements["projection"][self._gm.projection] taxis = self._originalData1.getTime() scaleFactor = 1.0 if self._originalData1.ndim > 2: zaxis = self._originalData1.getAxis(-3) else: zaxis = None scale = 1.0 lat = None lon = None latAccessor = self._data1.getLatitude() lonAccessor = self._data1.getLongitude() if latAccessor: lat = latAccessor[:] if lonAccessor: lon = lonAccessor[:] if self._vtkGeoTransform is not None: newv = vtk.vtkDoubleArray() newv.SetNumberOfComponents(3) newv.InsertTypedTuple(0, [lon.min(), lat.min(), 0]) newv.InsertTypedTuple(1, [lon.max(), lat.max(), 0]) vcs2vtk.projectArray(newv, projection, self._vtkDataSetBounds) dimMin = [0, 0, 0] dimMax = [0, 0, 0] newv.GetTypedTuple(0, dimMin) newv.GetTypedTuple(1, dimMax) maxDimX = max(dimMin[0], dimMax[0]) maxDimY = max(dimMin[1], dimMax[1]) if lat.max() != 0.0: scale = abs((maxDimY / lat.max())) if lon.max() != 0.0: temp = abs((maxDimX / lon.max())) if scale < temp: scale = temp else: scale = 1.0 # Vector attempt ltp_tmp = self._gm.linetype if ltp_tmp is None: ltp_tmp = "default" try: ltp_tmp = vcs.getline(ltp_tmp) lwidth = ltp_tmp.width[0] # noqa lcolor = ltp_tmp.color[0] lstyle = ltp_tmp.type[0] # noqa except Exception: lstyle = "solid" # noqa lwidth = 1. # noqa lcolor = [0., 0., 0., 100.] if self._gm.linewidth is not None: lwidth = self._gm.linewidth # noqa if self._gm.linecolor is not None: lcolor = self._gm.linecolor arrow = vtk.vtkGlyphSource2D() arrow.SetGlyphTypeToArrow() arrow.SetOutputPointsPrecision(vtk.vtkAlgorithm.DOUBLE_PRECISION) arrow.FilledOff() polydata = self._vtkPolyDataFilter.GetOutput() vectors = polydata.GetPointData().GetVectors() if self._gm.scaletype == 'constant' or\ self._gm.scaletype == 'constantNNormalize' or\ self._gm.scaletype == 'constantNLinear': scaleFactor = scale * self._gm.scale else: scaleFactor = 1.0 glyphFilter = vtk.vtkGlyph2D() glyphFilter.SetInputData(polydata) glyphFilter.SetInputArrayToProcess(1, 0, 0, 0, "vector") glyphFilter.SetSourceConnection(arrow.GetOutputPort()) glyphFilter.SetVectorModeToUseVector() # Rotate arrows to match vector data: glyphFilter.OrientOn() glyphFilter.ScalingOn() glyphFilter.SetScaleModeToScaleByVector() maxNormInVp = None minNormInVp = None # Find the min and max vector magnitudes (minNorm, maxNorm) = vectors.GetRange(-1) if maxNorm == 0: maxNorm = 1.0 if self._gm.scaletype == 'normalize' or self._gm.scaletype == 'linear' or\ self._gm.scaletype == 'constantNNormalize' or self._gm.scaletype == 'constantNLinear': if self._gm.scaletype == 'normalize' or self._gm.scaletype == 'constantNNormalize': scaleFactor /= maxNorm if self._gm.scaletype == 'linear' or self._gm.scaletype == 'constantNLinear': noOfComponents = vectors.GetNumberOfComponents() scalarArray = vtk.vtkDoubleArray() scalarArray.SetNumberOfComponents(1) scalarArray.SetNumberOfValues(vectors.GetNumberOfTuples()) oldRange = maxNorm - minNorm oldRange = 1.0 if oldRange == 0.0 else oldRange # New range min, max. newRangeValues = self._gm.scalerange newRange = newRangeValues[1] - newRangeValues[0] for i in range(0, vectors.GetNumberOfTuples()): norm = vtk.vtkMath.Norm(vectors.GetTuple(i), noOfComponents) newValue = (((norm - minNorm) * newRange) / oldRange) + newRangeValues[0] scalarArray.SetValue(i, newValue) polydata.GetPointData().SetScalars(scalarArray) maxNormInVp = newRangeValues[1] * scaleFactor minNormInVp = newRangeValues[0] * scaleFactor # Scale to vector magnitude: # NOTE: Currently we compute our own scaling factor since VTK does # it by clamping the values > max to max and values < min to min # and not remap the range. glyphFilter.SetScaleModeToScaleByScalar() glyphFilter.SetScaleFactor(scaleFactor) if (maxNormInVp is None): maxNormInVp = maxNorm * scaleFactor # minNormInVp is left None, as it is displayed only for linear scaling. mapper = vtk.vtkPolyDataMapper() glyphFilter.Update() data = glyphFilter.GetOutput() mapper.SetInputData(data) mapper.ScalarVisibilityOff() act = vtk.vtkActor() act.SetMapper(mapper) cmap = self.getColorMap() if isinstance(lcolor, (list, tuple)): r, g, b, a = lcolor else: r, g, b, a = cmap.index[lcolor] act.GetProperty().SetColor(r / 100., g / 100., b / 100.) plotting_dataset_bounds = self.getPlottingBounds() vp = self._resultDict.get('ratio_autot_viewport', [ self._template.data.x1, self._template.data.x2, self._template.data.y1, self._template.data.y2 ]) dataset_renderer, xScale, yScale = self._context().fitToViewport( act, vp, wc=plotting_dataset_bounds, geoBounds=self._vtkDataSetBoundsNoMask, geo=self._vtkGeoTransform, priority=self._template.data.priority, create_renderer=True) kwargs = { 'vtk_backend_grid': self._vtkDataSet, 'dataset_bounds': self._vtkDataSetBounds, 'plotting_dataset_bounds': plotting_dataset_bounds, "vtk_dataset_bounds_no_mask": self._vtkDataSetBoundsNoMask, 'vtk_backend_geo': self._vtkGeoTransform } if ('ratio_autot_viewport' in self._resultDict): kwargs["ratio_autot_viewport"] = vp self._resultDict.update(self._context().renderTemplate( self._template, self._data1, self._gm, taxis, zaxis, **kwargs)) # assume that self._data1.units has the proper vector units unitString = None if (hasattr(self._data1, 'units')): unitString = self._data1.units worldToViewportXScale = (vp[1] - vp[0]) /\ (self._vtkDataSetBoundsNoMask[1] - self._vtkDataSetBoundsNoMask[0]) maxNormInVp *= worldToViewportXScale if (minNormInVp): minNormInVp *= worldToViewportXScale vcs.utils.drawVectorLegend(self._context().canvas, self._template.legend, lcolor, lstyle, lwidth, unitString, maxNormInVp, maxNorm, minNormInVp, minNorm) if self._context().canvas._continents is None: self._useContinents = False if self._useContinents: continents_renderer, xScale, yScale = self._context( ).plotContinents(plotting_dataset_bounds, projection, self._dataWrapModulo, vp, self._template.data.priority, **kwargs) self._resultDict["vtk_backend_actors"] = [[ act, plotting_dataset_bounds ]] self._resultDict["vtk_backend_glyphfilters"] = [glyphFilter] self._resultDict["vtk_backend_luts"] = [[None, None]]
def plotVector(self,data1,data2,tmpl,gm,ren): self.setLayer(ren,tmpl.data.priority) ug,xm,xM,ym,yM,continents,wrap = vcs2vtk.genUnstructuredGrid(data1,data2,gm) if ug.IsA("vtkUnstructuredGrid"): c2p = vtk.vtkCellDataToPointData() c2p.SetInputData(ug) c2p.Update() #For contouring duplicate points seem to confuse it cln = vtk.vtkCleanUnstructuredGrid() cln.SetInputConnection(c2p.GetOutputPort()) missingMapper = vcs2vtk.putMaskOnVTKGrid(data1,ug,None) u=numpy.ma.ravel(data1) v=numpy.ma.ravel(data2) sh = list(u.shape) sh.append(1) u = numpy.reshape(u,sh) v = numpy.reshape(v,sh) z = numpy.zeros(u.shape) w = numpy.concatenate((u,v),axis=1) w = numpy.concatenate((w,z),axis=1) w = VN.numpy_to_vtk(w,deep=True) w.SetName("vectors") ug.GetPointData().AddArray(w) ## Vector attempt arrow = vtk.vtkArrowSource() l = gm.line if l is None: l = "default" try: l = vcs.getline(l) lwidth = l.width[0] lcolor = l.color[0] lstyle = l.type[0] except: lstyle = "solid" lwidth = 1. lcolor = 0 if gm.linewidth is not None: lwidth = gm.linewidth if gm.linecolor is not None: lcolor = gm.linecolor arrow.SetTipRadius(.1*lwidth) arrow.SetShaftRadius(.03*lwidth) arrow.Update() glyphFilter = vtk.vtkGlyph2D() glyphFilter.SetSourceConnection(arrow.GetOutputPort()) glyphFilter.OrientOn() glyphFilter.SetVectorModeToUseVector() glyphFilter.SetInputArrayToProcess(1,0,0,0,"vectors") glyphFilter.SetScaleFactor(2.*gm.scale) if ug.IsA("vtkUnstructuredGrid"): glyphFilter.SetInputConnection(cln.GetOutputPort()) else: glyphFilter.SetInputData(ug) mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(glyphFilter.GetOutputPort()) act = vtk.vtkActor() act.SetMapper(mapper) try: cmap = vcs.elements["colormap"][cmap] except: cmap = vcs.elements["colormap"][self.canvas.getcolormapname()] r,g,b = cmap.index[lcolor] act.GetProperty().SetColor(r/100.,g/100.,b/100.) x1,x2,y1,y2 = vcs2vtk.getRange(gm,xm,xM,ym,yM) act = vcs2vtk.doWrap(act,[x1,x2,y1,y2],wrap) vcs2vtk.fitToViewport(act,ren,[tmpl.data.x1,tmpl.data.x2,tmpl.data.y1,tmpl.data.y2],[x1,x2,y1,y2]) if tmpl.data.priority!=0: ren.AddActor(act) self.renderTemplate(ren,tmpl,data1,gm) if self.canvas._continents is None: continents = False if continents: projection = vcs.elements["projection"][gm.projection] self.plotContinents(x1,x2,y1,y2,projection,wrap,ren,tmpl)
def plotVector(self,data1,data2,tmpl,gm): ug,xm,xM,ym,yM,continents,wrap,geo,cellData = vcs2vtk.genGrid(data1,data2,gm) if cellData: c2p = vtk.vtkCellDataToPointData() c2p.SetInputData(ug) c2p.Update() #For contouring duplicate points seem to confuse it if ug.IsA("vtkUnstructuredGrid"): cln = vtk.vtkCleanUnstructuredGrid() cln.SetInputConnection(c2p.GetOutputPort()) missingMapper = vcs2vtk.putMaskOnVTKGrid(data1,ug,None,cellData) u=numpy.ma.ravel(data1) v=numpy.ma.ravel(data2) sh = list(u.shape) sh.append(1) u = numpy.reshape(u,sh) v = numpy.reshape(v,sh) z = numpy.zeros(u.shape) w = numpy.concatenate((u,v),axis=1) w = numpy.concatenate((w,z),axis=1) w = VN.numpy_to_vtk(w,deep=True) w.SetName("vectors") ug.GetPointData().AddArray(w) ## Vector attempt arrow = vtk.vtkArrowSource() l = gm.line if l is None: l = "default" try: l = vcs.getline(l) lwidth = l.width[0] lcolor = l.color[0] lstyle = l.type[0] except: lstyle = "solid" lwidth = 1. lcolor = 0 if gm.linewidth is not None: lwidth = gm.linewidth if gm.linecolor is not None: lcolor = gm.linecolor arrow.SetTipRadius(.1*lwidth) arrow.SetShaftRadius(.03*lwidth) arrow.Update() glyphFilter = vtk.vtkGlyph2D() glyphFilter.SetSourceConnection(arrow.GetOutputPort()) glyphFilter.OrientOn() glyphFilter.SetVectorModeToUseVector() glyphFilter.SetInputArrayToProcess(1,0,0,0,"vectors") glyphFilter.SetScaleFactor(2.*gm.scale) if cellData: if ug.IsA("vtkUnstructuredGrid"): glyphFilter.SetInputConnection(cln.GetOutputPort()) else: glyphFilter.SetInputConnection(c2p.GetOutputPort()) else: glyphFilter.SetInputData(ug) mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(glyphFilter.GetOutputPort()) act = vtk.vtkActor() act.SetMapper(mapper) try: cmap = vcs.elements["colormap"][cmap] except: cmap = vcs.elements["colormap"][self.canvas.getcolormapname()] r,g,b = cmap.index[lcolor] act.GetProperty().SetColor(r/100.,g/100.,b/100.) x1,x2,y1,y2 = vcs2vtk.getRange(gm,xm,xM,ym,yM) act = vcs2vtk.doWrap(act,[x1,x2,y1,y2],wrap) ren=vtk.vtkRenderer() self.renWin.AddRenderer(ren) self.setLayer(ren,tmpl.data.priority) vcs2vtk.fitToViewport(act,ren,[tmpl.data.x1,tmpl.data.x2,tmpl.data.y1,tmpl.data.y2],[x1,x2,y1,y2]) if tmpl.data.priority!=0: ren.AddActor(act) self.renderTemplate(tmpl,data1,gm) if self.canvas._continents is None: continents = False if continents: projection = vcs.elements["projection"][gm.projection] self.plotContinents(x1,x2,y1,y2,projection,wrap,tmpl)
def spaghetti_plot(variables, template=None, min_y=None, max_y=None, left_label=None, right_label=None, tick_sides=None, line="default", marker="default", x_labels="*", y_labels="*", canvas=None): """ This file is ready to be imported by your scripts, and you can just call this function. Sample usage is below. variables: List of variables to plot template: The template to use as the base for the plot. min_y: If you want to adjust the y axis bounds, you can set a minimum value. Will be derived from data if not specified. max_y: If you want to adjust the y axis bounds, you can set a maximum value. Will be derived from data if not specified. left_label: Text to put on the left Y axis right_label: Text to put on the right Y axis tick_sides: A list of "left" or "right" values indicating which side of the chart you want the variable axes to be displayed. line: A line object or name of a line object used to describe the lines plotted. Set to None to hide. marker: A marker object or name of a marker object used to describe the markers plotted. Set to None to hide. x_labels: Dictionary for setting axis tick labels y_labels: Dictionary for setting axis tick labels """ if canvas is None: canvas = vcs.init() if isinstance(template, (str, unicode)): template = vcs.gettemplate(template) if template is None: # Use our custom default template for 1ds template = vcs.createtemplate() # Shrink the template a bit template.scale(.78, "x") template.move(.02, "x") template.yname.x = .01 template.data.y1 = .1 template.box1.y1 = .1 ticlen = template.xtic1.y2 - template.xtic1.y1 template.xtic1.y1 = template.data.y1 template.xtic1.y2 = template.xtic1.y1 + ticlen template.xtic2.priority = 0 template.xlabel1.y = template.xtic1.y2 - .01 template.legend.x1 = template.data.x2 + (1 - template.data.x2) / 3. template.legend.x2 = .95 template.legend.y1 = template.data.y1 template.legend.y2 = template.data.y2 template.yname.y = (template.data.y1 + template.data.y2)/2. template.xname.y = template.xlabel1.y - .05 # The labels don't make any sense with multiple values; hide them. template.min.priority = 0 template.max.priority = 0 template.mean.priority = 0 template.dataname.priority = 0 templates = EzTemplate.oneD(len(variables), template=template) templates.x = canvas if tick_sides is None: tick_sides = ["left"] * len(variables) clean_ticks = [] for t in tick_sides: if t.lower() not in ('left', 'right'): raise ValueError("tick_sides must be a list of 'left' or 'right' values; found '%s'." % t) clean_ticks.append(t.lower()) tick_sides = clean_ticks if len(tick_sides) < len(variables): tick_sides += tick_sides[-1:] * len(variables) # Store min/max per side for appropriate scaling min_vals = {"left": min_y, "right": min_y} if min_y is None: for i, var in enumerate(variables): v_min = min(var) min_y = min_vals[tick_sides[i]] if min_y is None or min_y > v_min: min_vals[tick_sides[i]] = v_min max_vals = {"left": max_y, "right": max_y} if max_y is None: for i, var in enumerate(variables): v_max = max(var) max_y = max_vals[tick_sides[i]] if max_y is None or max_y < v_max: max_vals[tick_sides[i]] = v_max if isinstance(line, (str, unicode)): line = vcs.getline(line) if isinstance(marker, (str, unicode)): marker = vcs.getmarker(marker) to_pad = [] if line is not None: widths = line.width to_pad.append(widths) styles = line.type to_pad.append(styles) colors = line.color to_pad.append(colors) if marker is not None: markers = marker.type to_pad.append(markers) marker_colors = marker.color to_pad.append(marker_colors) marker_sizes = marker.size to_pad.append(marker_sizes) for padded in to_pad: if len(padded) < len(variables): padded += padded[-1:] * (len(variables) - len(padded)) for n in range(len(variables)): gm = vcs.create1d() if line is not None: gm.line = styles[n] gm.linewidth = widths[n] gm.linecolor = colors[n] else: gm.linewidth = 0 if marker is not None: gm.marker = markers[n] gm.markersize = marker_sizes[n] gm.markercolor = marker_colors[n] else: gm.marker = None gm.datawc_y1 = min_vals[tick_sides[n]] gm.datawc_y2 = max_vals[tick_sides[n]] template = templates.get(n) gm.xticlabels1 = x_labels if tick_sides[n] == "left": if tick_sides.index("left") == n: template.ylabel1.priority = 1 if left_label is not None: template.yname.priority = 0 left_text = vcs.createtext(Tt_source=template.yname.texttable, To_source=template.yname.textorientation) left_text.x = template.yname.x left_text.y = template.yname.y left_text.string = [left_label] templates.x.plot(left_text) else: template.ylabel1.priority = 0 template.yname.priority = 0 template.ylabel2.priority = 0 gm.yticlabels1 = y_labels gm.yticlabels2 = "" else: template.ylabel1.priority = 0 if tick_sides.index("right") == n: template.ylabel2.priority = 1 if right_label is not None: right_text = vcs.createtext(Tt_source=template.yname.texttable, To_source=template.yname.textorientation) right_text.x = template.data.x2 + (template.data.x1 - template.yname.x) right_text.y = template.yname.y right_text.string = [right_label] templates.x.plot(right_text) else: template.ylabel2.priority = 0 gm.yticlabels1 = "" gm.yticlabels2 = y_labels if n != 0: template.xlabel1.priority = 0 template.xname.priority = 0 var = variables[n] templates.x.plot(var, gm, template) return templates.x
def plotVector(self,data1,data2,tmpl,gm): #Preserve time and z axis for plotting these inof in rendertemplate taxis = data1.getTime() if data1.ndim>2: zaxis = data1.getAxis(-3) else: zaxis = None data1 = self.trimData2D(data1) # Ok get3 only the last 2 dims data2 = self.trimData2D(data2) ug,xm,xM,ym,yM,continents,wrap,geo = vcs2vtk.genGridOnPoints(data1,data2,gm,deep=False) missingMapper = vcs2vtk.putMaskOnVTKGrid(data1,ug,None,False,deep=False) u=numpy.ma.ravel(data1) v=numpy.ma.ravel(data2) sh = list(u.shape) sh.append(1) u = numpy.reshape(u,sh) v = numpy.reshape(v,sh) z = numpy.zeros(u.shape) w = numpy.concatenate((u,v),axis=1) w = numpy.concatenate((w,z),axis=1) # HACK The grid returned by vtk2vcs.genGrid is not the same size as the # data array. I'm not sure where the issue is...for now let's just zero-pad # data array so that we can at least test rendering until Charles gets # back from vacation: wLen = len(w) numPts = ug.GetNumberOfPoints() if wLen != numPts: warnings.warn("!!! Warning during vector plotting: Number of points does not "\ "match the number of vectors to be glyphed (%s points vs %s "\ "vectors). The vectors will be padded/truncated to match for "\ "rendering purposes, but the resulting image should not be "\ "trusted."%(numPts, wLen)) newShape = (numPts,) + w.shape[1:] w = numpy.ma.resize(w, newShape) w = vcs2vtk.numpy_to_vtk_wrapper(w,deep=False) w.SetName("vectors") ug.GetPointData().AddArray(w) ## Vector attempt l = gm.line if l is None: l = "default" try: l = vcs.getline(l) lwidth = l.width[0] lcolor = l.color[0] lstyle = l.type[0] except: lstyle = "solid" lwidth = 1. lcolor = 0 if gm.linewidth is not None: lwidth = gm.linewidth if gm.linecolor is not None: lcolor = gm.linecolor # Strip out masked points. if ug.IsA("vtkStructuredGrid"): if ug.GetCellBlanking(): visArray = ug.GetCellVisibilityArray() visArray.SetName("BlankingArray") ug.GetCellData().AddArray(visArray) thresh = vtk.vtkThreshold() thresh.SetInputData(ug) thresh.ThresholdByUpper(0.5) thresh.SetInputArrayToProcess(0, 0, 0, "vtkDataObject::FIELD_ASSOCIATION_CELLS", "BlankingArray") thresh.Update() ug = thresh.GetOutput() elif ug.GetPointBlanking(): visArray = ug.GetPointVisibilityArray() visArray.SetName("BlankingArray") ug.GetPointData().AddArray(visArray) thresh = vtk.vtkThreshold() thresh.SetInputData(ug) thresh.SetUpperThreshold(0.5) thresh.SetInputArrayToProcess(0, 0, 0, "vtkDataObject::FIELD_ASSOCIATION_POINTS", "BlankingArray") thresh.Update() ug = thresh.GetOutput() arrow = vtk.vtkGlyphSource2D() arrow.SetGlyphTypeToArrow() arrow.FilledOff() glyphFilter = vtk.vtkGlyph2D() glyphFilter.SetSourceConnection(arrow.GetOutputPort()) glyphFilter.SetVectorModeToUseVector() # Rotate arrows to match vector data: glyphFilter.OrientOn() # Scale to vector magnitude: glyphFilter.SetScaleModeToScaleByVector() # These are some unfortunately named methods. It does *not* clamp the scale # range to [min, max], but rather remaps the range [min, max]-->[0,1]. Bump # up min so that near-zero vectors will not be rendered, as these tend to # come out randomly oriented. glyphFilter.ClampingOn() glyphFilter.SetRange(0.01, 1.0) glyphFilter.SetInputArrayToProcess(1,0,0,0,"vectors") glyphFilter.SetScaleFactor(2.*gm.scale) #if cellData: # if ug.IsA("vtkUnstructuredGrid"): # glyphFilter.SetInputConnection(cln.GetOutputPort()) # else: # glyphFilter.SetInputConnection(c2p.GetOutputPort()) #else: # glyphFilter.SetInputData(ug) glyphFilter.SetInputData(ug) mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(glyphFilter.GetOutputPort()) act = vtk.vtkActor() act.SetMapper(mapper) try: cmap = vcs.elements["colormap"][cmap] except: cmap = vcs.elements["colormap"][self.canvas.getcolormapname()] r,g,b = cmap.index[lcolor] act.GetProperty().SetColor(r/100.,g/100.,b/100.) x1,x2,y1,y2 = vcs2vtk.getRange(gm,xm,xM,ym,yM) act = vcs2vtk.doWrap(act,[x1,x2,y1,y2],wrap) ren = self.createRenderer() self.renWin.AddRenderer(ren) self.setLayer(ren,tmpl.data.priority) vcs2vtk.fitToViewport(act,ren,[tmpl.data.x1,tmpl.data.x2,tmpl.data.y1,tmpl.data.y2],[x1,x2,y1,y2]) if tmpl.data.priority!=0: ren.AddActor(act) self.renderTemplate(tmpl,data1,gm,taxis,zaxis) if self.canvas._continents is None: continents = False if continents: projection = vcs.elements["projection"][gm.projection] self.plotContinents(x1,x2,y1,y2,projection,wrap,tmpl)
def line(name): try: obj = vcs.getline(str(name)) except: abort(404) return jsonify(vcs.utils.dumpToDict(obj)[0])
def _plotInternal(self): """Overrides baseclass implementation.""" # Preserve time and z axis for plotting these inof in rendertemplate projection = vcs.elements["projection"][self._gm.projection] zaxis, taxis = self.getZandT() # Streamline color if (not self._gm.coloredbyvector): ln_tmp = self._gm.linetype if ln_tmp is None: ln_tmp = "default" try: ln_tmp = vcs.getline(ln_tmp) lwidth = ln_tmp.width[0] # noqa lcolor = ln_tmp.color[0] lstyle = ln_tmp.type[0] # noqa except Exception: lstyle = "solid" # noqa lwidth = 1. # noqa lcolor = [0., 0., 0., 100.] if self._gm.linewidth is not None: lwidth = self._gm.linewidth # noqa if self._gm.linecolor is not None: lcolor = self._gm.linecolor # The unscaled continent bounds were fine in the presence of axis # conversion, so save them here continentBounds = vcs2vtk.computeDrawAreaBounds( self._vtkDataSetBoundsNoMask, self._context_flipX, self._context_flipY) # Only scaling the data in the presence of axis conversion changes # the seed points in any other cases, and thus results in plots # different from the baselines but still fundamentally sound, it # seems. Always scaling the data results in no differences in the # plots between Context2D and the old baselines. # Transform the input data T = vtk.vtkTransform() T.Scale(self._context_xScale, self._context_yScale, 1.) self._vtkDataSetFittedToViewport = vcs2vtk.applyTransformationToDataset( T, self._vtkDataSetFittedToViewport) self._vtkDataSetBoundsNoMask = self._vtkDataSetFittedToViewport.GetBounds( ) polydata = self._vtkDataSetFittedToViewport plotting_dataset_bounds = self.getPlottingBounds() x1, x2, y1, y2 = plotting_dataset_bounds vp = self._resultDict.get('ratio_autot_viewport', [ self._template.data.x1, self._template.data.x2, self._template.data.y1, self._template.data.y2 ]) # view and interactive area view = self._context().contextView area = vtk.vtkInteractiveArea() view.GetScene().AddItem(area) drawAreaBounds = vcs2vtk.computeDrawAreaBounds( self._vtkDataSetBoundsNoMask, self._context_flipX, self._context_flipY) [renWinWidth, renWinHeight] = self._context().renWin.GetSize() geom = vtk.vtkRecti(int(round(vp[0] * renWinWidth)), int(round(vp[2] * renWinHeight)), int(round((vp[1] - vp[0]) * renWinWidth)), int(round((vp[3] - vp[2]) * renWinHeight))) vcs2vtk.configureContextArea(area, drawAreaBounds, geom) dataLength = polydata.GetLength() if (not self._gm.evenlyspaced): # generate random seeds in a circle centered in the center of # the bounding box for the data. # by default vtkPointSource uses a global random source in vtkMath which is # seeded only once. It makes more sense to seed a random sequence each time you draw # the streamline plot. pointSequence = vtk.vtkMinimalStandardRandomSequence() pointSequence.SetSeedOnly(1177) # replicate the seed from vtkMath seed = vtk.vtkPointSource() seed.SetNumberOfPoints(self._gm.numberofseeds) seed.SetCenter(polydata.GetCenter()) seed.SetRadius(dataLength / 2.0) seed.SetRandomSequence(pointSequence) seed.Update() seedData = seed.GetOutput() # project all points to Z = 0 plane points = seedData.GetPoints() for i in range(0, points.GetNumberOfPoints()): p = list(points.GetPoint(i)) p[2] = 0 points.SetPoint(i, p) if (self._gm.integratortype == 0): integrator = vtk.vtkRungeKutta2() elif (self._gm.integratortype == 1): integrator = vtk.vtkRungeKutta4() else: if (self._gm.evenlyspaced): warnings.warn( "You cannot use RungeKutta45 for evenly spaced streamlines." "Using RungeKutta4 instead") integrator = vtk.vtkRungeKutta4() else: integrator = vtk.vtkRungeKutta45() if (self._gm.evenlyspaced): streamer = vtk.vtkEvenlySpacedStreamlines2D() startseed = self._gm.startseed \ if self._gm.startseed else polydata.GetCenter() streamer.SetStartPosition(startseed) streamer.SetSeparatingDistance(self._gm.separatingdistance) streamer.SetSeparatingDistanceRatio( self._gm.separatingdistanceratio) streamer.SetClosedLoopMaximumDistance( self._gm.closedloopmaximumdistance) else: # integrate streamlines on normalized vector so that # IntegrationTime stores distance streamer = vtk.vtkStreamTracer() streamer.SetSourceData(seedData) streamer.SetIntegrationDirection(self._gm.integrationdirection) streamer.SetMinimumIntegrationStep(self._gm.minimumsteplength) streamer.SetMaximumIntegrationStep(self._gm.maximumsteplength) streamer.SetMaximumError(self._gm.maximumerror) streamer.SetMaximumPropagation(dataLength * self._gm.maximumstreamlinelength) streamer.SetInputData(polydata) streamer.SetInputArrayToProcess(0, 0, 0, 0, "vector") streamer.SetIntegrationStepUnit(self._gm.integrationstepunit) streamer.SetInitialIntegrationStep(self._gm.initialsteplength) streamer.SetMaximumNumberOfSteps(self._gm.maximumsteps) streamer.SetTerminalSpeed(self._gm.terminalspeed) streamer.SetIntegrator(integrator) # add arc_length to streamlines arcLengthFilter = vtk.vtkAppendArcLength() arcLengthFilter.SetInputConnection(streamer.GetOutputPort()) arcLengthFilter.Update() streamlines = arcLengthFilter.GetOutput() # glyph seed points contour = vtk.vtkContourFilter() contour.SetInputConnection(arcLengthFilter.GetOutputPort()) contour.SetValue(0, 0.001) if (streamlines.GetNumberOfPoints()): r = streamlines.GetPointData().GetArray("arc_length").GetRange() numberofglyphsoneside = self._gm.numberofglyphs // 2 for i in range(1, numberofglyphsoneside): contour.SetValue(i, r[1] / numberofglyphsoneside * i) else: warnings.warn( "No streamlines created. " "The 'startseed' parameter needs to be inside the domain and " "not over masked data.") contour.SetInputArrayToProcess(0, 0, 0, 0, "arc_length") # arrow glyph source glyph2DSource = vtk.vtkGlyphSource2D() glyph2DSource.SetGlyphTypeToTriangle() glyph2DSource.SetRotationAngle(-90) glyph2DSource.SetFilled(self._gm.filledglyph) # arrow glyph adjustment transform = vtk.vtkTransform() transform.Scale(1., self._gm.glyphbasefactor, 1.) transformFilter = vtk.vtkTransformFilter() transformFilter.SetInputConnection(glyph2DSource.GetOutputPort()) transformFilter.SetTransform(transform) transformFilter.Update() glyphLength = transformFilter.GetOutput().GetLength() # drawing the glyphs at the seed points glyph = vtk.vtkGlyph2D() glyph.SetInputConnection(contour.GetOutputPort()) glyph.SetInputArrayToProcess(1, 0, 0, 0, "vector") glyph.SetSourceData(transformFilter.GetOutput()) glyph.SetScaleModeToDataScalingOff() glyph.SetScaleFactor(dataLength * self._gm.glyphscalefactor / glyphLength) glyph.SetColorModeToColorByVector() glyphMapper = vtk.vtkPolyDataMapper() glyphActor = vtk.vtkActor() mapper = vtk.vtkPolyDataMapper() act = vtk.vtkActor() glyph.Update() glyphDataset = glyph.GetOutput() streamer.Update() lineDataset = streamer.GetOutput() deleteLineColors = False deleteGlyphColors = False # color the streamlines and glyphs cmap = self.getColorMap() if (self._gm.coloredbyvector): numLevels = len(self._contourLevels) - 1 while len(self._contourColors) < numLevels: self._contourColors.append(self._contourColors[-1]) lut = vtk.vtkLookupTable() lut.SetNumberOfTableValues(numLevels) for i in range(numLevels): r, g, b, a = self.getColorIndexOrRGBA(cmap, self._contourColors[i]) lut.SetTableValue(i, r / 100., g / 100., b / 100., a / 100.) lut.SetVectorModeToMagnitude() if numpy.allclose(self._contourLevels[0], -1.e20): lmn = self._vectorRange[0] else: lmn = self._contourLevels[0][0] if numpy.allclose(self._contourLevels[-1], 1.e20): lmx = self._vectorRange[1] else: lmx = self._contourLevels[-1][-1] lut.SetRange(lmn, lmx) mapper.ScalarVisibilityOn() mapper.SetLookupTable(lut) mapper.UseLookupTableScalarRangeOn() mapper.SetScalarModeToUsePointFieldData() mapper.SelectColorArray("vector") lineAttrs = lineDataset.GetPointData() lineData = lineAttrs.GetArray("vector") if lineData and numLevels: lineColors = lut.MapScalars(lineData, vtk.VTK_COLOR_MODE_DEFAULT, 0) deleteLineColors = True else: print( 'WARNING: streamline pipeline cannot map scalars for "lineData", using solid color' ) numTuples = lineDataset.GetNumberOfPoints() color = [0, 0, 0, 255] lineColors = vcs2vtk.generateSolidColorArray(numTuples, color) glyphMapper.ScalarVisibilityOn() glyphMapper.SetLookupTable(lut) glyphMapper.UseLookupTableScalarRangeOn() glyphMapper.SetScalarModeToUsePointFieldData() glyphMapper.SelectColorArray("VectorMagnitude") glyphAttrs = glyphDataset.GetPointData() glyphData = glyphAttrs.GetArray("VectorMagnitude") if glyphData and numLevels: glyphColors = lut.MapScalars(glyphData, vtk.VTK_COLOR_MODE_DEFAULT, 0) deleteGlyphColors = True else: print( 'WARNING: streamline pipeline cannot map scalars for "glyphData", using solid color' ) numTuples = glyphDataset.GetNumberOfPoints() color = [0, 0, 0, 255] glyphColors = vcs2vtk.generateSolidColorArray(numTuples, color) else: mapper.ScalarVisibilityOff() glyphMapper.ScalarVisibilityOff() if isinstance(lcolor, (list, tuple)): r, g, b, a = lcolor else: r, g, b, a = cmap.index[lcolor] act.GetProperty().SetColor(r / 100., g / 100., b / 100.) glyphActor.GetProperty().SetColor(r / 100., g / 100., b / 100.) fixedColor = [ int((r / 100.) * 255), int((g / 100.) * 255), int((b / 100.) * 255), 255 ] numTuples = lineDataset.GetNumberOfPoints() lineColors = vcs2vtk.generateSolidColorArray(numTuples, fixedColor) numTuples = glyphDataset.GetNumberOfPoints() glyphColors = vcs2vtk.generateSolidColorArray( numTuples, fixedColor) # Add the streamlines lineItem = vtk.vtkPolyDataItem() lineItem.SetPolyData(lineDataset) lineItem.SetScalarMode(vtk.VTK_SCALAR_MODE_USE_POINT_DATA) lineItem.SetMappedColors(lineColors) if deleteLineColors: lineColors.FastDelete() area.GetDrawAreaItem().AddItem(lineItem) # Add the glyphs glyphItem = vtk.vtkPolyDataItem() glyphItem.SetPolyData(glyphDataset) glyphItem.SetScalarMode(vtk.VTK_SCALAR_MODE_USE_POINT_DATA) glyphItem.SetMappedColors(glyphColors) if deleteGlyphColors: glyphColors.FastDelete() area.GetDrawAreaItem().AddItem(glyphItem) plotting_dataset_bounds = self.getPlottingBounds() vp = self._resultDict.get('ratio_autot_viewport', [ self._template.data.x1, self._template.data.x2, self._template.data.y1, self._template.data.y2 ]) kwargs = { 'vtk_backend_grid': self._vtkDataSet, 'dataset_bounds': self._vtkDataSetBounds, 'plotting_dataset_bounds': plotting_dataset_bounds, "vtk_dataset_bounds_no_mask": self._vtkDataSetBoundsNoMask, 'vtk_backend_geo': self._vtkGeoTransform, "vtk_backend_draw_area_bounds": continentBounds, "vtk_backend_viewport_scale": [self._context_xScale, self._context_yScale] } if ('ratio_autot_viewport' in self._resultDict): kwargs["ratio_autot_viewport"] = vp self._resultDict.update(self._context().renderTemplate( self._template, self._data1, self._gm, taxis, zaxis, **kwargs)) if (self._gm.coloredbyvector): self._resultDict.update(self._context().renderColorBar( self._template, self._contourLevels, self._contourColors, None, self.getColorMap())) kwargs['xaxisconvert'] = self._gm.xaxisconvert kwargs['yaxisconvert'] = self._gm.yaxisconvert if self._data1.getAxis(-1).isLongitude() and self._data1.getAxis( -2).isLatitude(): self._context().plotContinents( self._plot_kargs.get("continents", self._useContinents), plotting_dataset_bounds, projection, self._dataWrapModulo, vp, self._template.data.priority, **kwargs) self._resultDict["vtk_backend_actors"] = [[ lineItem, plotting_dataset_bounds ]] self._resultDict["vtk_backend_luts"] = [[None, None]]
def test_vcs_read_old_scr(self): testfile = os.path.join("uvcdat-testdata", "data", "vcs", "old.scr") Ns = {} for k in vcs.elements.keys(): Ns[k] = len(vcs.elements[k].keys()) vcs.scriptrun(testfile) Ns2 = {} for k in vcs.elements.keys(): Ns2[k] = len(vcs.elements[k].keys()) diffs = { 'projection': 0, 'colormap': 53, 'isofill': 187, 'marker': 0, '3d_dual_scalar': 0, 'texttable': 4, '3d_scalar': 0, 'fillarea': 234, 'font': 0, '3d_vector': 0, '1d': 9, 'template': 43, 'textcombined': 0, 'textorientation': 3, 'xvsy': 0, 'xyvsy': 0, 'isoline': 113, 'boxfill': 239, 'fontNumber': 0, 'line': 21, 'meshfill': 0, 'yxvsx': 9, 'taylordiagram': 0, 'list': 26, 'display': 0, 'vector': 55, 'scatter': 0, "streamline": 0 } for k in vcs.elements.keys(): print "---Checking number of new elements for", k self.assertEqual(diffs[k], Ns2[k] - Ns[k]) gm = vcs.getisofill("pr_time_lat_1") self.assertEqual(gm.ymtics1, "lat5") self.assertTrue(gm.ext_2) self.assertEqual(gm.fillareastyle, "solid") self.assertEqual( gm.fillareacolors, [240, 240, 240, 28, 27, 26, 25, 23, 22, 21, 20, 19, 18, 16]) gm = vcs.getboxfill("lon_lat_mjop05") self.assertEqual(gm.xmtics1, "lon5") self.assertEqual(gm.yticlabels1, "lat20") self.assertEqual(gm.datawc_x1, 30) self.assertEqual(gm.datawc_x2, 210.) self.assertEqual(gm.datawc_y1, -30) self.assertEqual(gm.datawc_y2, 30.) self.assertEqual(gm.level_1, -0.05) self.assertEqual(gm.level_2, 0.05) self.assertEqual(gm.color_1, 18) self.assertEqual(gm.color_2, 219) gm = vcs.getline("red_solid") self.assertEqual(gm.type, ['solid']) self.assertEqual(gm.color, [242]) self.assertEqual(gm.width, [2.0]) gm = vcs.getyxvsx("pr_lsfit_lat") self.assertEqual(gm.xmtics1, "lat5") self.assertEqual(gm.linecolor, 242) self.assertEqual(gm.linewidth, 2.) self.assertEqual(gm.datawc_x1, 30) self.assertEqual(gm.datawc_x2, -30.) self.assertEqual(gm.datawc_y1, -5.) self.assertEqual(gm.datawc_y2, 5.) gm = vcs.getisoline("div_anom") self.assertEqual(gm.xmtics1, "lon5") self.assertEqual(gm.xticlabels1, "lon15") self.assertEqual(gm.linetypes, [ 'dash', 'dash', 'dash', 'dash', 'solid', 'dash', 'dash', 'dash', 'solid', 'solid', 'solid', 'solid', 'solid', 'solid', 'solid', 'solid', 'solid' ]) self.assertEqual(gm.linecolors, [ 241, 241, 241, 241, 242, 241, 241, 241, 1, 1, 1, 1, 1, 1, 1, 1, 1 ]) self.assertEqual(gm.linewidths, [ 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 ]) gm = vcs.getvector("lon_lat_IO_5") self.assertEqual(gm.xmtics1, "lon5") self.assertEqual(gm.xticlabels1, "lon20") self.assertEqual(gm.linecolor, 242) self.assertEqual(gm.linewidth, 2.) self.assertEqual(gm.scale, 3) self.assertEqual(gm.reference, 5)
def _plotInternal(self): """Overrides baseclass implementation.""" # Preserve time and z axis for plotting these inof in rendertemplate projection = vcs.elements["projection"][self._gm.projection] taxis = self._originalData1.getTime() scaleFactor = 1.0 if self._originalData1.ndim > 2: zaxis = self._originalData1.getAxis(-3) else: zaxis = None scale = 1.0 lat = None lon = None latAccessor = self._data1.getLatitude() lonAccessor = self._data1.getLongitude() if latAccessor: lat = latAccessor[:] if lonAccessor: lon = lonAccessor[:] if self._vtkGeoTransform is not None: newv = vtk.vtkDoubleArray() newv.SetNumberOfComponents(3) newv.InsertTypedTuple(0, [lon.min(), lat.min(), 0]) newv.InsertTypedTuple(1, [lon.max(), lat.max(), 0]) vcs2vtk.projectArray(newv, projection, self._vtkDataSetBounds) dimMin = [0, 0, 0] dimMax = [0, 0, 0] newv.GetTypedTuple(0, dimMin) newv.GetTypedTuple(1, dimMax) maxDimX = max(dimMin[0], dimMax[0]) maxDimY = max(dimMin[1], dimMax[1]) if lat.max() != 0.0: scale = abs((maxDimY / lat.max())) if lon.max() != 0.0: temp = abs((maxDimX / lon.max())) if scale < temp: scale = temp else: scale = 1.0 # Vector attempt l = self._gm.linetype if l is None: l = "default" try: l = vcs.getline(l) lwidth = l.width[0] # noqa lcolor = l.color[0] lstyle = l.type[0] # noqa except: lstyle = "solid" # noqa lwidth = 1. # noqa lcolor = [0., 0., 0., 100.] if self._gm.linewidth is not None: lwidth = self._gm.linewidth # noqa if self._gm.linecolor is not None: lcolor = self._gm.linecolor arrow = vtk.vtkGlyphSource2D() arrow.SetGlyphTypeToArrow() arrow.SetOutputPointsPrecision(vtk.vtkAlgorithm.DOUBLE_PRECISION) arrow.FilledOff() polydata = self._vtkPolyDataFilter.GetOutput() vectors = polydata.GetPointData().GetVectors() if self._gm.scaletype == 'constant' or\ self._gm.scaletype == 'constantNNormalize' or\ self._gm.scaletype == 'constantNLinear': scaleFactor = scale * 2.0 * self._gm.scale else: scaleFactor = 1.0 glyphFilter = vtk.vtkGlyph2D() glyphFilter.SetInputData(polydata) glyphFilter.SetInputArrayToProcess(1, 0, 0, 0, "vector") glyphFilter.SetSourceConnection(arrow.GetOutputPort()) glyphFilter.SetVectorModeToUseVector() # Rotate arrows to match vector data: glyphFilter.OrientOn() glyphFilter.ScalingOn() glyphFilter.SetScaleModeToScaleByVector() if self._gm.scaletype == 'normalize' or self._gm.scaletype == 'linear' or\ self._gm.scaletype == 'constantNNormalize' or self._gm.scaletype == 'constantNLinear': # Find the min and max vector magnitudes maxNorm = vectors.GetMaxNorm() if maxNorm == 0: maxNorm = 1.0 if self._gm.scaletype == 'normalize' or self._gm.scaletype == 'constantNNormalize': scaleFactor /= maxNorm if self._gm.scaletype == 'linear' or self._gm.scaletype == 'constantNLinear': minNorm = None maxNorm = None noOfComponents = vectors.GetNumberOfComponents() for i in range(0, vectors.GetNumberOfTuples()): norm = vtk.vtkMath.Norm(vectors.GetTuple(i), noOfComponents) if (minNorm is None or norm < minNorm): minNorm = norm if (maxNorm is None or norm > maxNorm): maxNorm = norm if maxNorm == 0: maxNorm = 1.0 scalarArray = vtk.vtkDoubleArray() scalarArray.SetNumberOfComponents(1) scalarArray.SetNumberOfValues(vectors.GetNumberOfTuples()) oldRange = maxNorm - minNorm oldRange = 1.0 if oldRange == 0.0 else oldRange # New range min, max. newRangeValues = self._gm.scalerange newRange = newRangeValues[1] - newRangeValues[0] for i in range(0, vectors.GetNumberOfTuples()): norm = vtk.vtkMath.Norm(vectors.GetTuple(i), noOfComponents) newValue = (((norm - minNorm) * newRange) / oldRange) + newRangeValues[0] scalarArray.SetValue(i, newValue) polydata.GetPointData().SetScalars(scalarArray) # Scale to vector magnitude: # NOTE: Currently we compute our own scaling factor since VTK does # it by clamping the values > max to max and values < min to min # and not remap the range. glyphFilter.SetScaleModeToScaleByScalar() glyphFilter.SetScaleFactor(scaleFactor) mapper = vtk.vtkPolyDataMapper() glyphFilter.Update() data = glyphFilter.GetOutput() mapper.SetInputData(data) mapper.ScalarVisibilityOff() act = vtk.vtkActor() act.SetMapper(mapper) cmap = self.getColorMap() if isinstance(lcolor, (list, tuple)): r, g, b, a = lcolor else: r, g, b, a = cmap.index[lcolor] act.GetProperty().SetColor(r / 100., g / 100., b / 100.) plotting_dataset_bounds = vcs2vtk.getPlottingBounds( vcs.utils.getworldcoordinates(self._gm, self._data1.getAxis(-1), self._data1.getAxis(-2)), self._vtkDataSetBounds, self._vtkGeoTransform) x1, x2, y1, y2 = plotting_dataset_bounds 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]] 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_... # if geo is None: # for dp in vcs.elements['display'].values(): # if (hasattr(dp, 'backend')): # prevWc = dp.backend.get('dataset_bounds', None) # if (prevWc): # middleX = float(vp[0] + vp[1]) / 2.0 # middleY = float(vp[2] + vp[3]) / 2.0 # sideX = float(vp[1] - vp[0]) / 2.0 # sideY = float(vp[3] - vp[2]) / 2.0 # ratioX = float(prevWc[1] - prevWc[0]) / float(wc[1] - wc[0]) # ratioY = float(prevWc[3] - prevWc[2]) / float(wc[3] - wc[2]) # sideX = sideX / ratioX # sideY = sideY / ratioY # vp = [middleX - sideX, middleX + sideX, middleY - sideY, middleY + sideY] dataset_renderer, xScale, yScale = self._context().fitToViewport( act, vp, wc=wc, priority=self._template.data.priority, create_renderer=True) kwargs = { 'vtk_backend_grid': self._vtkDataSet, 'dataset_bounds': self._vtkDataSetBounds, 'plotting_dataset_bounds': plotting_dataset_bounds, "vtk_dataset_bounds_no_mask": self._vtkDataSetBoundsNoMask, 'vtk_backend_geo': self._vtkGeoTransform } if ('ratio_autot_viewport' in self._resultDict): kwargs["ratio_autot_viewport"] = vp self._resultDict.update(self._context().renderTemplate( self._template, self._data1, self._gm, taxis, zaxis, **kwargs)) if self._context().canvas._continents is None: self._useContinents = False if self._useContinents: continents_renderer, xScale, yScale = self._context( ).plotContinents(plotting_dataset_bounds, projection, self._dataWrapModulo, vp, self._template.data.priority, **kwargs) self._resultDict["vtk_backend_actors"] = [[ act, plotting_dataset_bounds ]] self._resultDict["vtk_backend_glyphfilters"] = [glyphFilter] self._resultDict["vtk_backend_luts"] = [[None, None]]