syd 0.1.7__py3-none-any.whl → 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
syd/viewer.py CHANGED
@@ -4,36 +4,17 @@ import inspect
4
4
  from contextlib import contextmanager
5
5
  from matplotlib.figure import Figure
6
6
 
7
- from .parameters import (
8
- ParameterType,
9
- ActionType,
10
- Parameter,
11
- ParameterAddError,
12
- ParameterUpdateError,
13
- )
7
+ from .parameters import ParameterType, ActionType, Parameter
8
+ from .support import NoUpdate, NoInitialValue, ParameterAddError, ParameterUpdateError
14
9
 
15
-
16
- class _NoUpdate:
17
- """Singleton class to represent a non-update in parameter operations."""
18
-
19
- _instance = None
20
-
21
- def __new__(cls):
22
- if cls._instance is None:
23
- cls._instance = super().__new__(cls)
24
- return cls._instance
25
-
26
- def __eq__(self, other):
27
- """This makes sure all comparisons of _NoUpdate objects return True"""
28
- return isinstance(other, _NoUpdate)
29
-
30
-
31
- # Create the singleton instance
32
- _NO_UPDATE = _NoUpdate()
10
+ # Create the singleton instances
11
+ NO_UPDATE = NoUpdate()
12
+ NO_INITIAL_VALUE = NoInitialValue()
33
13
 
34
14
 
35
15
  def validate_parameter_operation(
36
- operation: str, parameter_type: Union[ParameterType, ActionType]
16
+ operation: str,
17
+ parameter_type: Union[ParameterType, ActionType],
37
18
  ) -> Callable:
38
19
  """
39
20
  Decorator that validates parameter operations for the viewer class.
@@ -112,15 +93,7 @@ def validate_parameter_operation(
112
93
  msg = f"Parameter called {name} was found but is registered as a different parameter type ({type(self.parameters[name])}). Expecting {parameter_type.value}."
113
94
  raise ParameterUpdateError(name, parameter_type.name, msg)
114
95
 
115
- try:
116
- return func(self, name, *args, **kwargs)
117
- except Exception as e:
118
- if operation == "add":
119
- raise ParameterAddError(name, parameter_type.name, str(e))
120
- elif operation == "update":
121
- raise ParameterUpdateError(name, parameter_type.name, str(e))
122
- else:
123
- raise e
96
+ return func(self, name, *args, **kwargs)
124
97
 
125
98
  return wrapper
126
99
 
@@ -152,7 +125,7 @@ class Viewer:
152
125
  ... self.update_float('x', value=state['x'])
153
126
  ...
154
127
  >>> viewer = MyViewer()
155
- >>> viewer.add_float('x', value=1.0, min_value=0, max_value=10)
128
+ >>> viewer.add_float('x', value=1.0, min=0, max=10)
156
129
  >>> viewer.on_change('x', viewer.update_based_on_x)
157
130
  """
158
131
 
@@ -182,7 +155,7 @@ class Viewer:
182
155
 
183
156
  Examples
184
157
  --------
185
- >>> viewer.add_float('x', value=1.0, min_value=0, max_value=10)
158
+ >>> viewer.add_float('x', value=1.0, min=0, max=10)
186
159
  >>> viewer.add_text('label', value='data')
187
160
  >>> viewer.state
188
161
  {'x': 1.0, 'label': 'data'}
@@ -241,36 +214,31 @@ class Viewer:
241
214
 
242
215
  def deploy(self, env: str = "notebook", **kwargs):
243
216
  """Deploy the app in a notebook or standalone environment"""
217
+ env = env.lower()
244
218
  if env == "notebook":
245
- from .notebook_deployment import NotebookDeployer
219
+ # On demand import because the deployers need to import the viewer
220
+ from .notebook_deployment.deployer import NotebookDeployer
246
221
 
247
222
  deployer = NotebookDeployer(self, **kwargs)
248
223
  deployer.deploy()
249
224
  return self
250
225
 
251
- elif env == "plotly":
252
- from .plotly_deployment import PlotlyDeployer
253
-
254
- deployer = PlotlyDeployer(self, **kwargs)
255
- deployer.deploy(mode="server")
256
- return self
257
-
258
- elif env == "plotly-inline":
259
- from .plotly_deployment import PlotlyDeployer
260
-
261
- deployer = PlotlyDeployer(self, **kwargs)
262
- deployer.deploy(mode="notebook")
263
- return self
226
+ elif env == "browser" or env == "flask":
227
+ # On demand import because the deployers need to import the viewer
228
+ from .flask_deployment.deployer import FlaskDeployer
264
229
 
265
- elif env == "flask":
266
- from .flask_deployment import FlaskDeployer
230
+ if "port" not in kwargs:
231
+ kwargs["port"] = None
232
+ if "continuous" in kwargs:
233
+ kwargs.pop("continuous")
267
234
 
268
235
  deployer = FlaskDeployer(self, **kwargs)
269
236
  deployer.deploy()
270
237
  return self
238
+
271
239
  else:
272
240
  raise ValueError(
273
- f"Unsupported environment: {env}, only 'notebook', 'plotly', 'plotly-inline', and 'flask' are supported right now."
241
+ f"Unsupported environment: {env}, only 'notebook', 'flask'/'browser' are supported right now."
274
242
  )
275
243
 
276
244
  @contextmanager
@@ -483,8 +451,25 @@ class Viewer:
483
451
  self.perform_callbacks(name)
484
452
 
485
453
  # -------------------- parameter registration methods --------------------
454
+ def remove_parameter(self, name: str) -> None:
455
+ """
456
+ Remove a parameter from the viewer.
457
+
458
+ Parameters
459
+ ----------
460
+ name : str
461
+ Name of the parameter to remove
462
+ """
463
+ if name in self.parameters:
464
+ del self.parameters[name]
465
+
486
466
  @validate_parameter_operation("add", ParameterType.text)
