11import dash
2- from dash import html , callback , Input , Output , dcc
2+ from dash import html , callback , Input , Output , State , dcc
33import dash_cytoscape as cyto
44import dash_mantine_components as dmc
55from dash_iconify import DashIconify
9797def family_tree_cytsocape ():
9898 """
9999 Generates a Dash Cytoscape component representing the family tree.
100+ Wrapped in a LoadingOverlay component.
100101
101102 Returns:
102- dash_cytoscape.Cytoscape : Dash Cytoscape component representing the family tree .
103+ dash_mantine_components.LoadingOverlay : Dash Mantine LoadingOverlay component wrapping the Cytoscape component .
103104 """
104- return cyto .Cytoscape (
105- id = "cytoscape-family-tree" ,
106- className = "wrapper" ,
107- style = {"height" : "450px" , "max-width" : "100%" },
108- stylesheet = CYTOSCAPE_STYLE ,
105+ return html .Div (
106+ [
107+ dmc .LoadingOverlay (
108+ cyto .Cytoscape (
109+ id = "cytoscape-family-tree" ,
110+ className = "wrapper" ,
111+ style = {"height" : "430px" , "max-width" : "100%" },
112+ stylesheet = CYTOSCAPE_STYLE ,
113+ ),
114+ id = "family-tree-loading" ,
115+ #loaderProps={"color": "#262626", "size": "xl", "variant": "dots"},
116+ overlayOpacity = 0 , # Transparent background
117+ overlayColor = "transparent" , # Transparent color
118+ overlayBlur = 2 , # Add blur effect (values typically range from 1-5)
119+ )
120+ ],
121+ id = "cytoscape-container"
109122 )
110123
111124
@@ -121,25 +134,28 @@ def generation_slider():
121134 run , generations_int [round (len (generations_int ) / 3 )]
122135 )
123136
124- return dcc .RangeSlider (
125- min (generations_int ),
126- max (generations_int ),
127- 1 ,
128- marks = {
129- min (generations_int ): {
130- "label" : f"Generation_{ min (generations_int )} " ,
131- "style" : MARKS_STYLE ,
132- },
133- max (generations_int ): {
134- "label" : f"Generation_{ max (generations_int )} " ,
135- "style" : MARKS_STYLE ,
137+ return html .Div (
138+ dcc .RangeSlider (
139+ min (generations_int ),
140+ max (generations_int ),
141+ 1 ,
142+ marks = {
143+ min (generations_int ): {
144+ "label" : f"Generation_{ min (generations_int )} " ,
145+ "style" : MARKS_STYLE ,
146+ },
147+ max (generations_int ): {
148+ "label" : f"Generation_{ max (generations_int )} " ,
149+ "style" : MARKS_STYLE ,
150+ },
136151 },
137- },
138- # pushable=1,
139- allowCross = False ,
140- id = "gen-range-slider" ,
141- tooltip = {"placement" : "top" , "always_visible" : True },
142- value = [random_generation - 4 , random_generation , random_generation + 1 ],
152+ # pushable=1,
153+ allowCross = False ,
154+ id = "gen-range-slider" ,
155+ tooltip = {"placement" : "top" , "always_visible" : True },
156+ value = [random_generation - 4 , random_generation , random_generation + 1 ],
157+ ),
158+ style = {"margin-top" : "12px" } # Add padding/margin at the top of the slider so not blurred by family tree laoding
143159 )
144160
145161
@@ -195,17 +211,40 @@ def set_individuals_select(gen_range):
195211
196212
197213@callback (
198- Output ("cytoscape-family-tree" , "elements" ),
199- Output ("cytoscape-family-tree" , "layout" ),
200- Output ("cytoscape-family-tree" , "stylesheet" ),
201- Input ("gen-range-slider" , "value" ),
202- Input ("ind-select" , "value" ),
203- Input ("cytoscape-family-tree" , "tapNodeData" ),
204- Input ("cytoscape-family-tree" , "tapEdgeData" ),
214+ Output ("family-tree-loading" , "loader" ),
215+ [Input ("gen-range-slider" , "value" ),
216+ Input ("ind-select" , "value" )],
217+ )
218+ def show_loading_indicator (gen_range , ind ):
219+ """
220+ Shows the loading indicator when input values change.
221+ In dash_mantine_components 0.12.0, we toggle the loader prop to show/hide loading.
222+
223+ Args:
224+ gen_range (list): Selected generation range.
225+ ind (str): Selected individual.
226+
227+ Returns:
228+ component: Loading spinner component to show
229+ """
230+ return dmc .Loader (color = "#6173E9" , size = "xl" , variant = "dots" )
231+
232+
233+ @callback (
234+ Output ("family-tree-loading" , "loader" , allow_duplicate = True ),
235+ [Output ("cytoscape-family-tree" , "elements" ),
236+ Output ("cytoscape-family-tree" , "layout" ),
237+ Output ("cytoscape-family-tree" , "stylesheet" )],
238+ [Input ("gen-range-slider" , "value" ),
239+ Input ("ind-select" , "value" ),
240+ Input ("cytoscape-family-tree" , "tapNodeData" ),
241+ Input ("cytoscape-family-tree" , "tapEdgeData" )],
242+ prevent_initial_call = True ,
205243)
206244def set_cytoscape (gen_range , ind , ind_clicked , edge_clicked ):
207245 """
208246 Sets the elements, layout, and stylesheet for the family tree visualization based on user interactions.
247+ Also hides the loading overlay when finished.
209248
210249 Args:
211250 gen_range (list): List containing the selected generation (idx 1) and minimum (idx 0), maximum (idx 2) generation values selected on the RangeSlider.
@@ -214,11 +253,11 @@ def set_cytoscape(gen_range, ind, ind_clicked, edge_clicked):
214253 edge_clicked (dict): Data of the edge clicked on the Cytoscape component.
215254
216255 Returns:
256+ None: To hide the loader
217257 list: Nodes and edges of Cytoscape component.
218258 dict: Layout configuration for the Cytoscape component.
219259 list: Stylesheet for the Cytoscape component.
220260 """
221-
222261 # Get Family tree through individual selection
223262 generation_range = range (gen_range [0 ], gen_range [2 ] + 1 )
224263 gen = gen_range [1 ]
@@ -291,7 +330,8 @@ def set_cytoscape(gen_range, ind, ind_clicked, edge_clicked):
291330 }
292331 )
293332
294- return elements , cytoscape_layout , new_cytoscape_style
333+ # Set loading overlay to None to hide it
334+ return None , elements , cytoscape_layout , new_cytoscape_style
295335
296336
297337@callback (
@@ -503,4 +543,4 @@ def family_tree_layout():
503543 return layout
504544
505545
506- layout = family_tree_layout
546+ layout = family_tree_layout
0 commit comments