2222"""Module for dash plotly."""
2323from typing import TYPE_CHECKING , Union
2424
25- from dash import Dash , dcc , html
25+ from dash import Dash , Input , Output , dcc , html
2626
2727from ansys .tools .visualization_interface .backends .plotly .plotly_interface import PlotlyBackend
28+ from ansys .tools .visualization_interface .backends .plotly .widgets .dropdown_manager import DashDropdownManager
2829
2930if TYPE_CHECKING :
3031 import plotly .graph_objects as go
@@ -43,6 +44,142 @@ def __init__(self, app: Dash = None) -> None:
4344 """
4445 super ().__init__ ()
4546 self ._app = app or Dash (__name__ )
47+ self ._dropdown_manager = DashDropdownManager (self ._fig )
48+ self ._setup_callbacks ()
49+
50+ @property
51+ def dropdown_manager (self ) -> DashDropdownManager :
52+ """Get the dropdown manager for this backend.
53+
54+ Returns
55+ -------
56+ DashDropdownManager
57+ The dropdown manager instance.
58+ """
59+ return self ._dropdown_manager
60+
61+ def plot (self , plottable_object , name : str = None , ** plotting_options ) -> None :
62+ """Plot a single object using Plotly and track mesh names for dropdown.
63+
64+ Parameters
65+ ----------
66+ plottable_object : Any
67+ The object to plot.
68+ name : str, optional
69+ Name of the mesh for labeling in Plotly.
70+ plotting_options : dict
71+ Additional plotting options.
72+ """
73+ # Call parent plot method
74+ super ().plot (plottable_object , name = name , ** plotting_options )
75+
76+ # Track mesh names for dropdown functionality
77+ if name :
78+ self ._dropdown_manager .add_mesh_name (name )
79+ else :
80+ # Try to get name from the latest trace added
81+ if self ._fig .data :
82+ latest_trace = self ._fig .data [- 1 ]
83+ trace_name = getattr (latest_trace , 'name' , None )
84+ if trace_name :
85+ self ._dropdown_manager .add_mesh_name (trace_name )
86+
87+ def _setup_callbacks (self ) -> None :
88+ """Setup Dash callbacks for mesh visibility control."""
89+ # Store reference to self for use in callback
90+ backend_instance = self
91+
92+ @self ._app .callback (
93+ Output ('mesh-graph' , 'figure' ),
94+ Input ('mesh-visibility-dropdown' , 'value' ),
95+ prevent_initial_call = True
96+ )
97+ def update_mesh_visibility (hidden_meshes ):
98+ """Update mesh visibility based on dropdown selection.
99+
100+ Parameters
101+ ----------
102+ hidden_meshes : List[str]
103+ List of mesh names to hide.
104+
105+ Returns
106+ -------
107+ go.Figure
108+ Updated figure with modified mesh visibility.
109+ """
110+ if hidden_meshes is None :
111+ hidden_meshes = []
112+
113+ # Get all mesh names
114+ all_mesh_names = backend_instance .dropdown_manager .get_mesh_names ()
115+ visible_mesh_names = [name for name in all_mesh_names if name not in hidden_meshes ]
116+
117+ # Create a copy of the figure to avoid modifying the original
118+ import plotly .graph_objects as go
119+ updated_fig = go .Figure (backend_instance ._fig )
120+
121+ # Update visibility for each trace
122+ for i , trace in enumerate (updated_fig .data ):
123+ trace_name = getattr (trace , 'name' , None )
124+ is_visible = trace_name in visible_mesh_names
125+ updated_fig .data [i ].visible = is_visible
126+
127+ return updated_fig
128+
129+ def create_dash_layout (self ) -> html .Div :
130+ """Create the Dash layout with optional dropdown for mesh visibility.
131+
132+ Returns
133+ -------
134+ html.Div
135+ The Dash layout component.
136+ """
137+ components = []
138+
139+ if self .dropdown_manager .get_mesh_names ():
140+ # Add dropdown for mesh visibility control
141+ mesh_names = self .dropdown_manager .get_mesh_names ()
142+ components .append (
143+ dcc .Dropdown (
144+ id = 'mesh-visibility-dropdown' ,
145+ options = [{'label' : name , 'value' : name } for name in mesh_names ],
146+ multi = True ,
147+ placeholder = "Select meshes to hide" ,
148+ searchable = True ,
149+ style = {
150+ 'width' : '280px' ,
151+ 'fontSize' : '14px'
152+ }
153+ )
154+
155+ )
156+
157+ # Add the main graph
158+ components .append (dcc .Graph (
159+ id = 'mesh-graph' ,
160+ figure = self ._fig ,
161+ style = {
162+ 'height' : '100vh' ,
163+ 'width' : '100%' ,
164+ 'margin' : '0' ,
165+ 'padding' : '0'
166+ },
167+ config = {
168+ 'responsive' : True ,
169+ 'displayModeBar' : True ,
170+ 'displaylogo' : False
171+ }
172+ ))
173+
174+ return html .Div (components , style = {
175+ 'fontFamily' : '"Open Sans", verdana, arial, sans-serif' ,
176+ 'backgroundColor' : '#ffffff' ,
177+ 'minHeight' : '100vh' ,
178+ 'width' : '100%' ,
179+ 'margin' : '0' ,
180+ 'padding' : '0' ,
181+ 'position' : 'relative'
182+ })
46183
47184 def show (self ,
48185 plottable_object = None ,
@@ -76,9 +213,8 @@ def show(self,
76213
77214 # Only show in browser if no screenshot is being taken
78215 if not screenshot :
79- self ._app .layout = html .Div ([
80- dcc .Graph (figure = self ._fig )
81- ])
216+ # Always use the create_dash_layout method to ensure dropdown is included when enabled
217+ self ._app .layout = self .create_dash_layout ()
82218 self ._app .run ()
83219
84220 else :
0 commit comments