487
- def add_text(self, name: str, *, value: str) -> None:
467
+ def add_text(
468
+ self,
469
+ name: str,
470
+ *,
471
+ value: Union[str, NoInitialValue] = NO_INITIAL_VALUE,
472
+ ) -> None:
488
473
  """
489
474
  Add a text input parameter to the viewer.
490
475
 
@@ -495,8 +480,9 @@ class Viewer:
495
480
  ----------
496
481
  name : str
497
482
  Name of the parameter (used as label in GUI)
498
- value : str
483
+ value : Union[str, NoInitialValue]
499
484
  Initial text value
485
+ If not provided, the parameter will be empty.
500
486
 
501
487
  Examples
502
488
  --------
@@ -512,7 +498,12 @@ class Viewer:
512
498
  self.parameters[name] = new_param
513
499
 
514
500
  @validate_parameter_operation("add", ParameterType.boolean)
515
- def add_boolean(self, name: str, *, value: bool) -> None:
501
+ def add_boolean(
502
+ self,
503
+ name: str,
504
+ *,
505
+ value: Union[bool, NoInitialValue] = NO_INITIAL_VALUE,
506
+ ) -> None:
516
507
  """
517
508
  Add a boolean parameter to the viewer.
518
509
 
@@ -523,8 +514,9 @@ class Viewer:
523
514
  ----------
524
515
  name : str
525
516
  Name of the parameter (used as label in GUI)
526
- value : bool
517
+ value : Union[bool, NoInitialValue]
527
518
  Initial state (True=checked, False=unchecked)
519
+ If not provided, the parameter will be checked.
528
520
 
529
521
  Examples
530
522
  --------
@@ -540,7 +532,13 @@ class Viewer:
540
532
  self.parameters[name] = new_param
541
533
 
542
534
  @validate_parameter_operation("add", ParameterType.selection)
543
- def add_selection(self, name: str, *, value: Any, options: List[Any]) -> None:
535
+ def add_selection(
536
+ self,
537
+ name: str,
538
+ *,
539
+ value: Union[Any, NoInitialValue] = NO_INITIAL_VALUE,
540
+ options: List[Any],
541
+ ) -> None:
544
542
  """
545
543
  Add a single-selection parameter to the viewer.
546
544
 
@@ -572,7 +570,11 @@ class Viewer:
572
570
 
573
571
  @validate_parameter_operation("add", ParameterType.multiple_selection)
574
572
  def add_multiple_selection(
575
- self, name: str, *, value: List[Any], options: List[Any]
573
+ self,
574
+ name: str,
575
+ *,
576
+ value: Union[List[Any], NoInitialValue] = NO_INITIAL_VALUE,
577
+ options: List[Any],
576
578
  ) -> None:
577
579
  """
578
580
  Add a multiple-selection parameter to the viewer.
@@ -585,8 +587,9 @@ class Viewer:
585
587
  ----------
586
588
  name : str
587
589
  Name of the parameter (used as label in GUI)
588
- value : list
590
+ value : Union[list, NoInitialValue]
589
591
  Initially selected values (must all be in options)
592
+ If not provided, the parameter will be empty.
590
593
  options : list
591
594
  List of values that can be selected
592
595
 
@@ -610,46 +613,38 @@ class Viewer:
610
613
  self,
611
614
  name: str,
612
615
  *,
613
- value: Union[float, int],
614
- min_value: Union[float, int],
615
- max_value: Union[float, int],
616
+ value: Union[Union[float, int], NoInitialValue] = NO_INITIAL_VALUE,
617
+ min: Union[float, int],
618
+ max: Union[float, int],
616
619
  ) -> None:
617
620
  """
618
621
  Add an integer parameter to the viewer.
619
622
 
620
- Creates a slider in the GUI that lets users select whole numbers between
621
- min_value and max_value. Values will be clamped to stay within bounds.
623
+ Creates a slider to select whole numbers between a minimum and maximum.
622
624
  See :class:`~syd.parameters.IntegerParameter` for details.
623
625
 
624
626
  Parameters
625
627
  ----------
626
628
  name : str
627
- Name of the parameter (used as label in GUI)
628
- value : int
629
- Initial value (will be clamped between min_value and max_value)
630
- min_value : int
629
+ Name of the parameter (used as label in GUI and internal identifier)
630
+ value : Union[int, NoInitialValue]
631
+ Initial value (default position of the slider)
632
+ If not provided, the parameter will be set to the minimum value.
633
+ min : int
631
634
  Minimum allowed value
632
- max_value : int
635
+ max : int
633
636
  Maximum allowed value
634
637
 
635
638
  Examples
636
639
  --------
637
- >>> viewer.add_integer('count', value=5, min_value=0, max_value=10)
638
- >>> viewer.state['count']
639
- 5
640
- >>> viewer.update_integer('count', value=15) # Will be clamped to 10
641
- >>> viewer.state['count']
642
- 10
640
+ >>> viewer.add_integer('age', value=25, min=0, max=120)
641
+
642
+ >>> viewer.add_integer('year', value=2023, min=1900, max=2100)
643
643
  """
644
644
  try:
645
- new_param = ParameterType.integer.value(
646
- name,
647
- value,
648
- min_value,
649
- max_value,
650
- )
645
+ new_param = ParameterType.integer.value(name, value, min, max)
651
646
  except Exception as e:
652
- raise ParameterAddError(name, "number", str(e))
647
+ raise ParameterAddError(name, "integer", str(e)) from e
653
648
  else:
654
649
  self.parameters[name] = new_param
655
650
 
@@ -658,52 +653,41 @@ class Viewer:
658
653
  self,
659
654
  name: str,
660
655
  *,
661
- value: Union[float, int],
662
- min_value: Union[float, int],
663
- max_value: Union[float, int],
656
+ value: Union[Union[float, int], NoInitialValue] = NO_INITIAL_VALUE,
657
+ min: Union[float, int],
658
+ max: Union[float, int],
664
659
  step: float = 0.01,
665
660
  ) -> None:
