New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BUG #1811: Show point information for plots using geographic projecti… #1878
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,18 +45,27 @@ def __init__(self, canvas, renWin=None, debug=False, bg=None, geometry=None): | |
self.renderer = None | ||
self._renderers = {} | ||
self._plot_keywords = [ | ||
'renderer', | ||
'vtk_backend_grid', | ||
'cdmsfile', | ||
'cell_coordinates' | ||
# used to render the continents | ||
'continents_renderer', | ||
# dataset bounds in lon/lat coordinates | ||
'dataset_bounds', | ||
# 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', | ||
# this may be slightly smaller than the data viewport. It is used | ||
# for vectorpipeline when drawn on top of a boxfill for instance | ||
'dataset_viewport', | ||
# used to render the dataset | ||
'dataset_renderer', | ||
# dataset scale: (xScale, yScale) | ||
'dataset_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', | ||
'renderer', | ||
'vtk_backend_grid', | ||
# vtkGeoTransform used for geographic transformation | ||
'vtk_backend_geo', | ||
'cdmsfile', | ||
'cell_coordinates'] | ||
] | ||
self.numberOfPlotCalls = 0 | ||
self.renderWindowSize = None | ||
self.clickRenderer = None | ||
|
@@ -131,47 +140,97 @@ def leftButtonPressEvent(self, obj, event): | |
continue | ||
t = vcs.elements["template"][d.template] | ||
gm = vcs.elements[d.g_type][d.g_name] | ||
if gm.projection != "linear": | ||
return | ||
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] | ||
# 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @danlipsa why field association? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because we want cellids which will give us cell scalars. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I see thanks. So are we not looking for point scalars in this case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is correct. For point data, the user has to click fairly close the a point to see the value. I have to experiment with that, I am not sure. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Do we have test for it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not implemented yet. I'll do it together with or after There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @aashish24 See #1885 |
||
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: | ||
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: | ||
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] | ||
else: | ||
V = V.flat[0] | ||
else: | ||
V = V.flat[0] | ||
try: | ||
st += "Var: %s\nX[%i] = %g\nY[%i] = %g\nValue: %g" % ( | ||
d.array[0].id, I, X, J, Y, V) | ||
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[%i] = %g\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) | ||
st += "Var: %s\nX=%g\nY=%g\nValue = N/A" % ( | ||
d.array[0].id, X, Y) | ||
if st == "": | ||
return | ||
ren = vtk.vtkRenderer() | ||
|
@@ -740,13 +799,12 @@ def plotContinents(self, wc, projection, wrap, vp, priority, **kargs): | |
# Stippling | ||
vcs2vtk.stippleLine(line_prop, contLine.type[0]) | ||
vtk_backend_grid = kargs.get("vtk_backend_grid", None) | ||
self.fitToViewportBounds(contActor, | ||
vp, | ||
wc=wc, geo=geo, | ||
geoBounds=vtk_backend_grid.GetBounds(), | ||
priority=priority, | ||
create_renderer=True) | ||
return {} | ||
return self.fitToViewportBounds(contActor, | ||
vp, | ||
wc=wc, geo=geo, | ||
geoBounds=vtk_backend_grid.GetBounds(), | ||
priority=priority, | ||
create_renderer=True) | ||
|
||
def renderTemplate(self, tmpl, data, gm, taxis, zaxis, **kargs): | ||
# ok first basic template stuff, let's store the displays | ||
|
@@ -1199,7 +1257,7 @@ def fitToViewportBounds(self, Actor, vp, wc=None, geoBounds=None, geo=None, prio | |
|
||
# Data range in World Coordinates | ||
if priority == 0: | ||
return None | ||
return (None, 1, 1) | ||
vp = tuple(vp) | ||
if wc is None: | ||
Xrg = list(Actor.GetXRange()) | ||
|
@@ -1315,7 +1373,7 @@ def fitToViewportBounds(self, Actor, vp, wc=None, geoBounds=None, geo=None, prio | |
plane = planeCollection.GetNextItem() | ||
|
||
Renderer.AddActor(Actor) | ||
return Renderer | ||
return (Renderer, xScale, yScale) | ||
|
||
def update_input(self, vtkobjects, array1, array2=None, update=True): | ||
if "vtk_backend_grid" in vtkobjects: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -507,6 +507,10 @@ def genGrid(data1, data2, gm, deep=True, grid=None, geo=None): | |
vg.SetPoints(geopts) | ||
else: | ||
vg = grid | ||
# Add a GlobalIds array to keep track of cell ids throughout the pipeline | ||
globalIds = numpy_to_vtk_wrapper(numpy.arange(0, vg.GetNumberOfCells()), deep=True) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @danlipsa why we have to do this? Meaning why we have to explicitly append the global ids? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because the hardware selector renders and gets the cell ids of the geometry which are not usually the same as the cell ids of the dataset. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
this is interesting. But by default should they be same? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you mean 'by default'? In the uvcdat case we have threshold + different mapper for different scalar ranges so the ids are not the dataset ids. If you have only the dataset in the pipeline I think only the polydata will not change ids. Maybe there are others but I would not bet on it :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I see. yeah, I won't either. |
||
globalIds.SetName('GlobalIds') | ||
vg.GetCellData().SetGlobalIds(globalIds) | ||
out = {"vtk_backend_grid": vg, | ||
"xm": xm, | ||
"xM": xM, | ||
|
@@ -867,6 +871,9 @@ def doWrap(Act, wc, wrap=[0., 360], fastClip=True): | |
return Act | ||
Mapper = Act.GetMapper() | ||
data = Mapper.GetInput() | ||
# insure that GLOBALIDS are not removed by the append filter | ||
attributes = data.GetCellData() | ||
attributes.SetActiveAttribute(-1, attributes.GLOBALIDS) | ||
xmn = min(wc[0], wc[1]) | ||
xmx = max(wc[0], wc[1]) | ||
if numpy.allclose(xmn, 1.e20) or numpy.allclose(xmx, 1.e20): | ||
|
@@ -878,7 +885,6 @@ def doWrap(Act, wc, wrap=[0., 360], fastClip=True): | |
ymx = abs(wrap[0]) | ||
ymn = -wrap[0] | ||
|
||
# Prepare MultiBlock and puts in oriinal data | ||
appendFilter = vtk.vtkAppendPolyData() | ||
appendFilter.AddInputData(data) | ||
appendFilter.Update() | ||
|
@@ -954,6 +960,11 @@ def doWrap(Act, wc, wrap=[0., 360], fastClip=True): | |
clipper.SetClipFunction(clipBox) | ||
clipper.SetInputConnection(appendFilter.GetOutputPort()) | ||
clipper.Update() | ||
# set globalids attribute | ||
attributes = clipper.GetOutput().GetCellData() | ||
globalIdsIndex = vtk.mutable(-1) | ||
attributes.GetArray("GlobalIds", globalIdsIndex) | ||
attributes.SetActiveAttribute(globalIdsIndex, attributes.GLOBALIDS) | ||
|
||
Mapper.SetInputData(clipper.GetOutput()) | ||
return Act | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@danlipsa why not use the same code (under if) for both cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because this code does not work now for isofill, isoline and vectors. When we fix dataset creation we can get rid of the vcs code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@danlipsa thanks. And I guess we have an issue for it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we do:
#1881
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks @danlipsa