@@ -204,6 +204,8 @@ def kwarg_to_ipywidget(key, val, update, slider_format_string, play_button=None)
204
204
The generated widget. This may be the raw widget or a higher level container
205
205
widget (e.g. HBox) depending on what widget was generated. If a fixed value is
206
206
returned then control will be *None*
207
+ param_hash :
208
+ A hash of the possible values, to be used to check duplicates in the future.
207
209
"""
208
210
control = None
209
211
if isinstance (val , set ):
@@ -214,7 +216,7 @@ def kwarg_to_ipywidget(key, val, update, slider_format_string, play_button=None)
214
216
pass
215
217
else :
216
218
# fixed parameter
217
- return val , None
219
+ return val , None , hash ( repr ( val ))
218
220
else :
219
221
val = list (val )
220
222
@@ -224,15 +226,15 @@ def kwarg_to_ipywidget(key, val, update, slider_format_string, play_button=None)
224
226
else :
225
227
selector = widgets .Select (options = val )
226
228
selector .observe (partial (update , values = val ), names = "index" )
227
- return val [0 ], selector
229
+ return val [0 ], selector , hash ( repr ( val ))
228
230
elif isinstance (val , widgets .Widget ) or isinstance (val , widgets .fixed ):
229
231
if not hasattr (val , "value" ):
230
232
raise TypeError (
231
233
"widgets passed as parameters must have the `value` trait."
232
234
"But the widget passed for {key} does not have a `.value` attribute"
233
235
)
234
236
if isinstance (val , widgets .fixed ):
235
- return val , None
237
+ return val , None , hash ( repr ( val ))
236
238
elif (
237
239
isinstance (val , widgets .Select )
238
240
or isinstance (val , widgets .SelectionSlider )
@@ -242,10 +244,11 @@ def kwarg_to_ipywidget(key, val, update, slider_format_string, play_button=None)
242
244
# it looks unlikely to change but still would be nice to just check
243
245
# if its a subclass
244
246
val .observe (partial (update , values = val .options ), names = "index" )
247
+ return val .value , val , hash (repr (val .options ))
245
248
else :
246
249
# set values to None and hope for the best
247
250
val .observe (partial (update , values = None ), names = "value" )
248
- return val .value , val
251
+ return val .value , val , hash ( repr ( val ))
249
252
# val.observe(partial(update, key=key, label=None), names=["value"])
250
253
else :
251
254
if isinstance (val , tuple ) and val [0 ] in ["r" , "range" , "rang" , "rage" ]:
@@ -267,7 +270,7 @@ def kwarg_to_ipywidget(key, val, update, slider_format_string, play_button=None)
267
270
)
268
271
slider .observe (partial (update , values = vals ), names = "value" )
269
272
controls = widgets .HBox ([slider , label ])
270
- return vals [[0 , - 1 ]], controls
273
+ return vals [[0 , - 1 ]], controls , hash ( "r" + repr ( vals ))
271
274
272
275
if isinstance (val , tuple ) and len (val ) in [2 , 3 ]:
273
276
# treat as an argument to linspace
@@ -279,7 +282,7 @@ def kwarg_to_ipywidget(key, val, update, slider_format_string, play_button=None)
279
282
raise ValueError (f"{ key } is { val .ndim } D but can only be 1D or a scalar" )
280
283
if len (val ) == 1 :
281
284
# don't need to create a slider
282
- return val [0 ], None
285
+ return val [0 ], None , hash ( repr ( val ))
283
286
else :
284
287
# params[key] = val[0]
285
288
label = widgets .Label (value = slider_format_string .format (val [0 ]))
@@ -299,7 +302,7 @@ def kwarg_to_ipywidget(key, val, update, slider_format_string, play_button=None)
299
302
control = widgets .HBox ([play , slider , label ])
300
303
else :
301
304
control = widgets .HBox ([slider , label ])
302
- return val [0 ], control
305
+ return val [0 ], control , hash ( repr ( val ))
303
306
304
307
305
308
def extract_num_options (val ):
@@ -455,17 +458,19 @@ def process_mpl_widget(val, update):
455
458
# oh boy do I ever not want to
456
459
val .set_active (0 )
457
460
cb = val .on_clicked (partial (changeify_radio , labels = val .labels , update = update ))
458
- return val .labels [0 ], val , cb
459
- elif isinstance (val , (mwidgets .Slider , RangeSlider )):
461
+ return val .labels [0 ], val , cb , hash (repr (val .labels ))
462
+ elif isinstance (val , (mwidgets .Slider , mwidgets .RangeSlider , RangeSlider )):
463
+ # TODO: proper inherit matplotlib rand
460
464
# potential future improvement:
461
465
# check if valstep has been set and then try to infer the values
462
466
# but not now, I'm trying to avoid premature optimization lest this
463
467
# drag on forever
464
468
cb = val .on_changed (partial (changeify , update = partial (update , values = None )))
465
- return val .val , val , cb
469
+ hash_ = hash (str (val .valmin ) + str (val .valmax ) + str (val .valstep ))
470
+ return val .val , val , cb , hash_
466
471
else :
467
472
cb = val .on_changed (partial (changeify , update = partial (update , values = None )))
468
- return val .val , val , cb
473
+ return val .val , val , cb , hash ( repr ( val ))
469
474
470
475
471
476
def kwarg_to_mpl_widget (
@@ -512,6 +517,7 @@ def kwarg_to_mpl_widget(
512
517
the callback id
513
518
new_y
514
519
The widget_y to use for the next pass.
520
+ hash
515
521
"""
516
522
slider_height , radio_height , gap_height = heights
517
523
@@ -525,7 +531,7 @@ def kwarg_to_mpl_widget(
525
531
if isinstance (val , tuple ):
526
532
pass
527
533
else :
528
- return val , None , None , widget_y
534
+ return val , None , None , widget_y , hash ( repr ( val ))
529
535
else :
530
536
val = list (val )
531
537
@@ -537,10 +543,10 @@ def kwarg_to_mpl_widget(
537
543
widget_y += radio_height * n + gap_height
538
544
radio_buttons = mwidgets .RadioButtons (radio_ax , val , active = 0 )
539
545
cb = radio_buttons .on_clicked (partial (changeify_radio , labels = val , update = update ))
540
- return val [0 ], radio_buttons , cb , widget_y
546
+ return val [0 ], radio_buttons , cb , widget_y , hash ( repr ( val ))
541
547
elif isinstance (val , mwidgets .AxesWidget ):
542
- val , widget , cb = process_mpl_widget (val , update )
543
- return val , widget , cb , widget_y
548
+ val , widget , cb , hash_ = process_mpl_widget (val , update )
549
+ return val , widget , cb , widget_y , hash_
544
550
else :
545
551
slider = None
546
552
if isinstance (val , tuple ) and val [0 ] in ["r" , "range" , "rang" , "rage" ]:
@@ -552,7 +558,7 @@ def kwarg_to_mpl_widget(
552
558
slider = create_mpl_range_selection_slider (slider_ax , key , vals , slider_format_string )
553
559
cb = slider .on_changed (partial (changeify , update = partial (update , values = vals )))
554
560
widget_y += slider_height + gap_height
555
- return vals [[0 , - 1 ]], slider , cb , widget_y
561
+ return vals [[0 , - 1 ]], slider , cb , widget_y , hash ( repr ( vals ))
556
562
557
563
if isinstance (val , tuple ):
558
564
if len (val ) == 2 :
@@ -569,7 +575,7 @@ def update_text(val):
569
575
slider .on_changed (update_text )
570
576
cb = slider .on_changed (partial (changeify , update = partial (update , values = None )))
571
577
widget_y += slider_height + gap_height
572
- return min_ , slider , cb , widget_y
578
+ return min_ , slider , cb , widget_y , hash ( repr ( val ))
573
579
elif len (val ) == 3 :
574
580
# should warn that that doesn't make sense with matplotlib sliders
575
581
min_ = val [0 ]
@@ -580,13 +586,13 @@ def update_text(val):
580
586
raise ValueError (f"{ key } is { val .ndim } D but can only be 1D or a scalar" )
581
587
if len (val ) == 1 :
582
588
# don't need to create a slider
583
- return val [0 ], None , None , widget_y
589
+ return val [0 ], None , None , widget_y , hash ( repr ( val ))
584
590
else :
585
591
slider_ax = fig .add_axes ([0.2 , 0.9 - widget_y - gap_height , 0.65 , slider_height ])
586
592
slider = create_mpl_selection_slider (slider_ax , key , val , slider_format_string )
587
593
slider .on_changed (partial (changeify , update = partial (update , values = val )))
588
594
widget_y += slider_height + gap_height
589
- return val [0 ], slider , None , widget_y
595
+ return val [0 ], slider , None , widget_y , hash ( repr ( val ))
590
596
591
597
592
598
def create_slider_format_dict (slider_format_string ):
0 commit comments