666
661
  """
667
- Add a decimal number parameter to the viewer.
662
+ Add a float parameter to the viewer.
668
663
 
669
-
670
- Creates a slider in the GUI that lets users select numbers between
671
- min_value and max_value. Values will be rounded to the nearest step
672
- and clamped to stay within bounds.
664
+ Creates a slider to select decimal numbers between a minimum and maximum.
665
+ See :class:`~syd.parameters.FloatParameter` for details.
673
666
 
674
667
  Parameters
675
668
  ----------
676
669
  name : str
677
- Name of the parameter (used as label in GUI)
678
- value : float
679
- Initial value (will be clamped between min_value and max_value)
680
- min_value : float
670
+ Name of the parameter (internal identifier)
671
+ value : Union[float, NoInitialValue]
672
+ Initial value (default position of the slider)
673
+ If not provided, the parameter will be set to the minimum value.
674
+ min : float
681
675
  Minimum allowed value
682
- max_value : float
676
+ max : float
683
677
  Maximum allowed value
684
678
  step : float, optional
685
- Size of each increment (default: 0.01)
679
+ Step size for the slider (default: 0.01)
686
680
 
687
681
  Examples
688
682
  --------
689
- >>> viewer.add_float('temperature', value=20.0,
690
- ... min_value=0.0, max_value=100.0, step=0.5)
691
- >>> viewer.state['temperature']
692
- 20.0
693
- >>> viewer.update_float('temperature', value=20.7) # Will round to 20.5
694
- >>> viewer.state['temperature']
695
- 20.5
683
+ >>> viewer.add_float('temperature', value=98.6, min=95.0, max=105.0, step=0.1)
684
+
685
+ >>> viewer.add_float('price', value=9.99, min=0.0, max=100.0, step=0.01)
696
686
  """
697
687
  try:
698
- new_param = ParameterType.float.value(
699
- name,
700
- value,
701
- min_value,
702
- max_value,
703
- step,
704
- )
688
+ new_param = ParameterType.float.value(name, value, min, max, step)
705
689
  except Exception as e:
706
- raise ParameterAddError(name, "number", str(e)) from e
690
+ raise ParameterAddError(name, "float", str(e)) from e
707
691
  else:
708
692
  self.parameters[name] = new_param
709
693
 
@@ -712,48 +696,38 @@ class Viewer:
712
696
  self,
713
697
  name: str,
714
698
  *,
715
- value: Tuple[Union[float, int], Union[float, int]],
716
- min_value: Union[float, int],
717
- max_value: Union[float, int],
699
+ value: Union[
700
+ Tuple[Union[float, int], Union[float, int]], NoInitialValue
701
+ ] = NO_INITIAL_VALUE,
702
+ min: Union[float, int],
703
+ max: Union[float, int],
718
704
  ) -> None:
719
705
  """
720
- Add a range parameter for whole numbers to the viewer.
706
+ Add an integer range parameter to the viewer.
721
707
 
722
- Creates a range slider in the GUI that lets users select a range of integers
723
- between min_value and max_value. The range is specified as (low, high) and
724
- both values will be clamped to stay within bounds.
708
+ Creates a range slider to select a range of whole numbers between bounds.
725
709
  See :class:`~syd.parameters.IntegerRangeParameter` for details.
726
710
 
727
711
  Parameters
728
712
  ----------
729
713
  name : str
730
- Name of the parameter (used as label in GUI)
731
- value : tuple[int, int]
732
- Initial (low, high) values
733
- min_value : int
734
- Minimum allowed value for both low and high
735
- max_value : int
736
- Maximum allowed value for both low and high
714
+ Name of the parameter (internal identifier)
715
+ value : Union[tuple[int, int], NoInitialValue]
716
+ Initial (low, high) values for the range
717
+ If not provided, the parameter will be set to the full range.
718
+ min : int
719
+ Minimum allowed value for the range
720
+ max : int
721
+ Maximum allowed value for the range
737
722
 
738
723
  Examples
739
724
  --------
740
- >>> viewer.add_integer_range('age_range',
741
- ... value=(25, 35),
742
- ... min_value=18, max_value=100)
743
- >>> viewer.state['age_range']
744
- (25, 35)
745
- >>> # Values will be swapped if low > high
746
- >>> viewer.update_integer_range('age_range', value=(40, 30))
747
- >>> viewer.state['age_range']
748
- (30, 40)
725
+ >>> viewer.add_integer_range('age_range', value=(25, 45), min=18, max=100)
726
+
727
+ >>> viewer.add_integer_range('year_range', value=(2000, 2020), min=1900, max=2100)
749
728
  """
750
729
  try:
751
- new_param = ParameterType.integer_range.value(
752
- name,
753
- value,
754
- min_value,
755
- max_value,
756
- )
730
+ new_param = ParameterType.integer_range.value(name, value, min, max)
757
731
  except Exception as e:
758
732
  raise ParameterAddError(name, "integer_range", str(e)) from e
759
733
  else:
@@ -764,52 +738,41 @@ class Viewer:
764
738
  self,
765
739
  name: str,
766
740
  *,
767
- value: Tuple[Union[float, int], Union[float, int]],
768
- min_value: Union[float, int],
769
- max_value: Union[float, int],
741
+ value: Union[
742
+ Tuple[Union[float, int], Union[float, int]], NoInitialValue
743
+ ] = NO_INITIAL_VALUE,
744
+ min: Union[float, int],
745
+ max: Union[float, int],
770
746
  step: float = 0.01,
771
747
  ) -> None:
