From 536cc7c126f59346b2b65ddc9075305e677edb43 Mon Sep 17 00:00:00 2001 From: Berk Geveci Date: Thu, 17 Sep 2026 11:34:24 -0400 Subject: [PATCH] fix(paraview): keep plugins working on newer ParaView/VTK Three APIs the plugins relied on changed in VTK 9.7, and each failed in a way that pointed somewhere unhelpful: - vtkUnstructuredGrid.points returns a vtkPoints subclass, where it used to hand back a numpy array. EAMProject died on .flatten(), and EAMSphere assigned an ndarray straight back to .points, which SetPoints now refuses. Both go through numpy_support instead. - GetCellTypesArray() is gone; GetCellTypes() returns that array now. A small _cell_types_array() helper prefers the old name when present. - vtkTrackballPan is no longer exported from vtkPVVTKExtensionsInteractionStyle; vtkPVTrackballPan is the survivor, and it exists in 6.0 as well. All of it is backward compatible. Verified against ParaView 6.0.1 (VTK 9.5.2) and ParaView master (VTK 9.7): identical pg2 output, full and cropped. --- src/e3sm_quickview/plugins/eam_projection.py | 26 +++++++++++++++++--- src/e3sm_quickview/view_manager.py | 4 +-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/e3sm_quickview/plugins/eam_projection.py b/src/e3sm_quickview/plugins/eam_projection.py index cbeb34e..a6fc9b8 100644 --- a/src/e3sm_quickview/plugins/eam_projection.py +++ b/src/e3sm_quickview/plugins/eam_projection.py @@ -110,6 +110,16 @@ def timed(label): yield +def _cell_types_array(grid): + """Per-cell type array, across VTK versions. + + VTK 9.7 dropped `GetCellTypesArray()`; `GetCellTypes()` now returns that + array, where it used to fill a vtkCellTypes passed in by the caller. + """ + getter = getattr(grid, "GetCellTypesArray", None) + return getter() if getter is not None else grid.GetCellTypes() + + def ProcessPoint(point, radius): # theta = math.radians(point[0] - 180.) # phi = math.radians(point[1]) @@ -256,10 +266,16 @@ def RequestData(self, request, inInfo, outInfo): else: outData.DeepCopy(inData) - inPoints = inData.points + inPoints = numpy_support.vtk_to_numpy(inData.GetPoints().GetData()) pRadius = (self.radius + 1) if self.isData else self.radius outPoints = np.array(list(map(lambda x: ProcessPoint(x, pRadius), inPoints))) - outData.points = outPoints + vtk_coords = vtkPoints() + vtk_coords.SetData( + numpy_support.numpy_to_vtk( + outPoints, deep=True, array_type=vtkConstants.VTK_FLOAT + ) + ) + outData.SetPoints(vtk_coords) return 1 @@ -443,7 +459,9 @@ def RequestData(self, request, inInfo, outInfo): out_points_vtk = vtkPoints() out_points_vtk.DeepCopy(outData.GetPoints()) outData.SetPoints(out_points_vtk) - out_points_np = outData.points + out_points_np = numpy_support.vtk_to_numpy( + outData.GetPoints().GetData() + ) flat = out_points_np.flatten() x = flat[0::3] - 180.0 if self.translate else flat[0::3] @@ -696,7 +714,7 @@ def RequestData(self, request, inInfo, outInfo): cells = vtkCellArray() cell_types = vtkUnsignedCharArray() cells.DeepCopy(outData.GetCells()) - cell_types.DeepCopy(outData.GetCellTypesArray()) + cell_types.DeepCopy(_cell_types_array(outData)) outData.SetCells(cell_types, cells) # Crop against absolute lon/lat ranges, in the same diff --git a/src/e3sm_quickview/view_manager.py b/src/e3sm_quickview/view_manager.py index 9e4fa5c..fa28744 100644 --- a/src/e3sm_quickview/view_manager.py +++ b/src/e3sm_quickview/view_manager.py @@ -4,8 +4,8 @@ from paraview.modules.vtkPVVTKExtensionsInteractionStyle import ( vtkPVInteractorStyle, + vtkPVTrackballPan, vtkPVTrackballZoom, - vtkTrackballPan, ) from trame.app import TrameComponent from trame.decorators import controller @@ -84,7 +84,7 @@ def __init__(self, server, source): ) ) self._style.AddManipulator( - vtkTrackballPan( + vtkPVTrackballPan( button=1, shift=0, control=0,