1+ # Copyright (C) 2024 - 2025 ANSYS, Inc. and/or its affiliates.
2+ # SPDX-License-Identifier: MIT
3+ #
4+ #
5+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6+ # of this software and associated documentation files (the "Software"), to deal
7+ # in the Software without restriction, including without limitation the rights
8+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+ # copies of the Software, and to permit persons to whom the Software is
10+ # furnished to do so, subject to the following conditions:
11+ #
12+ # The above copyright notice and this permission notice shall be included in all
13+ # copies or substantial portions of the Software.
14+ #
15+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+ # SOFTWARE.
22+
123"""Plotly backend interface for visualization."""
2- from ansys . tools . visualization_interface . backends . _base import BaseBackend
3- from ansys . tools . visualization_interface . types . mesh_object_plot import MeshObjectPlot
24+ from typing import Any , Iterable , Union
25+
426import plotly .graph_objects as go
527from pyvista import PolyData
6- from typing import Union , Iterable , Any
28+
29+ from ansys .tools .visualization_interface .backends ._base import BaseBackend
30+ from ansys .tools .visualization_interface .types .mesh_object_plot import MeshObjectPlot
731
832
933class PlotlyBackend (BaseBackend ):
1034 """Plotly interface for visualization."""
1135
12- def __init__ (self , ** kwargs ):
36+ def __init__ (self ) -> None :
37+ """Initialize the Plotly backend."""
1338 self ._fig = go .Figure ()
1439
1540 def _pv_to_mesh3d (self , pv_mesh : PolyData ) -> go .Mesh3d :
16- """Convert a PyVista PolyData mesh to Plotly Mesh3d format."""
41+ """Convert a PyVista PolyData mesh to Plotly Mesh3d format.
42+
43+ Parameters
44+ ----------
45+ pv_mesh : PolyData
46+ The PyVista PolyData mesh to convert.
47+
48+ Returns
49+ -------
50+ go.Mesh3d
51+ The converted Plotly Mesh3d object.
52+ """
1753 points = pv_mesh .points
1854 x , y , z = points [:, 0 ], points [:, 1 ], points [:, 2 ]
19-
55+
2056 # Convert mesh to triangular mesh if needed, since Plotly only supports triangular faces
2157 triangulated_mesh = pv_mesh .triangulate ()
22-
58+
2359 # Extract triangular faces
2460 faces = triangulated_mesh .faces .reshape ((- 1 , 4 )) # Now we know all faces are triangular (3 vertices + count)
2561 i , j , k = faces [:, 1 ], faces [:, 2 ], faces [:, 3 ]
26-
62+
2763 return go .Mesh3d (x = x , y = y , z = z , i = i , j = j , k = k )
64+
2865 @property
2966 def layout (self ) -> Any :
30- """Get the current layout of the Plotly figure."""
67+ """Get the current layout of the Plotly figure.
68+
69+ Returns
70+ -------
71+ Any
72+ The current layout of the Plotly figure.
73+ """
3174 return self ._fig .layout
3275
3376 @layout .setter
34- def layout (self , new_layout : Any ):
35- """Set a new layout for the Plotly figure."""
77+ def layout (self , new_layout : Any ) -> None :
78+ """Set a new layout for the Plotly figure.
79+
80+ Parameters
81+ ----------
82+ new_layout : Any
83+ New layout to set for the Plotly figure.
84+ """
3685 self ._fig .update_layout (new_layout )
3786
38- def plot_iter (self , plotting_list ):
39- """Plot multiple objects using Plotly."""
87+ def plot_iter (self , plotting_list : Iterable [Any ]) -> None :
88+ """Plot multiple objects using Plotly.
89+
90+ Parameters
91+ ----------
92+ plotting_list : Iterable[Any]
93+ An iterable of objects to plot.
94+ """
4095 for item in plotting_list :
4196 self .plot (item )
42-
43-
44- def plot (self , plottable_object : Union [PolyData , MeshObjectPlot , go .Mesh3d ], ** plotting_options ):
45- """Plot a single object using Plotly."""
97+
98+
99+ def plot (self , plottable_object : Union [PolyData , MeshObjectPlot , go .Mesh3d ], ** plotting_options ) -> None :
100+ """Plot a single object using Plotly.
101+
102+ Parameters
103+ ----------
104+ plottable_object : Union[PolyData, MeshObjectPlot, go.Mesh3d]
105+ The object to plot. Can be a PyVista PolyData, a MeshObjectPlot, or a Plotly Mesh3d.
106+ plotting_options : dict
107+ Additional plotting options.
108+ """
46109 if isinstance (plottable_object , PolyData ):
47110 mesh = self ._pv_to_mesh3d (plottable_object )
48111 self ._fig .add_trace (mesh )
@@ -58,19 +121,31 @@ def plot(self, plottable_object: Union[PolyData, MeshObjectPlot, go.Mesh3d], **p
58121 except Exception :
59122 raise TypeError ("Unsupported plottable_object type for PlotlyInterface." )
60123
61- def show (self ,
124+ def show (self ,
62125 plottable_object = None ,
63126 screenshot : str = None ,
64127 name_filter = None ,
65- ** kwargs ):
66- """Render the Plotly scene."""
128+ ** kwargs ) -> None :
129+ """Render the Plotly scene.
130+
131+ Parameters
132+ ----------
133+ plottable_object : Any, optional
134+ Object to show, by default None.
135+ screenshot : str, optional
136+ Path to save a screenshot, by default None.
137+ name_filter : bool, optional
138+ Flag to filter the object, by default None.
139+ kwargs : dict
140+ Additional options the selected backend accepts.
141+ """
67142 if plottable_object is not None :
68143 self .plot (plottable_object )
69-
144+
70145 # Only show in browser if no screenshot is being taken
71146 if not screenshot :
72147 self ._fig .show (** kwargs )
73-
148+
74149 if screenshot :
75150 screenshot_str = str (screenshot )
76151 if screenshot_str .endswith ('.html' ):
0 commit comments