772
748
  """
773
- Add a range parameter for decimal numbers to the viewer.
749
+ Add a float range parameter to the viewer.
774
750
 
775
- Creates a range slider in the GUI that lets users select a range of numbers
776
- between min_value and max_value. The range is specified as (low, high) and
777
- both values will be rounded to the nearest step and clamped to stay within bounds.
751
+ Creates a range slider to select a range of decimal numbers between bounds.
778
752
  See :class:`~syd.parameters.FloatRangeParameter` for details.
779
753
 
780
754
  Parameters
781
755
  ----------
782
756
  name : str
783
- Name of the parameter (used as label in GUI)
784
- value : tuple[float, float]
785
- Initial (low, high) values
786
- min_value : float
787
- Minimum allowed value for both low and high
788
- max_value : float
789
- Maximum allowed value for both low and high
757
+ Name of the parameter (internal identifier)
758
+ value : Union[tuple[float, float], NoInitialValue]
759
+ Initial (low, high) values for the range
760
+ If not provided, the parameter will be set to the full range.
761
+ min : float
762
+ Minimum allowed value for the range
763
+ max : float
764
+ Maximum allowed value for the range
790
765
  step : float, optional
791
- Size of each increment (default: 0.01)
766
+ Step size for the slider (default: 0.01)
792
767
 
793
768
  Examples
794
769
  --------
795
- >>> viewer.add_float_range('price_range',
796
- ... value=(10.0, 20.0),
797
- ... min_value=0.0, max_value=100.0, step=0.5)
798
- >>> viewer.state['price_range']
799
- (10.0, 20.0)
800
- >>> # Values will be rounded to nearest step
801
- >>> viewer.update_float_range('price_range', value=(10.7, 19.2))
802
- >>> viewer.state['price_range']
803
- (10.5, 19.0)
770
+ >>> viewer.add_float_range('temp_range', value=(97.0, 99.0), min=95.0, max=105.0, step=0.1)
771
+
772
+ >>> viewer.add_float_range('price_range', value=(10.0, 50.0), min=0.0, max=100.0, step=0.01)
804
773
  """
805
774
  try:
806
- new_param = ParameterType.float_range.value(
807
- name,
808
- value,
809
- min_value,
810
- max_value,
811
- step,
812
- )
775
+ new_param = ParameterType.float_range.value(name, value, min, max, step)
813
776
  except Exception as e:
814
777
  raise ParameterAddError(name, "float_range", str(e)) from e
815
778
  else:
@@ -820,7 +783,7 @@ class Viewer:
820
783
  self,
821
784
  name: str,
822
785
  *,
823
- value: Union[float, int],
786
+ value: Union[Union[float, int], NoInitialValue] = NO_INITIAL_VALUE,
824
787
  ) -> None:
825
788
  """
826
789
  Add an unbounded integer parameter to the viewer.
@@ -833,8 +796,9 @@ class Viewer:
833
796
  ----------
834
797
  name : str
835
798
  Name of the parameter (used as label in GUI)
836
- value : int
799
+ value : Union[int, NoInitialValue]
837
800
  Initial value
801
+ If not provided, the parameter will be set to 0.
838
802
 
839
803
  Examples
840
804
  --------
@@ -843,10 +807,7 @@ class Viewer:
843
807
  1000000
844
808
  """
845
809
  try:
846
- new_param = ParameterType.unbounded_integer.value(
847
- name,
848
- value,
849
- )
810
+ new_param = ParameterType.unbounded_integer.value(name, value)
850
811
  except Exception as e:
851
812
  raise ParameterAddError(name, "unbounded_integer", str(e)) from e
852
813
  else:
@@ -857,7 +818,7 @@ class Viewer:
857
818
  self,
858
819
  name: str,
859
820
  *,
860
- value: Union[float, int],
821
+ value: Union[Union[float, int], NoInitialValue] = NO_INITIAL_VALUE,
861
822
  step: Optional[float] = None,
862
823
  ) -> None:
863
824
  """
@@ -872,8 +833,9 @@ class Viewer:
872
833
  ----------
873
834
  name : str
874
835
  Name of the parameter (used as label in GUI)
875
- value : float
836
+ value : Union[float, NoInitialValue]
876
837
  Initial value
838
+ If not provided, the parameter will be set to 0.
877
839
  step : float, optional
878
840
  Size of each increment (or None for no rounding)
879
841
 
@@ -888,11 +850,7 @@ class Viewer:
888
850
  5.51e-07
889
851
  """
890
852
  try:
891
- new_param = ParameterType.unbounded_float.value(
892
- name,
893
- value,
894
- step,
895
- )
853
+ new_param = ParameterType.unbounded_float.value(name, value, step)
896
854
  except Exception as e:
897
855
  raise ParameterAddError(name, "unbounded_float", str(e)) from e
898
856
  else:
@@ -903,7 +861,7 @@ class Viewer:
903
861
  self,
904
862
  name: str,
905
863
  *,
906
- label: str,
864
+ label: Union[str, NoInitialValue] = NO_INITIAL_VALUE,
907
865
  callback: Callable[[], None],
908
866
  ) -> None:
909
867
  """
@@ -917,8 +875,9 @@ class Viewer:
917
875
  ----------
918
876
  name : str
919
877
  Name of the parameter (internal identifier)
920
- label : str
878
+ label : Union[str, NoInitialValue]
921
879
  Text to display on the button
880
+ If not provided, the parameter's label will be set to the name.
922
881
  callback : callable
923
882
  Function to call when the button is clicked (takes state as a single argument)
924
883
 
@@ -947,7 +906,7 @@ class Viewer:
947
906
  # -------------------- parameter update methods --------------------
948
907
  @validate_parameter_operation("update", ParameterType.text)
949
908
  def update_text(
950
- self, name: str, *, value: Union[str, _NoUpdate] = _NO_UPDATE
909
+ self, name: str, *, value: Union[str, NoUpdate] = NO_UPDATE
951
910
  ) -> None:
952
911
  """
953
912
  Update a text parameter's value.
@@ -959,7 +918,7 @@ class Viewer:
959
918
  ----------
960
919
  name : str
961
920
  Name of the text parameter to update
962
- value : str, optional
921
+ value : Union[str, NoUpdate], optional
963
922
  New text value (if not provided, no change)
964
923
 
965
924
  Examples
@@ -970,14 +929,14 @@ class Viewer:
970
929
  'New Title'
971
930
  """
972
931
  updates = {}
973
- if not value == _NO_UPDATE:
932
+ if not value == NO_UPDATE:
974
933
  updates["value"] = value
975
934
  if updates:
976
935
  self.parameters[name].update(updates)
977
936
 
978
937
  @validate_parameter_operation("update", ParameterType.boolean)
979
938
  def update_boolean(
980
- self, name: str, *, value: Union[bool, _NoUpdate] = _NO_UPDATE
939
+ self, name: str, *, value: Union[bool, NoUpdate] = NO_UPDATE
981
940
  ) -> None:
982
941
  """
983
942
  Update a boolean parameter's value.
@@ -989,7 +948,7 @@ class Viewer:
989
948
  ----------
990
949
  name : str
991
950
  Name of the boolean parameter to update
992
- value : bool, optional
951
+ value : Union[bool, NoUpdate], optional
993
952
  New state (True/False) (if not provided, no change)
994
953
 
995
954
  Examples
@@ -1000,7 +959,7 @@ class Viewer:
1000
959
  False
1001
960
  """
1002
961
  updates = {}
1003
- if not value == _NO_UPDATE:
962
+ if not value == NO_UPDATE:
1004
963
  updates["value"] = value
1005
964
  if updates:
1006
965
  self.parameters[name].update(updates)
@@ -1010,8 +969,8 @@ class Viewer:
1010
969
  self,
1011
970
  name: str,
1012
971
  *,
1013
- value: Union[Any, _NoUpdate] = _NO_UPDATE,
1014
- options: Union[List[Any], _NoUpdate] = _NO_UPDATE,
972
+ value: Union[Any, NoUpdate] = NO_UPDATE,
973
+ options: Union[List[Any], NoUpdate] = NO_UPDATE,
1015
974
  ) -> None:
1016
975
  """
1017
976
  Update a selection parameter's value and/or options.
@@ -1023,9 +982,9 @@ class Viewer:
1023
982
  ----------
1024
983
  name : str
1025
984
  Name of the selection parameter to update
1026
- value : Any, optional
985
+ value : Union[Any, NoUpdate], optional
1027
986
  New selected value (must be in options) (if not provided, no change)
1028
- options : list, optional
987
+ options : Union[list, NoUpdate], optional
1029
988
  New list of selectable options (if not provided, no change)
1030
989
 
1031
990
  Examples
@@ -1040,9 +999,9 @@ class Viewer:
1040
999
  ... value='purple')
1041
1000
  """
1042
1001
  updates = {}
1043
- if not value == _NO_UPDATE:
1002
+ if not value == NO_UPDATE:
1044
1003
  updates["value"] = value
1045
- if not options == _NO_UPDATE:
1004
+ if not options == NO_UPDATE:
1046
1005
  updates["options"] = options
1047
1006
  if updates:
1048
1007
  self.parameters[name].update(updates)
@@ -1052,8 +1011,8 @@ class Viewer:
1052
1011
  self,
1053
1012
  name: str,
1054
1013
  *,
1055
- value: Union[List[Any], _NoUpdate] = _NO_UPDATE,
1056
- options: Union[List[Any], _NoUpdate] = _NO_UPDATE,
1014
+ value: Union[List[Any], NoUpdate] = NO_UPDATE,
1015
+ options: Union[List[Any], NoUpdate] = NO_UPDATE,
1057
1016
  ) -> None:
1058
1017
  """
1059
1018
  Update a multiple selection parameter's values and/or options.
@@ -1065,9 +1024,9 @@ class Viewer:
1065
1024
  ----------
1066
1025
  name : str
1067
1026
  Name of the multiple selection parameter to update
1068
- value : list, optional
1027
+ value : Union[list, NoUpdate], optional
1069
1028
  New list of selected values (all must be in options) (if not provided, no change)
1070
- options : list, optional
1029
+ options : Union[list, NoUpdate], optional
1071
1030
  New list of selectable options (if not provided, no change)
1072
1031
 
1073
1032
  Examples
@@ -1084,9 +1043,9 @@ class Viewer:
1084
1043
  ... value=['cheese', 'bacon'])
1085
1044
  """
1086
1045
  updates = {}
1087
- if not value == _NO_UPDATE:
1046
+ if not value == NO_UPDATE:
1088
1047
  updates["value"] = value
1089
- if not options == _NO_UPDATE:
1048
+ if not options == NO_UPDATE:
1090
1049
  updates["options"] = options
1091
1050
  if updates:
1092
1051
  self.parameters[name].update(updates)
@@ -1096,200 +1055,196 @@ class Viewer:
1096
1055
  self,
1097
1056
  name: str,
1098
1057
  *,
1099
- value: Union[int, _NoUpdate] = _NO_UPDATE,
1100
- min_value: Union[int, _NoUpdate] = _NO_UPDATE,
1101
- max_value: Union[int, _NoUpdate] = _NO_UPDATE,
1058
+ value: Union[int, NoUpdate] = NO_UPDATE,
1059
+ min: Union[int, NoUpdate] = NO_UPDATE,
1060
+ max: Union[int, NoUpdate] = NO_UPDATE,
1102
1061
  ) -> None:
1103
1062
  """
1104
- Update an integer parameter's value and/or bounds.
1063
+ Update an integer parameter.
1105
1064
 
1106
- Updates a parameter created by :meth:`~syd.viewer.Viewer.add_integer`.
1107
- See :class:`~syd.parameters.IntegerParameter` for details about value validation.
1065
+ Change the value or bounds of an existing integer parameter.
1066
+ See :class:`~syd.parameters.IntegerParameter` for details.
1108
1067
 
1109
1068
  Parameters
1110
1069
  ----------
1111
1070
  name : str
1112
- Name of the integer parameter to update
1113
- value : int, optional
1114
- New value (will be clamped to bounds) (if not provided, no change)
1115
- min_value : int, optional
1116
- New minimum value (if not provided, no change)
1117
- max_value : int, optional
1118
- New maximum value (if not provided, no change)
1071
+ Name of the parameter to update
1072
+ value : Union[int, NoUpdate], optional
1073
+ New value
1074
+ min : Union[int, NoUpdate], optional
1075
+ New minimum allowed value
1076
+ max : Union[int, NoUpdate], optional
1077
+ New maximum allowed value
1119
1078
 
1120
1079
  Examples
1121
1080
  --------
1122
- >>> viewer.add_integer('count', value=5, min_value=0, max_value=10)
1123
- >>> # Update just the value
1124
- >>> viewer.update_integer('count', value=8)
1125
- >>> # Update bounds (current value will be clamped if needed)
1126
- >>> viewer.update_integer('count', min_value=7, max_value=15)
1081
+ >>> viewer.update_integer('age', value=30) # Update just the value
1082
+
1083
+ >>> viewer.update_integer('year', min=2000, max=2023) # Update just the bounds
1127
1084
  """
1128
1085
  updates = {}
1129
- if not value == _NO_UPDATE:
1130
- updates["value"] = value
1131
- if not min_value == _NO_UPDATE:
1132
- updates["min_value"] = min_value
1133
- if not max_value == _NO_UPDATE:
1134
- updates["max_value"] = max_value
1135
- if updates:
1136
- self.parameters[name].update(updates)
1086
+ if not isinstance(value, NoUpdate):
1087
+ updates["value"] = int(value)
1088
+ if not isinstance(min, NoUpdate):
1089
+ updates["min"] = int(min)
1090
+ if not isinstance(max, NoUpdate):
1091
+ updates["max"] = int(max)
1092
+
1093
+ parameter = self.parameters[name]
1094
+ parameter.update(updates)
1137
1095
 
1138
1096
  @validate_parameter_operation("update", ParameterType.float)
1139
1097
  def update_float(
1140
1098
  self,
1141
1099
  name: str,
1142
1100
  *,
1143
- value: Union[float, _NoUpdate] = _NO_UPDATE,
1144
- min_value: Union[float, _NoUpdate] = _NO_UPDATE,
1145
- max_value: Union[float, _NoUpdate] = _NO_UPDATE,
1146
- step: Union[float, _NoUpdate] = _NO_UPDATE,
1101
+ value: Union[float, NoUpdate] = NO_UPDATE,
1102
+ min: Union[float, NoUpdate] = NO_UPDATE,
1103
+ max: Union[float, NoUpdate] = NO_UPDATE,
1104
+ step: Union[float, NoUpdate] = NO_UPDATE,
1147
1105
  ) -> None:
1148
1106
  """
1149
- Update a float parameter's value, bounds, and/or step size.
1107
+ Update a float parameter.
1150
1108
 
1151
- Updates a parameter created by :meth:`~syd.viewer.Viewer.add_float`.
1152
- See :class:`~syd.parameters.FloatParameter` for details about value validation.
1109
+ Change the value, bounds, or step size of an existing float parameter.
1110
+ See :class:`~syd.parameters.FloatParameter` for details.
1153
1111
 
1154
1112
  Parameters
1155
1113
  ----------
1156
1114
  name : str
1157
- Name of the float parameter to update
1158
- value : float, optional
1159
- New value (will be rounded and clamped) (if not provided, no change)
1160
- min_value : float, optional
1161
- New minimum value (if not provided, no change)
1162
- max_value : float, optional
1163
- New maximum value (if not provided, no change)
1164
- step : float, optional
1165
- New step size (if not provided, no change)
1115
+ Name of the parameter to update
1116
+ value : Union[float, NoUpdate], optional
1117
+ New value
1118
+ min : Union[float, NoUpdate], optional
1119
+ New minimum allowed value
1120
+ max : Union[float, NoUpdate], optional
1121
+ New maximum allowed value
1122
+ step : Union[float, NoUpdate], optional
1123
+ New step size for the slider
1166
1124
 
1167
1125
  Examples
1168
1126
  --------
1169
- >>> viewer.add_float('temperature', value=20.0,
1170
- ... min_value=0.0, max_value=100.0, step=0.5)
1171
- >>> # Update just the value (will round to step)
1172
- >>> viewer.update_float('temperature', value=20.7) # Becomes 20.5
1173
- >>> # Update bounds and step size
1174
- >>> viewer.update_float('temperature',
1175
- ... min_value=15.0, max_value=30.0, step=0.1)
1127
+ >>> viewer.update_float('temperature', value=99.5) # Update just the value
1128
+
1129
+ >>> viewer.update_float('price', min=5.0, max=200.0, step=0.05) # Update bounds and step
1176
1130
  """
1177
1131
  updates = {}
1178
- if not value == _NO_UPDATE:
1179
- updates["value"] = value
1180
- if not min_value == _NO_UPDATE:
1181
- updates["min_value"] = min_value
1182
- if not max_value == _NO_UPDATE:
1183
- updates["max_value"] = max_value
1184
- if not step == _NO_UPDATE:
1185
- updates["step"] = step
1186
- if updates:
1187
- self.parameters[name].update(updates)
1132
+ if not isinstance(value, NoUpdate):
1133
+ updates["value"] = float(value)
1134
+ if not isinstance(min, NoUpdate):
1135
+ updates["min"] = float(min)
1136
+ if not isinstance(max, NoUpdate):
1137
+ updates["max"] = float(max)
1138
+ if not isinstance(step, NoUpdate):
1139
+ updates["step"] = float(step)
1140
+
1141
+ parameter = self.parameters[name]
1142
+ parameter.update(updates)
1188
1143
 
1189
1144
  @validate_parameter_operation("update", ParameterType.integer_range)
1190
1145
  def update_integer_range(
1191
1146
  self,
1192
1147
  name: str,
1193
1148
  *,
1194
- value: Union[Tuple[int, int], _NoUpdate] = _NO_UPDATE,
1195
- min_value: Union[int, _NoUpdate] = _NO_UPDATE,
1196
- max_value: Union[int, _NoUpdate] = _NO_UPDATE,
1149
+ value: Union[Tuple[int, int], NoUpdate] = NO_UPDATE,
1150
+ min: Union[int, NoUpdate] = NO_UPDATE,
1151
+ max: Union[int, NoUpdate] = NO_UPDATE,
1197
1152
  ) -> None:
1198
1153
  """
1199
- Update an integer range parameter's values and/or bounds.
1154
+ Update an integer range parameter.
1200
1155
 
1201
- Updates a parameter created by :meth:`~syd.viewer.Viewer.add_integer_range`.
1202
- See :class:`~syd.parameters.IntegerRangeParameter` for details about value validation.
1156
+ Change the range values or bounds of an existing integer range parameter.
1157
+ See :class:`~syd.parameters.IntegerRangeParameter` for details.
1203
1158
 
1204
1159
  Parameters
1205
1160
  ----------
1206
1161
  name : str
1207
- Name of the integer range parameter to update
1208
- value : tuple[int, int], optional
1209
- New (low, high) values (will be clamped) (if not provided, no change)
1210
- min_value : int, optional
1211
- New minimum value for both low and high (if not provided, no change)
1212
- max_value : int, optional
1213
- New maximum value for both low and high (if not provided, no change)
1162
+ Name of the parameter to update
1163
+ value : Union[tuple[int, int], NoUpdate], optional
1164
+ New (low, high) values
1165
+ min : Union[int, NoUpdate], optional
1166
+ New minimum allowed value
1167
+ max : Union[int, NoUpdate], optional
1168
+ New maximum allowed value
1214
1169
 
1215
1170
  Examples
1216
1171
  --------
1217
- >>> viewer.add_integer_range('age_range',
1218
- ... value=(25, 35),
1219
- ... min_value=18, max_value=100)
1220
- >>> # Update just the range (values will be swapped if needed)
1221
- >>> viewer.update_integer_range('age_range', value=(40, 30)) # Becomes (30, 40)
1222
- >>> # Update bounds (current values will be clamped if needed)
1223
- >>> viewer.update_integer_range('age_range', min_value=20, max_value=80)
1172
+ >>> viewer.update_integer_range('age_range', value=(30, 50)) # Update just the values
1173
+
1174
+ >>> viewer.update_integer_range('year_range', min=1950, max=2023) # Update just the bounds
1224
1175
  """
1225
1176
  updates = {}
1226
- if not value == _NO_UPDATE:
1227
- updates["value"] = value
1228
- if not min_value == _NO_UPDATE:
1229
- updates["min_value"] = min_value
1230
- if not max_value == _NO_UPDATE:
1231
- updates["max_value"] = max_value
1232
- if updates:
1233
- self.parameters[name].update(updates)
1177
+ if not isinstance(value, NoUpdate):
1178
+ val_low, val_high = value
1179
+ updates["value"] = (int(val_low), int(val_high))
1180
+ if not isinstance(min, NoUpdate):
1181
+ updates["min"] = int(min)
1182
+ if not isinstance(max, NoUpdate):
1183
+ updates["max"] = int(max)
1184
+
1185
+ parameter = self.parameters[name]
1186
+ parameter.update(updates)
1234
1187
 
1235
1188
  @validate_parameter_operation("update", ParameterType.float_range)
1236
1189
  def update_float_range(
1237
1190
  self,
1238
1191
  name: str,
1239
1192
  *,
1240
- value: Union[Tuple[float, float], _NoUpdate] = _NO_UPDATE,
1241
- min_value: Union[float, _NoUpdate] = _NO_UPDATE,
1242
- max_value: Union[float, _NoUpdate] = _NO_UPDATE,
1243
- step: Union[float, _NoUpdate] = _NO_UPDATE,
1193
+ value: Union[Tuple[float, float], NoUpdate] = NO_UPDATE,
1194
+ min: Union[float, NoUpdate] = NO_UPDATE,
1195
+ max: Union[float, NoUpdate] = NO_UPDATE,
1196
+ step: Union[float, NoUpdate] = NO_UPDATE,
1244
1197
  ) -> None:
1245
1198
  """
1246
- Update a float range parameter's values, bounds, and/or step size.
1199
+ Update a float range parameter.
1247
1200
 
1248
- Updates a parameter created by :meth:`~syd.viewer.Viewer.add_float_range`.
1249
- See :class:`~syd.parameters.FloatRangeParameter` for details about value validation.
1201
+ Change the range values, bounds, or step size of an existing float range parameter.
1202
+ See :class:`~syd.parameters.FloatRangeParameter` for details.
1250
1203
 
1251
1204
  Parameters
1252
1205
  ----------
1253
1206
  name : str
1254
- Name of the float range parameter to update
1255
- value : tuple[float, float], optional
1256
- New (low, high) values (will be rounded and clamped) (if not provided, no change)
1257
- min_value : float, optional
1258
- New minimum value for both low and high (if not provided, no change)
1259
- max_value : float, optional
1260
- New maximum value for both low and high (if not provided, no change)
1261
- step : float, optional
1262
- New step size for rounding values (if not provided, no change)
1207
+ Name of the parameter to update
1208
+ value : Union[tuple[float, float], NoUpdate], optional
1209
+ New (low, high) values
1210
+ min : Union[float, NoUpdate], optional
1211
+ New minimum allowed value
1212
+ max : Union[float, NoUpdate], optional
1213
+ New maximum allowed value
1214
+ step : Union[float, NoUpdate], optional
1215
+ New step size for the slider
1263
1216
 
1264
1217
  Examples
1265
1218
  --------
1266
- >>> viewer.add_float_range('price_range',
1267
- ... value=(10.0, 20.0),
1268
- ... min_value=0.0, max_value=100.0, step=0.5)
1269
- >>> # Update just the range (values will be rounded and swapped if needed)
1270
- >>> viewer.update_float_range('price_range', value=(15.7, 14.2)) # Becomes (14.0, 15.5)
1271
- >>> # Update bounds and step size
1272
- >>> viewer.update_float_range('price_range',
1273
- ... min_value=5.0, max_value=50.0, step=0.1)
1219
+ >>> viewer.update_float_range('temp_range', value=(97.5, 98.5)) # Update just the values
1220
+
1221
+ >>> viewer.update_float_range(
1222
+ ... 'price_range',
1223
+ ... min=10.0,
1224
+ ... max=500.0,
1225
+ ... step=0.5
1226
+ ... ) # Update bounds and step
1274
1227
  """
1275
1228
  updates = {}
1276
- if not value == _NO_UPDATE:
1277
- updates["value"] = value
1278
- if not min_value == _NO_UPDATE:
1279
- updates["min_value"] = min_value
1280
- if not max_value == _NO_UPDATE:
1281
- updates["max_value"] = max_value
1282
- if not step == _NO_UPDATE:
1283
- updates["step"] = step
1284
- if updates:
1285
- self.parameters[name].update(updates)
1229
+ if not isinstance(value, NoUpdate):
1230
+ val_low, val_high = value
1231
+ updates["value"] = (float(val_low), float(val_high))
1232
+ if not isinstance(min, NoUpdate):
1233
+ updates["min"] = float(min)
1234
+ if not isinstance(max, NoUpdate):
1235
+ updates["max"] = float(max)
1236
+ if not isinstance(step, NoUpdate):
1237
+ updates["step"] = float(step)
1238
+
1239
+ parameter = self.parameters[name]
1240
+ parameter.update(updates)
1286
1241
 
1287
1242
  @validate_parameter_operation("update", ParameterType.unbounded_integer)
1288
1243
  def update_unbounded_integer(
1289
1244
  self,
1290
1245
  name: str,
1291
1246
  *,
1292
- value: Union[int, _NoUpdate] = _NO_UPDATE,
1247
+ value: Union[int, NoUpdate] = NO_UPDATE,
1293
1248
  ) -> None:
1294
1249
  """
1295
1250
  Update an unbounded integer parameter's value and/or bounds.
@@ -1301,7 +1256,7 @@ class Viewer:
1301
1256
  ----------
1302
1257
  name : str
1303
1258
  Name of the unbounded integer parameter to update
1304
- value : int, optional
1259
+ value : Union[int, NoUpdate], optional
1305
1260
  New value (if not provided, no change)
1306
1261
 
1307
1262
  Examples
@@ -1311,7 +1266,7 @@ class Viewer:
1311
1266
  >>> viewer.update_unbounded_integer('population', value=2000000)
1312
1267
  """
1313
1268
  updates = {}
1314
- if not value == _NO_UPDATE:
1269
+ if not value == NO_UPDATE:
1315
1270
  updates["value"] = value
1316
1271
  if updates:
1317
1272
  self.parameters[name].update(updates)
@@ -1321,8 +1276,8 @@ class Viewer:
1321
1276
  self,
1322
1277
  name: str,
1323
1278
  *,
1324
- value: Union[float, _NoUpdate] = _NO_UPDATE,
1325
- step: Union[Optional[float], _NoUpdate] = _NO_UPDATE,
1279
+ value: Union[float, NoUpdate] = NO_UPDATE,
1280
+ step: Union[Optional[float], NoUpdate] = NO_UPDATE,
1326
1281
  ) -> None:
1327
1282
  """
1328
1283
  Update an unbounded float parameter's value, bounds, and/or step size.
@@ -1334,9 +1289,9 @@ class Viewer:
1334
1289
  ----------
1335
1290
  name : str
1336
1291
  Name of the unbounded float parameter to update
1337
- value : float, optional
1292
+ value : Union[float, NoUpdate], optional
1338
1293
  New value (will be rounded if step is set) (if not provided, no change)
1339
- step : float or None, optional
1294
+ step : Union[Optional[float], NoUpdate], optional
1340
1295
  New step size for rounding, or None for no rounding (if not provided, no change)
1341
1296
 
1342
1297
  Examples
@@ -1350,9 +1305,9 @@ class Viewer:
1350
1305
  >>> viewer.update_unbounded_float('wavelength', step=None)
1351
1306
  """
1352
1307
  updates = {}
1353
- if not value == _NO_UPDATE:
1308
+ if not value == NO_UPDATE:
1354
1309
  updates["value"] = value
1355
- if not step == _NO_UPDATE:
1310
+ if not step == NO_UPDATE:
1356
1311
  updates["step"] = step
1357
1312
  if updates:
1358
1313
  self.parameters[name].update(updates)
@@ -1362,8 +1317,8 @@ class Viewer:
1362
1317
  self,
1363
1318
  name: str,
1364
1319
  *,
1365
- label: Union[str, _NoUpdate] = _NO_UPDATE,
1366
- callback: Union[Callable[[], None], _NoUpdate] = _NO_UPDATE,
1320
+ label: Union[str, NoUpdate] = NO_UPDATE,
1321
+ callback: Union[Callable[[], None], NoUpdate] = NO_UPDATE,
1367
1322
  ) -> None:
1368
1323
  """
1369
1324
  Update a button parameter's label and/or callback function.
@@ -1375,9 +1330,9 @@ class Viewer:
1375
1330
  ----------
1376
1331
  name : str
1377
1332
  Name of the button parameter to update
1378
- label : str, optional
1333
+ label : Union[str, NoUpdate], optional
1379
1334
  New text to display on the button (if not provided, no change)
1380
- callback : callable, optional
1335
+ callback : Union[callable, NoUpdate], optional
1381
1336
  New function to call when clicked (if not provided, no change)
1382
1337
 
1383
1338
  Examples
@@ -1389,13 +1344,21 @@ class Viewer:
1389
1344
  ... callback=new_callback)
1390
1345
  """
1391
1346
  updates = {}
1392
- if not label == _NO_UPDATE:
1347
+ if not label == NO_UPDATE:
1393
1348
  updates["label"] = label
1394
- if not callback == _NO_UPDATE:
1395
- callback = self._prepare_function(
1396
- callback,
1397
- context="Updating button callback:",
1398
- )
1399
- updates["callback"] = callback
1349
+ if not callback == NO_UPDATE:
1350
+ try:
1351
+ callback = self._prepare_function(
1352
+ callback,
1353
+ context="Updating button callback:",
1354
+ )
1355
+ except Exception as e:
1356
+ raise ParameterUpdateError(
1357
+ name,
1358
+ "button",
1359
+ str(e),
1360
+ ) from e
1361
+ else:
1362
+ updates["callback"] = callback
1400
1363
  if updates:
1401
1364
  self.parameters[name].update(updates)