ezinput.ezinput_jupyter

   1import os
   2import yaml
   3from ipyfilechooser import FileChooser
   4import ipywidgets as widgets
   5from IPython.display import display, clear_output
   6from pathlib import Path
   7
   8from typing import Optional
   9
  10"""
  11A module to help simplify the create of GUIs in Jupyter notebooks using ipywidgets.
  12"""
  13
  14CONFIG_PATH = Path.home() / ".ezinput"
  15
  16if not os.path.exists(CONFIG_PATH):
  17    os.makedirs(CONFIG_PATH)
  18
  19
  20class EZInputJupyter:
  21    """
  22    A class to create GUIs in Jupyter notebooks using `ipywidgets`.
  23
  24    Parameters
  25    ----------
  26    title : str, optional
  27        Title of the GUI, used to store settings. Defaults to "basic_gui".
  28    width : str, optional
  29        Width of the widget container. Defaults to "50%".
  30    """
  31
  32    def __init__(self, title="basic_gui", width="50%"):
  33        """
  34        Container for widgets.
  35
  36        Parameters
  37        ----------
  38        title : str, optional
  39            The title of the widget container, used to store settings.
  40        width : str, optional
  41            The width of the widget container.
  42        """
  43        pass
  44
  45    def __getvalue__(self, tag: str):
  46        """
  47        @unified
  48        Get the value of a widget.
  49
  50        Parameters
  51        ----------
  52        tag : str
  53            Tag to identify the widget.
  54
  55        Returns
  56        -------
  57        Any
  58            The value of the widget.
  59        """
  60        return self.elements[tag].value
  61
  62    def __getitem__(self, tag: str) -> widgets.Widget:
  63        """
  64        Get a widget by tag.
  65
  66        Parameters
  67        ----------
  68        tag : str
  69            The tag of the widget.
  70
  71        Returns
  72        -------
  73        widgets.Widget
  74            The widget.
  75        """
  76        return self.elements[tag]
  77
  78    def __len__(self) -> int:
  79        """
  80        Get the number of widgets.
  81
  82        Returns
  83        -------
  84        int
  85            The number of widgets.
  86        """
  87        return len(self.elements)
  88
  89    def add_label(self, value="", *args, **kwargs):
  90        """
  91        @unified
  92        Add a label widget to the container.
  93
  94        Parameters
  95        ----------
  96        label : str, optional
  97            The label text to display. Defaults to "".
  98        *args : tuple
  99            Additional positional arguments for the widget.
 100        **kwargs : dict
 101            Additional keyword arguments for the widget.
 102        """
 103        self._nLabels += 1
 104        style = kwargs.pop("style", self._style)
 105        self.elements[f"label_{self._nLabels}"] = widgets.Label(
 106            value=value,
 107            *args,
 108            **kwargs,
 109            layout=self._layout,
 110            style=style,
 111        )
 112
 113    def add_text(
 114        self,
 115        tag: str,
 116        description: str = "",
 117        placeholder: str = "",
 118        *args,
 119        remember_value=False,
 120        **kwargs,
 121    ):
 122        """
 123        @unified
 124        Add a text widget to the container.
 125
 126        Parameters
 127        ----------
 128        tag : str
 129            Tag to identify the widget.
 130        description : str, optional
 131            The message to display. Defaults to "".
 132        placeholder : str, optional
 133            Placeholder text for the input field. Defaults to "".
 134        remember_value : bool, optional
 135            Whether to remember the last entered value. Defaults to False.
 136        *args : tuple
 137            Additional positional arguments for the widget.
 138        **kwargs : dict
 139            Additional keyword arguments for the widget.
 140        """
 141        if self.params is not None:
 142            if tag in self.params:
 143                kwargs["value"] = self.params[tag]
 144        elif remember_value and tag in self.cfg:
 145            kwargs["value"] = str(self.cfg[tag])
 146
 147        style = kwargs.pop("style", self._style)
 148        self.elements[tag] = widgets.Text(
 149            description=description,
 150            placeholder=placeholder,
 151            *args,
 152            **kwargs,
 153            layout=self._layout,
 154            style=style,
 155        )
 156
 157    def add_callback(
 158        self, tag, func, values: dict, description="Run", *args, **kwargs
 159    ):
 160        """
 161        @unified
 162        Add a button widget to the container.
 163
 164        Parameters
 165        ----------
 166        tag : str
 167            Tag to identify the widget.
 168        func : callable
 169            The function to call when the button is clicked.
 170        values : dict
 171            Dictionary of widget values to pass to the callback function.
 172        description : str, optional
 173            The label for the button. Defaults to "Run".
 174        *args : tuple
 175            Additional positional arguments for the button.
 176        **kwargs : dict
 177            Additional keyword arguments for the button.
 178        """
 179        style = kwargs.pop("style", self._style)
 180        self.elements[tag] = widgets.Button(
 181            description=description,
 182            *args,
 183            **kwargs,
 184            layout=self._layout,
 185            style=style,
 186        )
 187
 188        def wrapped(button):
 189            self.save_settings()
 190            func(values)
 191
 192        self.elements[tag].on_click(wrapped)
 193
 194    def add_button(self, tag, description="Run", *args, **kwargs):
 195        """
 196        @jupyter
 197        Add a button widget to the container.
 198
 199        Parameters
 200        ----------
 201        tag : str
 202            Tag to identify the widget.
 203        description : str, optional
 204            The label for the button. Defaults to "Run".
 205        *args : tuple
 206            Additional positional arguments for the widget.
 207        **kwargs : dict
 208            Additional keyword arguments for the widget.
 209        """
 210        style = kwargs.pop("style", self._style)
 211        self.elements[tag] = widgets.Button(
 212            description=description,
 213            *args,
 214            **kwargs,
 215            layout=self._layout,
 216            style=style,
 217        )
 218
 219    def add_text_area(
 220        self,
 221        tag: str,
 222        description: str = "",
 223        placeholder: str = "",
 224        *args,
 225        remember_value=False,
 226        on_change: Optional[callable] = None,
 227        **kwargs,
 228    ):
 229        """
 230        @unified
 231        Add a textarea widget to the container.
 232
 233        Parameters
 234        ----------
 235        tag : str
 236            Tag to identify the widget.
 237        description : str, optional
 238            The message to display. Defaults to "".
 239        placeholder : str, optional
 240            Placeholder text for the input field. Defaults to "".
 241        remember_value : bool, optional
 242            Whether to remember the last entered value. Defaults to False.
 243        *args : tuple
 244            Additional positional arguments for the widget.
 245        **kwargs : dict
 246            Additional keyword arguments for the widget.
 247        """
 248        if self.params is not None:
 249            if tag in self.params:
 250                kwargs["value"] = self.params[tag]
 251        elif remember_value and tag in self.cfg:
 252            kwargs["value"] = str(self.cfg[tag])
 253        style = kwargs.pop("style", self._style)
 254        self.elements[tag] = widgets.Textarea(
 255            description=description,
 256            placeholder=placeholder,
 257            *args,
 258            **kwargs,
 259            layout=self._layout,
 260            style=style,
 261        )
 262
 263        if on_change is not None:
 264            self.elements[tag].observe(on_change, names="value")
 265
 266    def add_HTML(
 267        self, tag: str, value: str, description: str = "", *args, **kwargs
 268    ):
 269        """
 270        @jupyter
 271        Add an HTML widget to the container.
 272
 273        Parameters
 274        ----------
 275        tag : str
 276            Tag to identify the widget.
 277        value : str
 278            The HTML content to display.
 279        *args : tuple
 280            Additional positional arguments for the widget.
 281        **kwargs : dict
 282            Additional keyword arguments for the widget.
 283        """
 284        style = kwargs.pop("style", self._style)
 285        self.elements[tag] = widgets.HTML(
 286            value=value,
 287            description=description,
 288            *args,
 289            **kwargs,
 290            layout=self._layout,
 291            style=style,
 292        )
 293
 294    def add_int_range(
 295        self,
 296        tag: str,
 297        description: str,
 298        vmin: int,
 299        vmax: int,
 300        *args,
 301        remember_value=False,
 302        on_change: Optional[callable] = None,
 303        **kwargs,
 304    ):
 305        """
 306        @unified
 307        Add an integer slider widget to the container.
 308
 309        Parameters
 310        ----------
 311        tag : str
 312            Tag to identify the widget.
 313        description : str
 314            The message to display.
 315        vmin : int
 316            Minimum value of the slider.
 317        vmax : int
 318            Maximum value of the slider.
 319        remember_value : bool, optional
 320            Whether to remember the last selected value. Defaults to False.
 321        *args : tuple
 322            Additional positional arguments for the widget.
 323        **kwargs : dict
 324            Additional keyword arguments for the widget.
 325        """
 326        if self.params is not None:
 327            if tag in self.params and vmin <= self.params[tag] <= vmax:
 328                kwargs["value"] = self.params[tag]
 329        elif (
 330            remember_value
 331            and tag in self.cfg
 332            and vmin <= self.cfg[tag] <= vmax
 333        ):
 334            kwargs["value"] = int(self.cfg[tag])
 335        style = kwargs.pop("style", self._style)
 336        self.elements[tag] = widgets.IntSlider(
 337            description=description,
 338            min=vmin,
 339            max=vmax,
 340            *args,
 341            **kwargs,
 342            layout=self._layout,
 343            style=style,
 344        )
 345
 346        if on_change is not None:
 347            self.elements[tag].observe(on_change, names="value")
 348
 349    def add_int_slider(
 350        self,
 351        tag: str,
 352        description: str,
 353        min: int,
 354        max: int,
 355        *args,
 356        remember_value=False,
 357        on_change: Optional[callable] = None,
 358        **kwargs,
 359    ):
 360        """
 361        @jupyter
 362        Add an integer slider widget to the container.
 363
 364        Parameters
 365        ----------
 366        tag : str
 367            Tag to identify the widget.
 368        description : str
 369            The message to display.
 370        vmin : int
 371            Minimum value of the slider.
 372        vmax : int
 373            Maximum value of the slider.
 374        remember_value : bool, optional
 375            Whether to remember the last selected value. Defaults to False.
 376        *args : tuple
 377            Additional positional arguments for the widget.
 378        **kwargs : dict
 379            Additional keyword arguments for the widget.
 380        """
 381        self.add_int_range(
 382            tag,
 383            description,
 384            vmin=min,
 385            vmax=max,
 386            *args,
 387            remember_value=remember_value,
 388            **kwargs,
 389        )
 390
 391        if on_change is not None:
 392            self.elements[tag].observe(on_change, names="value")
 393
 394    def add_float_range(
 395        self,
 396        tag: str,
 397        description: str,
 398        vmin: float,
 399        vmax: float,
 400        *args,
 401        remember_value=False,
 402        on_change: Optional[callable] = None,
 403        **kwargs,
 404    ):
 405        """
 406        @unified
 407        Add a float slider widget to the container.
 408
 409        Parameters
 410        ----------
 411        tag : str
 412            Tag to identify the widget.
 413        description : str
 414            The message to display.
 415        vmin : float
 416            Minimum value of the slider.
 417        vmax : float
 418            Maximum value of the slider.
 419        remember_value : bool, optional
 420            Whether to remember the last selected value. Defaults to False.
 421        *args : tuple
 422            Additional positional arguments for the widget.
 423        **kwargs : dict
 424            Additional keyword arguments for the widget.
 425        """
 426        if self.params is not None:
 427            if tag in self.params and vmin <= self.params[tag] <= vmax:
 428                kwargs["value"] = self.params[tag]
 429        elif (
 430            remember_value
 431            and tag in self.cfg
 432            and vmin <= self.cfg[tag] <= vmax
 433        ):
 434            kwargs["value"] = int(self.cfg[tag])
 435        style = kwargs.pop("style", self._style)
 436        self.elements[tag] = widgets.FloatSlider(
 437            description=description,
 438            min=vmin,
 439            max=vmax,
 440            *args,
 441            **kwargs,
 442            layout=self._layout,
 443            style=style,
 444        )
 445
 446        if on_change is not None:
 447            self.elements[tag].observe(on_change, names="value")
 448
 449    def add_float_slider(
 450        self,
 451        tag: str,
 452        description: str,
 453        min: int,
 454        max: int,
 455        *args,
 456        remember_value=False,
 457        on_change: Optional[callable] = None,
 458        **kwargs,
 459    ):
 460        """
 461        @jupyter
 462        Add an float slider widget to the container.
 463
 464        Parameters
 465        ----------
 466        tag : str
 467            Tag to identify the widget.
 468        description : str
 469            The message to display.
 470        min : float
 471            Minimum value of the slider.
 472        max : float
 473            Maximum value of the slider.
 474        remember_value : bool, optional
 475            Whether to remember the last selected value. Defaults to False.
 476        *args : tuple
 477            Additional positional arguments for the widget.
 478        **kwargs : dict
 479            Additional keyword arguments for the widget.
 480        """
 481        self.add_float_range(
 482            tag,
 483            description,
 484            vmin=min,
 485            vmax=max,
 486            *args,
 487            remember_value=remember_value,
 488            **kwargs,
 489        )
 490
 491        if on_change is not None:
 492            self.elements[tag].observe(on_change, names="value")
 493
 494    def add_check(
 495        self,
 496        tag: str,
 497        description: str,
 498        *args,
 499        remember_value=False,
 500        on_change: Optional[callable] = None,
 501        **kwargs,
 502    ):
 503        """
 504        @unified
 505        Add a checkbox widget to the container.
 506
 507        Parameters
 508        ----------
 509        tag : str
 510            Tag to identify the widget.
 511        description : str
 512            The message to display.
 513        remember_value : bool, optional
 514            Whether to remember the last selected value. Defaults to False.
 515        *args : tuple
 516            Additional positional arguments for the widget.
 517        **kwargs : dict
 518            Additional keyword arguments for the widget.
 519        """
 520        if self.params is not None:
 521            if tag in self.params:
 522                kwargs["value"] = self.params[tag]
 523        elif remember_value and tag in self.cfg:
 524            kwargs["value"] = self.cfg[tag]
 525        style = kwargs.pop("style", self._style)
 526        self.elements[tag] = widgets.Checkbox(
 527            description=description,
 528            *args,
 529            **kwargs,
 530            layout=self._layout,
 531            style=style,
 532        )
 533
 534        if on_change is not None:
 535            self.elements[tag].observe(on_change, names="value")
 536
 537    def add_int_text(
 538        self,
 539        tag,
 540        description: str = "",
 541        *args,
 542        remember_value=False,
 543        on_change: Optional[callable] = None,
 544        **kwargs,
 545    ):
 546        """
 547        @unified
 548        Add an integer text widget to the container.
 549
 550        Parameters
 551        ----------
 552        tag : str
 553            Tag to identify the widget.
 554        description : str, optional
 555            The message to display. Defaults to "".
 556        remember_value : bool, optional
 557            Whether to remember the last entered value. Defaults to False.
 558        *args : tuple
 559            Additional positional arguments for the widget.
 560        **kwargs : dict
 561            Additional keyword arguments for the widget.
 562        """
 563        if self.params is not None:
 564            if tag in self.params:
 565                kwargs["value"] = self.params[tag]
 566        elif remember_value and tag in self.cfg:
 567            kwargs["value"] = self.cfg[tag]
 568
 569        style = kwargs.pop("style", self._style)
 570        self.elements[tag] = widgets.IntText(
 571            description=description,
 572            *args,
 573            **kwargs,
 574            layout=self._layout,
 575            style=style,
 576        )
 577
 578        if on_change is not None:
 579            self.elements[tag].observe(on_change, names="value")
 580
 581    def add_bounded_int_text(
 582        self,
 583        tag,
 584        description: str,
 585        vmin: int,
 586        vmax: int,
 587        *args,
 588        remember_value=False,
 589        on_change: Optional[callable] = None,
 590        **kwargs,
 591    ):
 592        """
 593        @unified
 594        Add a bounded integer text widget to the container.
 595
 596        Parameters
 597        ----------
 598        tag : str
 599            Tag to identify the widget.
 600        description : str
 601            The message to display.
 602        vmin : int
 603            Minimum value of the input field.
 604        vmax : int
 605            Maximum value of the input field.
 606        remember_value : bool, optional
 607            Whether to remember the last entered value. Defaults to False.
 608        *args : tuple
 609            Additional positional arguments for the widget.
 610        **kwargs : dict
 611            Additional keyword arguments for the widget.
 612        """
 613        if self.params is not None:
 614            if tag in self.params:
 615                kwargs["value"] = self.params[tag]
 616        elif remember_value and tag in self.cfg:
 617            kwargs["value"] = self.cfg[tag]
 618        style = kwargs.pop("style", self._style)
 619        self.elements[tag] = widgets.BoundedIntText(
 620            min=vmin,
 621            max=vmax,
 622            description=description,
 623            *args,
 624            **kwargs,
 625            layout=self._layout,
 626            style=style,
 627        )
 628
 629        if on_change is not None:
 630            self.elements[tag].observe(on_change, names="value")
 631
 632    def add_float_text(
 633        self,
 634        tag,
 635        description: str = "",
 636        *args,
 637        remember_value=False,
 638        on_change: Optional[callable] = None,
 639        **kwargs,
 640    ):
 641        """
 642        @unified
 643        Add a float text widget to the container.
 644
 645        Parameters
 646        ----------
 647        tag : str
 648            Tag to identify the widget.
 649        description : str, optional
 650            The message to display. Defaults to "".
 651        remember_value : bool, optional
 652            Whether to remember the last entered value. Defaults to False.
 653        *args : tuple
 654            Additional positional arguments for the widget.
 655        **kwargs : dict
 656            Additional keyword arguments for the widget.
 657        """
 658        if self.params is not None:
 659            if tag in self.params:
 660                kwargs["value"] = self.params[tag]
 661        elif remember_value and tag in self.cfg:
 662            kwargs["value"] = self.cfg[tag]
 663        style = kwargs.pop("style", self._style)
 664        self.elements[tag] = widgets.FloatText(
 665            description=description,
 666            *args,
 667            **kwargs,
 668            layout=self._layout,
 669            style=style,
 670        )
 671
 672        if on_change is not None:
 673            self.elements[tag].observe(on_change, names="value")
 674
 675    def add_bounded_float_text(
 676        self,
 677        tag,
 678        description: str,
 679        vmin: int,
 680        vmax: int,
 681        *args,
 682        remember_value=False,
 683        on_change: Optional[callable] = None,
 684        **kwargs,
 685    ):
 686        """
 687        @unified
 688        Add a bounded float text widget to the container.
 689
 690        Parameters
 691        ----------
 692        tag : str
 693            Tag to identify the widget.
 694        description : str
 695            The message to display.
 696        vmin : int
 697            Minimum value of the input field.
 698        vmax : int
 699            Maximum value of the input field.
 700        remember_value : bool, optional
 701            Whether to remember the last entered value. Defaults to False.
 702        *args : tuple
 703            Additional positional arguments for the widget.
 704        **kwargs : dict
 705            Additional keyword arguments for the widget.
 706        """
 707        if self.params is not None:
 708            if tag in self.params:
 709                kwargs["value"] = self.params[tag]
 710        elif remember_value and tag in self.cfg:
 711            kwargs["value"] = self.cfg[tag]
 712        style = kwargs.pop("style", self._style)
 713        self.elements[tag] = widgets.BoundedFloatText(
 714            min=vmin,
 715            max=vmax,
 716            description=description,
 717            *args,
 718            **kwargs,
 719            layout=self._layout,
 720            style=style,
 721        )
 722
 723        if on_change is not None:
 724            self.elements[tag].observe(on_change, names="value")
 725
 726    def add_dropdown(
 727        self,
 728        tag,
 729        options: list,
 730        description: str = "",
 731        *args,
 732        remember_value=False,
 733        on_change: Optional[callable] = None,
 734        **kwargs,
 735    ):
 736        """
 737        @unified
 738        Add a dropdown widget to the container.
 739
 740        Parameters
 741        ----------
 742        tag : str
 743            Tag to identify the widget.
 744        options : list
 745            List of choices for the dropdown.
 746        description : str, optional
 747            The message to display. Defaults to "".
 748        remember_value : bool, optional
 749            Whether to remember the last selected value. Defaults to False.
 750        *args : tuple
 751            Additional positional arguments for the widget.
 752        **kwargs : dict
 753            Additional keyword arguments for the widget.
 754        """
 755        if remember_value and tag in self.cfg and self.cfg[tag] in options:
 756            kwargs["value"] = self.cfg[tag]
 757        if self.params is not None:
 758            if tag in self.params:
 759                kwargs["value"] = self.params[tag]
 760        style = kwargs.pop("style", self._style)
 761        self.elements[tag] = widgets.Dropdown(
 762            options=options,
 763            description=description,
 764            *args,
 765            **kwargs,
 766            layout=self._layout,
 767            style=style,
 768        )
 769
 770        if on_change is not None:
 771            self.elements[tag].observe(on_change, names="value")
 772
 773    def add_checkbox(
 774        self,
 775        tag: str,
 776        description: str,
 777        *args,
 778        remember_value=False,
 779        on_change: Optional[callable] = None,
 780        **kwargs,
 781    ):
 782        """
 783        @jupyter
 784        Add a checkbox widget to the container.
 785
 786        Parameters
 787        ----------
 788        tag : str
 789            Tag to identify the widget.
 790        description : str
 791            The message to display.
 792        remember_value : bool, optional
 793            Whether to remember the last selected value. Defaults to False.
 794        *args : tuple
 795            Additional positional arguments for the widget.
 796        **kwargs : dict
 797            Additional keyword arguments for the widget.
 798        """
 799        self.add_check(
 800            tag,
 801            description=description,
 802            remember_value=remember_value,
 803            *args,
 804            **kwargs,
 805        )
 806
 807        if on_change is not None:
 808            self.elements[tag].observe(on_change, names="value")
 809
 810    def add_select_multiple(
 811        self, tag: str, options: list, description: str = "", *args, **kwargs
 812    ):
 813        """
 814        @jupyter
 815        Add a multiple selection widget to the container.
 816
 817        Parameters
 818        ----------
 819        tag : str
 820            Tag to identify the widget.
 821        options : list
 822            List of choices for the selection.
 823        *args : tuple
 824            Additional positional arguments for the widget.
 825        **kwargs : dict
 826            Additional keyword arguments for the widget.
 827        """
 828        style = kwargs.pop("style", self._style)
 829        self.elements[tag] = widgets.SelectMultiple(
 830            options=options,
 831            description=description,
 832            *args,
 833            **kwargs,
 834            layout=self._layout,
 835            style=style,
 836        )
 837
 838    def add_file_upload(
 839        self, tag, *args, accept=None, multiple=False, **kwargs
 840    ):
 841        """
 842        @jupyter
 843        Add a file upload widget to the container.
 844
 845        Parameters
 846        ----------
 847        tag : str
 848            Tag to identify the widget.
 849        accept : str, optional
 850            The file types to accept. Defaults to None.
 851        multiple : bool, optional
 852            Allow multiple files to be uploaded. Defaults to False.
 853        *args : tuple
 854            Additional positional arguments for the widget.
 855        **kwargs : dict
 856            Additional keyword arguments for the widget.
 857        """
 858        self.elements[tag] = FileChooser()
 859        if accept is not None:
 860            self.elements[tag].filter_pattern = accept
 861
 862    def add_output(self, tag: str, *args, **kwargs):
 863        """
 864        @unified
 865        Add an output widget to the container.
 866
 867        Parameters
 868        ----------
 869        tag : str
 870            Tag to identify the widget.
 871        *args : tuple
 872            Additional positional arguments for the widget.
 873        **kwargs : dict
 874            Additional keyword arguments for the widget.
 875        """
 876        style = kwargs.pop("style", self._style)
 877        self.elements[tag] = widgets.Output(
 878            *args,
 879            **kwargs,
 880            layout=self._layout,
 881            style=style,
 882        )
 883
 884    def add_custom_widget(
 885        self,
 886        tag: str,
 887        custom_widget,
 888        *args,
 889        remember_value=False,
 890        on_change: Optional[callable] = None,
 891        **kwargs,
 892    ):
 893        """
 894        @jupyter
 895        Add a custom widget to the container.
 896        Parameters
 897        ----------
 898        tag : str
 899            Tag to identify the widget.
 900        custom_widget : ipywidget to add
 901            The custom widget to add.
 902        *args : tuple
 903            Additional positional arguments for the widget.
 904        **kwargs : dict
 905            Additional keyword arguments for the widget.
 906        """
 907        if self.params is not None:
 908            if tag in self.params:
 909                kwargs["value"] = self.params[tag]
 910        elif remember_value and tag in self.cfg:
 911            kwargs["value"] = self.cfg[tag]
 912        style = kwargs.pop("style", self._style)
 913        self.elements[tag] = custom_widget(
 914            *args,
 915            **kwargs,
 916            layout=self._layout,
 917            style=style,
 918        )
 919
 920        if on_change is not None:
 921            self.elements[tag].observe(on_change, names="value")
 922
 923    def save_parameters(self, path: str):
 924        """
 925        @unified
 926        Save the widget values to a file.
 927
 928        Parameters
 929        ----------
 930        path : str
 931            The path to save the file.
 932        """
 933        if not path.endswith(".yml"):
 934            path += f"{self.title}_parameters.yml"
 935        out = {}
 936        for tag in self.elements:
 937            if tag.startswith("label_"):
 938                pass
 939            elif hasattr(self.elements[tag], "value"):
 940                out[tag] = self.elements[tag].value
 941        with open(path, "w") as f:
 942            yaml.dump(out, f)
 943
 944    def save_settings(self):
 945        """
 946        @unified
 947        Save the widget values to the configuration file.
 948        """
 949        for tag in self.elements:
 950            if tag.startswith("label_"):
 951                pass
 952            elif hasattr(self.elements[tag], "value"):
 953                if type(self.elements[tag].value) != tuple:
 954                    self.cfg[tag] = self.elements[tag].value
 955        config_file = CONFIG_PATH / f"{self.title}.yml"
 956        config_file.parent.mkdir(exist_ok=True)
 957
 958        base_config = self._get_config(self.title)  # loads the config file
 959        for key, value in self.cfg.items():
 960            base_config[key] = value
 961
 962        with open(config_file, "w") as f:
 963            yaml.dump(base_config, f)
 964
 965    def show(self):
 966        """
 967        @unified
 968        Display the widgets in the container.
 969        """
 970        self._main_display.children = tuple(self.elements.values())
 971        clear_output()
 972        display(self._main_display)
 973
 974    def clear_elements(self):
 975        """
 976        @unified
 977        Clear all widgets from the container.
 978        """
 979        self.elements = {}
 980        self._nLabels = 0
 981        self._main_display.children = ()
 982
 983    def _get_config(self, title: Optional[str]) -> dict:
 984        """
 985        Get the configuration dictionary without needing to initialize the GUI.
 986
 987        Parameters
 988        ----------
 989        title : str, optional
 990            The title of the GUI. If None, returns the entire configuration.
 991
 992        Returns
 993        -------
 994        dict
 995            The configuration dictionary.
 996        """
 997
 998        config_file = CONFIG_PATH / f"{title}.yml"
 999
1000        if not config_file.exists():
1001            return {}
1002
1003        with open(config_file, "r") as f:
1004            return yaml.load(f, Loader=yaml.SafeLoader)
CONFIG_PATH = PosixPath('/home/runner/.ezinput')
class EZInputJupyter:
  21class EZInputJupyter:
  22    """
  23    A class to create GUIs in Jupyter notebooks using `ipywidgets`.
  24
  25    Parameters
  26    ----------
  27    title : str, optional
  28        Title of the GUI, used to store settings. Defaults to "basic_gui".
  29    width : str, optional
  30        Width of the widget container. Defaults to "50%".
  31    """
  32
  33    def __init__(self, title="basic_gui", width="50%"):
  34        """
  35        Container for widgets.
  36
  37        Parameters
  38        ----------
  39        title : str, optional
  40            The title of the widget container, used to store settings.
  41        width : str, optional
  42            The width of the widget container.
  43        """
  44        pass
  45
  46    def __getvalue__(self, tag: str):
  47        """
  48        @unified
  49        Get the value of a widget.
  50
  51        Parameters
  52        ----------
  53        tag : str
  54            Tag to identify the widget.
  55
  56        Returns
  57        -------
  58        Any
  59            The value of the widget.
  60        """
  61        return self.elements[tag].value
  62
  63    def __getitem__(self, tag: str) -> widgets.Widget:
  64        """
  65        Get a widget by tag.
  66
  67        Parameters
  68        ----------
  69        tag : str
  70            The tag of the widget.
  71
  72        Returns
  73        -------
  74        widgets.Widget
  75            The widget.
  76        """
  77        return self.elements[tag]
  78
  79    def __len__(self) -> int:
  80        """
  81        Get the number of widgets.
  82
  83        Returns
  84        -------
  85        int
  86            The number of widgets.
  87        """
  88        return len(self.elements)
  89
  90    def add_label(self, value="", *args, **kwargs):
  91        """
  92        @unified
  93        Add a label widget to the container.
  94
  95        Parameters
  96        ----------
  97        label : str, optional
  98            The label text to display. Defaults to "".
  99        *args : tuple
 100            Additional positional arguments for the widget.
 101        **kwargs : dict
 102            Additional keyword arguments for the widget.
 103        """
 104        self._nLabels += 1
 105        style = kwargs.pop("style", self._style)
 106        self.elements[f"label_{self._nLabels}"] = widgets.Label(
 107            value=value,
 108            *args,
 109            **kwargs,
 110            layout=self._layout,
 111            style=style,
 112        )
 113
 114    def add_text(
 115        self,
 116        tag: str,
 117        description: str = "",
 118        placeholder: str = "",
 119        *args,
 120        remember_value=False,
 121        **kwargs,
 122    ):
 123        """
 124        @unified
 125        Add a text widget to the container.
 126
 127        Parameters
 128        ----------
 129        tag : str
 130            Tag to identify the widget.
 131        description : str, optional
 132            The message to display. Defaults to "".
 133        placeholder : str, optional
 134            Placeholder text for the input field. Defaults to "".
 135        remember_value : bool, optional
 136            Whether to remember the last entered value. Defaults to False.
 137        *args : tuple
 138            Additional positional arguments for the widget.
 139        **kwargs : dict
 140            Additional keyword arguments for the widget.
 141        """
 142        if self.params is not None:
 143            if tag in self.params:
 144                kwargs["value"] = self.params[tag]
 145        elif remember_value and tag in self.cfg:
 146            kwargs["value"] = str(self.cfg[tag])
 147
 148        style = kwargs.pop("style", self._style)
 149        self.elements[tag] = widgets.Text(
 150            description=description,
 151            placeholder=placeholder,
 152            *args,
 153            **kwargs,
 154            layout=self._layout,
 155            style=style,
 156        )
 157
 158    def add_callback(
 159        self, tag, func, values: dict, description="Run", *args, **kwargs
 160    ):
 161        """
 162        @unified
 163        Add a button widget to the container.
 164
 165        Parameters
 166        ----------
 167        tag : str
 168            Tag to identify the widget.
 169        func : callable
 170            The function to call when the button is clicked.
 171        values : dict
 172            Dictionary of widget values to pass to the callback function.
 173        description : str, optional
 174            The label for the button. Defaults to "Run".
 175        *args : tuple
 176            Additional positional arguments for the button.
 177        **kwargs : dict
 178            Additional keyword arguments for the button.
 179        """
 180        style = kwargs.pop("style", self._style)
 181        self.elements[tag] = widgets.Button(
 182            description=description,
 183            *args,
 184            **kwargs,
 185            layout=self._layout,
 186            style=style,
 187        )
 188
 189        def wrapped(button):
 190            self.save_settings()
 191            func(values)
 192
 193        self.elements[tag].on_click(wrapped)
 194
 195    def add_button(self, tag, description="Run", *args, **kwargs):
 196        """
 197        @jupyter
 198        Add a button widget to the container.
 199
 200        Parameters
 201        ----------
 202        tag : str
 203            Tag to identify the widget.
 204        description : str, optional
 205            The label for the button. Defaults to "Run".
 206        *args : tuple
 207            Additional positional arguments for the widget.
 208        **kwargs : dict
 209            Additional keyword arguments for the widget.
 210        """
 211        style = kwargs.pop("style", self._style)
 212        self.elements[tag] = widgets.Button(
 213            description=description,
 214            *args,
 215            **kwargs,
 216            layout=self._layout,
 217            style=style,
 218        )
 219
 220    def add_text_area(
 221        self,
 222        tag: str,
 223        description: str = "",
 224        placeholder: str = "",
 225        *args,
 226        remember_value=False,
 227        on_change: Optional[callable] = None,
 228        **kwargs,
 229    ):
 230        """
 231        @unified
 232        Add a textarea widget to the container.
 233
 234        Parameters
 235        ----------
 236        tag : str
 237            Tag to identify the widget.
 238        description : str, optional
 239            The message to display. Defaults to "".
 240        placeholder : str, optional
 241            Placeholder text for the input field. Defaults to "".
 242        remember_value : bool, optional
 243            Whether to remember the last entered value. Defaults to False.
 244        *args : tuple
 245            Additional positional arguments for the widget.
 246        **kwargs : dict
 247            Additional keyword arguments for the widget.
 248        """
 249        if self.params is not None:
 250            if tag in self.params:
 251                kwargs["value"] = self.params[tag]
 252        elif remember_value and tag in self.cfg:
 253            kwargs["value"] = str(self.cfg[tag])
 254        style = kwargs.pop("style", self._style)
 255        self.elements[tag] = widgets.Textarea(
 256            description=description,
 257            placeholder=placeholder,
 258            *args,
 259            **kwargs,
 260            layout=self._layout,
 261            style=style,
 262        )
 263
 264        if on_change is not None:
 265            self.elements[tag].observe(on_change, names="value")
 266
 267    def add_HTML(
 268        self, tag: str, value: str, description: str = "", *args, **kwargs
 269    ):
 270        """
 271        @jupyter
 272        Add an HTML widget to the container.
 273
 274        Parameters
 275        ----------
 276        tag : str
 277            Tag to identify the widget.
 278        value : str
 279            The HTML content to display.
 280        *args : tuple
 281            Additional positional arguments for the widget.
 282        **kwargs : dict
 283            Additional keyword arguments for the widget.
 284        """
 285        style = kwargs.pop("style", self._style)
 286        self.elements[tag] = widgets.HTML(
 287            value=value,
 288            description=description,
 289            *args,
 290            **kwargs,
 291            layout=self._layout,
 292            style=style,
 293        )
 294
 295    def add_int_range(
 296        self,
 297        tag: str,
 298        description: str,
 299        vmin: int,
 300        vmax: int,
 301        *args,
 302        remember_value=False,
 303        on_change: Optional[callable] = None,
 304        **kwargs,
 305    ):
 306        """
 307        @unified
 308        Add an integer slider widget to the container.
 309
 310        Parameters
 311        ----------
 312        tag : str
 313            Tag to identify the widget.
 314        description : str
 315            The message to display.
 316        vmin : int
 317            Minimum value of the slider.
 318        vmax : int
 319            Maximum value of the slider.
 320        remember_value : bool, optional
 321            Whether to remember the last selected value. Defaults to False.
 322        *args : tuple
 323            Additional positional arguments for the widget.
 324        **kwargs : dict
 325            Additional keyword arguments for the widget.
 326        """
 327        if self.params is not None:
 328            if tag in self.params and vmin <= self.params[tag] <= vmax:
 329                kwargs["value"] = self.params[tag]
 330        elif (
 331            remember_value
 332            and tag in self.cfg
 333            and vmin <= self.cfg[tag] <= vmax
 334        ):
 335            kwargs["value"] = int(self.cfg[tag])
 336        style = kwargs.pop("style", self._style)
 337        self.elements[tag] = widgets.IntSlider(
 338            description=description,
 339            min=vmin,
 340            max=vmax,
 341            *args,
 342            **kwargs,
 343            layout=self._layout,
 344            style=style,
 345        )
 346
 347        if on_change is not None:
 348            self.elements[tag].observe(on_change, names="value")
 349
 350    def add_int_slider(
 351        self,
 352        tag: str,
 353        description: str,
 354        min: int,
 355        max: int,
 356        *args,
 357        remember_value=False,
 358        on_change: Optional[callable] = None,
 359        **kwargs,
 360    ):
 361        """
 362        @jupyter
 363        Add an integer slider widget to the container.
 364
 365        Parameters
 366        ----------
 367        tag : str
 368            Tag to identify the widget.
 369        description : str
 370            The message to display.
 371        vmin : int
 372            Minimum value of the slider.
 373        vmax : int
 374            Maximum value of the slider.
 375        remember_value : bool, optional
 376            Whether to remember the last selected value. Defaults to False.
 377        *args : tuple
 378            Additional positional arguments for the widget.
 379        **kwargs : dict
 380            Additional keyword arguments for the widget.
 381        """
 382        self.add_int_range(
 383            tag,
 384            description,
 385            vmin=min,
 386            vmax=max,
 387            *args,
 388            remember_value=remember_value,
 389            **kwargs,
 390        )
 391
 392        if on_change is not None:
 393            self.elements[tag].observe(on_change, names="value")
 394
 395    def add_float_range(
 396        self,
 397        tag: str,
 398        description: str,
 399        vmin: float,
 400        vmax: float,
 401        *args,
 402        remember_value=False,
 403        on_change: Optional[callable] = None,
 404        **kwargs,
 405    ):
 406        """
 407        @unified
 408        Add a float slider widget to the container.
 409
 410        Parameters
 411        ----------
 412        tag : str
 413            Tag to identify the widget.
 414        description : str
 415            The message to display.
 416        vmin : float
 417            Minimum value of the slider.
 418        vmax : float
 419            Maximum value of the slider.
 420        remember_value : bool, optional
 421            Whether to remember the last selected value. Defaults to False.
 422        *args : tuple
 423            Additional positional arguments for the widget.
 424        **kwargs : dict
 425            Additional keyword arguments for the widget.
 426        """
 427        if self.params is not None:
 428            if tag in self.params and vmin <= self.params[tag] <= vmax:
 429                kwargs["value"] = self.params[tag]
 430        elif (
 431            remember_value
 432            and tag in self.cfg
 433            and vmin <= self.cfg[tag] <= vmax
 434        ):
 435            kwargs["value"] = int(self.cfg[tag])
 436        style = kwargs.pop("style", self._style)
 437        self.elements[tag] = widgets.FloatSlider(
 438            description=description,
 439            min=vmin,
 440            max=vmax,
 441            *args,
 442            **kwargs,
 443            layout=self._layout,
 444            style=style,
 445        )
 446
 447        if on_change is not None:
 448            self.elements[tag].observe(on_change, names="value")
 449
 450    def add_float_slider(
 451        self,
 452        tag: str,
 453        description: str,
 454        min: int,
 455        max: int,
 456        *args,
 457        remember_value=False,
 458        on_change: Optional[callable] = None,
 459        **kwargs,
 460    ):
 461        """
 462        @jupyter
 463        Add an float slider widget to the container.
 464
 465        Parameters
 466        ----------
 467        tag : str
 468            Tag to identify the widget.
 469        description : str
 470            The message to display.
 471        min : float
 472            Minimum value of the slider.
 473        max : float
 474            Maximum value of the slider.
 475        remember_value : bool, optional
 476            Whether to remember the last selected value. Defaults to False.
 477        *args : tuple
 478            Additional positional arguments for the widget.
 479        **kwargs : dict
 480            Additional keyword arguments for the widget.
 481        """
 482        self.add_float_range(
 483            tag,
 484            description,
 485            vmin=min,
 486            vmax=max,
 487            *args,
 488            remember_value=remember_value,
 489            **kwargs,
 490        )
 491
 492        if on_change is not None:
 493            self.elements[tag].observe(on_change, names="value")
 494
 495    def add_check(
 496        self,
 497        tag: str,
 498        description: str,
 499        *args,
 500        remember_value=False,
 501        on_change: Optional[callable] = None,
 502        **kwargs,
 503    ):
 504        """
 505        @unified
 506        Add a checkbox widget to the container.
 507
 508        Parameters
 509        ----------
 510        tag : str
 511            Tag to identify the widget.
 512        description : str
 513            The message to display.
 514        remember_value : bool, optional
 515            Whether to remember the last selected value. Defaults to False.
 516        *args : tuple
 517            Additional positional arguments for the widget.
 518        **kwargs : dict
 519            Additional keyword arguments for the widget.
 520        """
 521        if self.params is not None:
 522            if tag in self.params:
 523                kwargs["value"] = self.params[tag]
 524        elif remember_value and tag in self.cfg:
 525            kwargs["value"] = self.cfg[tag]
 526        style = kwargs.pop("style", self._style)
 527        self.elements[tag] = widgets.Checkbox(
 528            description=description,
 529            *args,
 530            **kwargs,
 531            layout=self._layout,
 532            style=style,
 533        )
 534
 535        if on_change is not None:
 536            self.elements[tag].observe(on_change, names="value")
 537
 538    def add_int_text(
 539        self,
 540        tag,
 541        description: str = "",
 542        *args,
 543        remember_value=False,
 544        on_change: Optional[callable] = None,
 545        **kwargs,
 546    ):
 547        """
 548        @unified
 549        Add an integer text widget to the container.
 550
 551        Parameters
 552        ----------
 553        tag : str
 554            Tag to identify the widget.
 555        description : str, optional
 556            The message to display. Defaults to "".
 557        remember_value : bool, optional
 558            Whether to remember the last entered value. Defaults to False.
 559        *args : tuple
 560            Additional positional arguments for the widget.
 561        **kwargs : dict
 562            Additional keyword arguments for the widget.
 563        """
 564        if self.params is not None:
 565            if tag in self.params:
 566                kwargs["value"] = self.params[tag]
 567        elif remember_value and tag in self.cfg:
 568            kwargs["value"] = self.cfg[tag]
 569
 570        style = kwargs.pop("style", self._style)
 571        self.elements[tag] = widgets.IntText(
 572            description=description,
 573            *args,
 574            **kwargs,
 575            layout=self._layout,
 576            style=style,
 577        )
 578
 579        if on_change is not None:
 580            self.elements[tag].observe(on_change, names="value")
 581
 582    def add_bounded_int_text(
 583        self,
 584        tag,
 585        description: str,
 586        vmin: int,
 587        vmax: int,
 588        *args,
 589        remember_value=False,
 590        on_change: Optional[callable] = None,
 591        **kwargs,
 592    ):
 593        """
 594        @unified
 595        Add a bounded integer text widget to the container.
 596
 597        Parameters
 598        ----------
 599        tag : str
 600            Tag to identify the widget.
 601        description : str
 602            The message to display.
 603        vmin : int
 604            Minimum value of the input field.
 605        vmax : int
 606            Maximum value of the input field.
 607        remember_value : bool, optional
 608            Whether to remember the last entered value. Defaults to False.
 609        *args : tuple
 610            Additional positional arguments for the widget.
 611        **kwargs : dict
 612            Additional keyword arguments for the widget.
 613        """
 614        if self.params is not None:
 615            if tag in self.params:
 616                kwargs["value"] = self.params[tag]
 617        elif remember_value and tag in self.cfg:
 618            kwargs["value"] = self.cfg[tag]
 619        style = kwargs.pop("style", self._style)
 620        self.elements[tag] = widgets.BoundedIntText(
 621            min=vmin,
 622            max=vmax,
 623            description=description,
 624            *args,
 625            **kwargs,
 626            layout=self._layout,
 627            style=style,
 628        )
 629
 630        if on_change is not None:
 631            self.elements[tag].observe(on_change, names="value")
 632
 633    def add_float_text(
 634        self,
 635        tag,
 636        description: str = "",
 637        *args,
 638        remember_value=False,
 639        on_change: Optional[callable] = None,
 640        **kwargs,
 641    ):
 642        """
 643        @unified
 644        Add a float text widget to the container.
 645
 646        Parameters
 647        ----------
 648        tag : str
 649            Tag to identify the widget.
 650        description : str, optional
 651            The message to display. Defaults to "".
 652        remember_value : bool, optional
 653            Whether to remember the last entered value. Defaults to False.
 654        *args : tuple
 655            Additional positional arguments for the widget.
 656        **kwargs : dict
 657            Additional keyword arguments for the widget.
 658        """
 659        if self.params is not None:
 660            if tag in self.params:
 661                kwargs["value"] = self.params[tag]
 662        elif remember_value and tag in self.cfg:
 663            kwargs["value"] = self.cfg[tag]
 664        style = kwargs.pop("style", self._style)
 665        self.elements[tag] = widgets.FloatText(
 666            description=description,
 667            *args,
 668            **kwargs,
 669            layout=self._layout,
 670            style=style,
 671        )
 672
 673        if on_change is not None:
 674            self.elements[tag].observe(on_change, names="value")
 675
 676    def add_bounded_float_text(
 677        self,
 678        tag,
 679        description: str,
 680        vmin: int,
 681        vmax: int,
 682        *args,
 683        remember_value=False,
 684        on_change: Optional[callable] = None,
 685        **kwargs,
 686    ):
 687        """
 688        @unified
 689        Add a bounded float text widget to the container.
 690
 691        Parameters
 692        ----------
 693        tag : str
 694            Tag to identify the widget.
 695        description : str
 696            The message to display.
 697        vmin : int
 698            Minimum value of the input field.
 699        vmax : int
 700            Maximum value of the input field.
 701        remember_value : bool, optional
 702            Whether to remember the last entered value. Defaults to False.
 703        *args : tuple
 704            Additional positional arguments for the widget.
 705        **kwargs : dict
 706            Additional keyword arguments for the widget.
 707        """
 708        if self.params is not None:
 709            if tag in self.params:
 710                kwargs["value"] = self.params[tag]
 711        elif remember_value and tag in self.cfg:
 712            kwargs["value"] = self.cfg[tag]
 713        style = kwargs.pop("style", self._style)
 714        self.elements[tag] = widgets.BoundedFloatText(
 715            min=vmin,
 716            max=vmax,
 717            description=description,
 718            *args,
 719            **kwargs,
 720            layout=self._layout,
 721            style=style,
 722        )
 723
 724        if on_change is not None:
 725            self.elements[tag].observe(on_change, names="value")
 726
 727    def add_dropdown(
 728        self,
 729        tag,
 730        options: list,
 731        description: str = "",
 732        *args,
 733        remember_value=False,
 734        on_change: Optional[callable] = None,
 735        **kwargs,
 736    ):
 737        """
 738        @unified
 739        Add a dropdown widget to the container.
 740
 741        Parameters
 742        ----------
 743        tag : str
 744            Tag to identify the widget.
 745        options : list
 746            List of choices for the dropdown.
 747        description : str, optional
 748            The message to display. Defaults to "".
 749        remember_value : bool, optional
 750            Whether to remember the last selected value. Defaults to False.
 751        *args : tuple
 752            Additional positional arguments for the widget.
 753        **kwargs : dict
 754            Additional keyword arguments for the widget.
 755        """
 756        if remember_value and tag in self.cfg and self.cfg[tag] in options:
 757            kwargs["value"] = self.cfg[tag]
 758        if self.params is not None:
 759            if tag in self.params:
 760                kwargs["value"] = self.params[tag]
 761        style = kwargs.pop("style", self._style)
 762        self.elements[tag] = widgets.Dropdown(
 763            options=options,
 764            description=description,
 765            *args,
 766            **kwargs,
 767            layout=self._layout,
 768            style=style,
 769        )
 770
 771        if on_change is not None:
 772            self.elements[tag].observe(on_change, names="value")
 773
 774    def add_checkbox(
 775        self,
 776        tag: str,
 777        description: str,
 778        *args,
 779        remember_value=False,
 780        on_change: Optional[callable] = None,
 781        **kwargs,
 782    ):
 783        """
 784        @jupyter
 785        Add a checkbox widget to the container.
 786
 787        Parameters
 788        ----------
 789        tag : str
 790            Tag to identify the widget.
 791        description : str
 792            The message to display.
 793        remember_value : bool, optional
 794            Whether to remember the last selected value. Defaults to False.
 795        *args : tuple
 796            Additional positional arguments for the widget.
 797        **kwargs : dict
 798            Additional keyword arguments for the widget.
 799        """
 800        self.add_check(
 801            tag,
 802            description=description,
 803            remember_value=remember_value,
 804            *args,
 805            **kwargs,
 806        )
 807
 808        if on_change is not None:
 809            self.elements[tag].observe(on_change, names="value")
 810
 811    def add_select_multiple(
 812        self, tag: str, options: list, description: str = "", *args, **kwargs
 813    ):
 814        """
 815        @jupyter
 816        Add a multiple selection widget to the container.
 817
 818        Parameters
 819        ----------
 820        tag : str
 821            Tag to identify the widget.
 822        options : list
 823            List of choices for the selection.
 824        *args : tuple
 825            Additional positional arguments for the widget.
 826        **kwargs : dict
 827            Additional keyword arguments for the widget.
 828        """
 829        style = kwargs.pop("style", self._style)
 830        self.elements[tag] = widgets.SelectMultiple(
 831            options=options,
 832            description=description,
 833            *args,
 834            **kwargs,
 835            layout=self._layout,
 836            style=style,
 837        )
 838
 839    def add_file_upload(
 840        self, tag, *args, accept=None, multiple=False, **kwargs
 841    ):
 842        """
 843        @jupyter
 844        Add a file upload widget to the container.
 845
 846        Parameters
 847        ----------
 848        tag : str
 849            Tag to identify the widget.
 850        accept : str, optional
 851            The file types to accept. Defaults to None.
 852        multiple : bool, optional
 853            Allow multiple files to be uploaded. Defaults to False.
 854        *args : tuple
 855            Additional positional arguments for the widget.
 856        **kwargs : dict
 857            Additional keyword arguments for the widget.
 858        """
 859        self.elements[tag] = FileChooser()
 860        if accept is not None:
 861            self.elements[tag].filter_pattern = accept
 862
 863    def add_output(self, tag: str, *args, **kwargs):
 864        """
 865        @unified
 866        Add an output widget to the container.
 867
 868        Parameters
 869        ----------
 870        tag : str
 871            Tag to identify the widget.
 872        *args : tuple
 873            Additional positional arguments for the widget.
 874        **kwargs : dict
 875            Additional keyword arguments for the widget.
 876        """
 877        style = kwargs.pop("style", self._style)
 878        self.elements[tag] = widgets.Output(
 879            *args,
 880            **kwargs,
 881            layout=self._layout,
 882            style=style,
 883        )
 884
 885    def add_custom_widget(
 886        self,
 887        tag: str,
 888        custom_widget,
 889        *args,
 890        remember_value=False,
 891        on_change: Optional[callable] = None,
 892        **kwargs,
 893    ):
 894        """
 895        @jupyter
 896        Add a custom widget to the container.
 897        Parameters
 898        ----------
 899        tag : str
 900            Tag to identify the widget.
 901        custom_widget : ipywidget to add
 902            The custom widget to add.
 903        *args : tuple
 904            Additional positional arguments for the widget.
 905        **kwargs : dict
 906            Additional keyword arguments for the widget.
 907        """
 908        if self.params is not None:
 909            if tag in self.params:
 910                kwargs["value"] = self.params[tag]
 911        elif remember_value and tag in self.cfg:
 912            kwargs["value"] = self.cfg[tag]
 913        style = kwargs.pop("style", self._style)
 914        self.elements[tag] = custom_widget(
 915            *args,
 916            **kwargs,
 917            layout=self._layout,
 918            style=style,
 919        )
 920
 921        if on_change is not None:
 922            self.elements[tag].observe(on_change, names="value")
 923
 924    def save_parameters(self, path: str):
 925        """
 926        @unified
 927        Save the widget values to a file.
 928
 929        Parameters
 930        ----------
 931        path : str
 932            The path to save the file.
 933        """
 934        if not path.endswith(".yml"):
 935            path += f"{self.title}_parameters.yml"
 936        out = {}
 937        for tag in self.elements:
 938            if tag.startswith("label_"):
 939                pass
 940            elif hasattr(self.elements[tag], "value"):
 941                out[tag] = self.elements[tag].value
 942        with open(path, "w") as f:
 943            yaml.dump(out, f)
 944
 945    def save_settings(self):
 946        """
 947        @unified
 948        Save the widget values to the configuration file.
 949        """
 950        for tag in self.elements:
 951            if tag.startswith("label_"):
 952                pass
 953            elif hasattr(self.elements[tag], "value"):
 954                if type(self.elements[tag].value) != tuple:
 955                    self.cfg[tag] = self.elements[tag].value
 956        config_file = CONFIG_PATH / f"{self.title}.yml"
 957        config_file.parent.mkdir(exist_ok=True)
 958
 959        base_config = self._get_config(self.title)  # loads the config file
 960        for key, value in self.cfg.items():
 961            base_config[key] = value
 962
 963        with open(config_file, "w") as f:
 964            yaml.dump(base_config, f)
 965
 966    def show(self):
 967        """
 968        @unified
 969        Display the widgets in the container.
 970        """
 971        self._main_display.children = tuple(self.elements.values())
 972        clear_output()
 973        display(self._main_display)
 974
 975    def clear_elements(self):
 976        """
 977        @unified
 978        Clear all widgets from the container.
 979        """
 980        self.elements = {}
 981        self._nLabels = 0
 982        self._main_display.children = ()
 983
 984    def _get_config(self, title: Optional[str]) -> dict:
 985        """
 986        Get the configuration dictionary without needing to initialize the GUI.
 987
 988        Parameters
 989        ----------
 990        title : str, optional
 991            The title of the GUI. If None, returns the entire configuration.
 992
 993        Returns
 994        -------
 995        dict
 996            The configuration dictionary.
 997        """
 998
 999        config_file = CONFIG_PATH / f"{title}.yml"
1000
1001        if not config_file.exists():
1002            return {}
1003
1004        with open(config_file, "r") as f:
1005            return yaml.load(f, Loader=yaml.SafeLoader)

A class to create GUIs in Jupyter notebooks using ipywidgets.

Parameters

title : str, optional Title of the GUI, used to store settings. Defaults to "basic_gui". width : str, optional Width of the widget container. Defaults to "50%".

EZInputJupyter(title='basic_gui', width='50%')
33    def __init__(self, title="basic_gui", width="50%"):
34        """
35        Container for widgets.
36
37        Parameters
38        ----------
39        title : str, optional
40            The title of the widget container, used to store settings.
41        width : str, optional
42            The width of the widget container.
43        """
44        pass

Container for widgets.

Parameters

title : str, optional The title of the widget container, used to store settings. width : str, optional The width of the widget container.

def add_label(self, value='', *args, **kwargs):
 90    def add_label(self, value="", *args, **kwargs):
 91        """
 92        @unified
 93        Add a label widget to the container.
 94
 95        Parameters
 96        ----------
 97        label : str, optional
 98            The label text to display. Defaults to "".
 99        *args : tuple
100            Additional positional arguments for the widget.
101        **kwargs : dict
102            Additional keyword arguments for the widget.
103        """
104        self._nLabels += 1
105        style = kwargs.pop("style", self._style)
106        self.elements[f"label_{self._nLabels}"] = widgets.Label(
107            value=value,
108            *args,
109            **kwargs,
110            layout=self._layout,
111            style=style,
112        )

@unified Add a label widget to the container.

Parameters

label : str, optional The label text to display. Defaults to "". args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_text( self, tag: str, description: str = '', placeholder: str = '', *args, remember_value=False, **kwargs):
114    def add_text(
115        self,
116        tag: str,
117        description: str = "",
118        placeholder: str = "",
119        *args,
120        remember_value=False,
121        **kwargs,
122    ):
123        """
124        @unified
125        Add a text widget to the container.
126
127        Parameters
128        ----------
129        tag : str
130            Tag to identify the widget.
131        description : str, optional
132            The message to display. Defaults to "".
133        placeholder : str, optional
134            Placeholder text for the input field. Defaults to "".
135        remember_value : bool, optional
136            Whether to remember the last entered value. Defaults to False.
137        *args : tuple
138            Additional positional arguments for the widget.
139        **kwargs : dict
140            Additional keyword arguments for the widget.
141        """
142        if self.params is not None:
143            if tag in self.params:
144                kwargs["value"] = self.params[tag]
145        elif remember_value and tag in self.cfg:
146            kwargs["value"] = str(self.cfg[tag])
147
148        style = kwargs.pop("style", self._style)
149        self.elements[tag] = widgets.Text(
150            description=description,
151            placeholder=placeholder,
152            *args,
153            **kwargs,
154            layout=self._layout,
155            style=style,
156        )

@unified Add a text widget to the container.

Parameters

tag : str Tag to identify the widget. description : str, optional The message to display. Defaults to "". placeholder : str, optional Placeholder text for the input field. Defaults to "". remember_value : bool, optional Whether to remember the last entered value. Defaults to False. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_callback(self, tag, func, values: dict, description='Run', *args, **kwargs):
158    def add_callback(
159        self, tag, func, values: dict, description="Run", *args, **kwargs
160    ):
161        """
162        @unified
163        Add a button widget to the container.
164
165        Parameters
166        ----------
167        tag : str
168            Tag to identify the widget.
169        func : callable
170            The function to call when the button is clicked.
171        values : dict
172            Dictionary of widget values to pass to the callback function.
173        description : str, optional
174            The label for the button. Defaults to "Run".
175        *args : tuple
176            Additional positional arguments for the button.
177        **kwargs : dict
178            Additional keyword arguments for the button.
179        """
180        style = kwargs.pop("style", self._style)
181        self.elements[tag] = widgets.Button(
182            description=description,
183            *args,
184            **kwargs,
185            layout=self._layout,
186            style=style,
187        )
188
189        def wrapped(button):
190            self.save_settings()
191            func(values)
192
193        self.elements[tag].on_click(wrapped)

@unified Add a button widget to the container.

Parameters

tag : str Tag to identify the widget. func : callable The function to call when the button is clicked. values : dict Dictionary of widget values to pass to the callback function. description : str, optional The label for the button. Defaults to "Run". args : tuple Additional positional arguments for the button. *kwargs : dict Additional keyword arguments for the button.

def add_button(self, tag, description='Run', *args, **kwargs):
195    def add_button(self, tag, description="Run", *args, **kwargs):
196        """
197        @jupyter
198        Add a button widget to the container.
199
200        Parameters
201        ----------
202        tag : str
203            Tag to identify the widget.
204        description : str, optional
205            The label for the button. Defaults to "Run".
206        *args : tuple
207            Additional positional arguments for the widget.
208        **kwargs : dict
209            Additional keyword arguments for the widget.
210        """
211        style = kwargs.pop("style", self._style)
212        self.elements[tag] = widgets.Button(
213            description=description,
214            *args,
215            **kwargs,
216            layout=self._layout,
217            style=style,
218        )

@jupyter Add a button widget to the container.

Parameters

tag : str Tag to identify the widget. description : str, optional The label for the button. Defaults to "Run". args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_text_area( self, tag: str, description: str = '', placeholder: str = '', *args, remember_value=False, on_change: Optional[<built-in function callable>] = None, **kwargs):
220    def add_text_area(
221        self,
222        tag: str,
223        description: str = "",
224        placeholder: str = "",
225        *args,
226        remember_value=False,
227        on_change: Optional[callable] = None,
228        **kwargs,
229    ):
230        """
231        @unified
232        Add a textarea widget to the container.
233
234        Parameters
235        ----------
236        tag : str
237            Tag to identify the widget.
238        description : str, optional
239            The message to display. Defaults to "".
240        placeholder : str, optional
241            Placeholder text for the input field. Defaults to "".
242        remember_value : bool, optional
243            Whether to remember the last entered value. Defaults to False.
244        *args : tuple
245            Additional positional arguments for the widget.
246        **kwargs : dict
247            Additional keyword arguments for the widget.
248        """
249        if self.params is not None:
250            if tag in self.params:
251                kwargs["value"] = self.params[tag]
252        elif remember_value and tag in self.cfg:
253            kwargs["value"] = str(self.cfg[tag])
254        style = kwargs.pop("style", self._style)
255        self.elements[tag] = widgets.Textarea(
256            description=description,
257            placeholder=placeholder,
258            *args,
259            **kwargs,
260            layout=self._layout,
261            style=style,
262        )
263
264        if on_change is not None:
265            self.elements[tag].observe(on_change, names="value")

@unified Add a textarea widget to the container.

Parameters

tag : str Tag to identify the widget. description : str, optional The message to display. Defaults to "". placeholder : str, optional Placeholder text for the input field. Defaults to "". remember_value : bool, optional Whether to remember the last entered value. Defaults to False. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_HTML(self, tag: str, value: str, description: str = '', *args, **kwargs):
267    def add_HTML(
268        self, tag: str, value: str, description: str = "", *args, **kwargs
269    ):
270        """
271        @jupyter
272        Add an HTML widget to the container.
273
274        Parameters
275        ----------
276        tag : str
277            Tag to identify the widget.
278        value : str
279            The HTML content to display.
280        *args : tuple
281            Additional positional arguments for the widget.
282        **kwargs : dict
283            Additional keyword arguments for the widget.
284        """
285        style = kwargs.pop("style", self._style)
286        self.elements[tag] = widgets.HTML(
287            value=value,
288            description=description,
289            *args,
290            **kwargs,
291            layout=self._layout,
292            style=style,
293        )

@jupyter Add an HTML widget to the container.

Parameters

tag : str Tag to identify the widget. value : str The HTML content to display. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_int_range( self, tag: str, description: str, vmin: int, vmax: int, *args, remember_value=False, on_change: Optional[<built-in function callable>] = None, **kwargs):
295    def add_int_range(
296        self,
297        tag: str,
298        description: str,
299        vmin: int,
300        vmax: int,
301        *args,
302        remember_value=False,
303        on_change: Optional[callable] = None,
304        **kwargs,
305    ):
306        """
307        @unified
308        Add an integer slider widget to the container.
309
310        Parameters
311        ----------
312        tag : str
313            Tag to identify the widget.
314        description : str
315            The message to display.
316        vmin : int
317            Minimum value of the slider.
318        vmax : int
319            Maximum value of the slider.
320        remember_value : bool, optional
321            Whether to remember the last selected value. Defaults to False.
322        *args : tuple
323            Additional positional arguments for the widget.
324        **kwargs : dict
325            Additional keyword arguments for the widget.
326        """
327        if self.params is not None:
328            if tag in self.params and vmin <= self.params[tag] <= vmax:
329                kwargs["value"] = self.params[tag]
330        elif (
331            remember_value
332            and tag in self.cfg
333            and vmin <= self.cfg[tag] <= vmax
334        ):
335            kwargs["value"] = int(self.cfg[tag])
336        style = kwargs.pop("style", self._style)
337        self.elements[tag] = widgets.IntSlider(
338            description=description,
339            min=vmin,
340            max=vmax,
341            *args,
342            **kwargs,
343            layout=self._layout,
344            style=style,
345        )
346
347        if on_change is not None:
348            self.elements[tag].observe(on_change, names="value")

@unified Add an integer slider widget to the container.

Parameters

tag : str Tag to identify the widget. description : str The message to display. vmin : int Minimum value of the slider. vmax : int Maximum value of the slider. remember_value : bool, optional Whether to remember the last selected value. Defaults to False. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_int_slider( self, tag: str, description: str, min: int, max: int, *args, remember_value=False, on_change: Optional[<built-in function callable>] = None, **kwargs):
350    def add_int_slider(
351        self,
352        tag: str,
353        description: str,
354        min: int,
355        max: int,
356        *args,
357        remember_value=False,
358        on_change: Optional[callable] = None,
359        **kwargs,
360    ):
361        """
362        @jupyter
363        Add an integer slider widget to the container.
364
365        Parameters
366        ----------
367        tag : str
368            Tag to identify the widget.
369        description : str
370            The message to display.
371        vmin : int
372            Minimum value of the slider.
373        vmax : int
374            Maximum value of the slider.
375        remember_value : bool, optional
376            Whether to remember the last selected value. Defaults to False.
377        *args : tuple
378            Additional positional arguments for the widget.
379        **kwargs : dict
380            Additional keyword arguments for the widget.
381        """
382        self.add_int_range(
383            tag,
384            description,
385            vmin=min,
386            vmax=max,
387            *args,
388            remember_value=remember_value,
389            **kwargs,
390        )
391
392        if on_change is not None:
393            self.elements[tag].observe(on_change, names="value")

@jupyter Add an integer slider widget to the container.

Parameters

tag : str Tag to identify the widget. description : str The message to display. vmin : int Minimum value of the slider. vmax : int Maximum value of the slider. remember_value : bool, optional Whether to remember the last selected value. Defaults to False. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_float_range( self, tag: str, description: str, vmin: float, vmax: float, *args, remember_value=False, on_change: Optional[<built-in function callable>] = None, **kwargs):
395    def add_float_range(
396        self,
397        tag: str,
398        description: str,
399        vmin: float,
400        vmax: float,
401        *args,
402        remember_value=False,
403        on_change: Optional[callable] = None,
404        **kwargs,
405    ):
406        """
407        @unified
408        Add a float slider widget to the container.
409
410        Parameters
411        ----------
412        tag : str
413            Tag to identify the widget.
414        description : str
415            The message to display.
416        vmin : float
417            Minimum value of the slider.
418        vmax : float
419            Maximum value of the slider.
420        remember_value : bool, optional
421            Whether to remember the last selected value. Defaults to False.
422        *args : tuple
423            Additional positional arguments for the widget.
424        **kwargs : dict
425            Additional keyword arguments for the widget.
426        """
427        if self.params is not None:
428            if tag in self.params and vmin <= self.params[tag] <= vmax:
429                kwargs["value"] = self.params[tag]
430        elif (
431            remember_value
432            and tag in self.cfg
433            and vmin <= self.cfg[tag] <= vmax
434        ):
435            kwargs["value"] = int(self.cfg[tag])
436        style = kwargs.pop("style", self._style)
437        self.elements[tag] = widgets.FloatSlider(
438            description=description,
439            min=vmin,
440            max=vmax,
441            *args,
442            **kwargs,
443            layout=self._layout,
444            style=style,
445        )
446
447        if on_change is not None:
448            self.elements[tag].observe(on_change, names="value")

@unified Add a float slider widget to the container.

Parameters

tag : str Tag to identify the widget. description : str The message to display. vmin : float Minimum value of the slider. vmax : float Maximum value of the slider. remember_value : bool, optional Whether to remember the last selected value. Defaults to False. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_float_slider( self, tag: str, description: str, min: int, max: int, *args, remember_value=False, on_change: Optional[<built-in function callable>] = None, **kwargs):
450    def add_float_slider(
451        self,
452        tag: str,
453        description: str,
454        min: int,
455        max: int,
456        *args,
457        remember_value=False,
458        on_change: Optional[callable] = None,
459        **kwargs,
460    ):
461        """
462        @jupyter
463        Add an float slider widget to the container.
464
465        Parameters
466        ----------
467        tag : str
468            Tag to identify the widget.
469        description : str
470            The message to display.
471        min : float
472            Minimum value of the slider.
473        max : float
474            Maximum value of the slider.
475        remember_value : bool, optional
476            Whether to remember the last selected value. Defaults to False.
477        *args : tuple
478            Additional positional arguments for the widget.
479        **kwargs : dict
480            Additional keyword arguments for the widget.
481        """
482        self.add_float_range(
483            tag,
484            description,
485            vmin=min,
486            vmax=max,
487            *args,
488            remember_value=remember_value,
489            **kwargs,
490        )
491
492        if on_change is not None:
493            self.elements[tag].observe(on_change, names="value")

@jupyter Add an float slider widget to the container.

Parameters

tag : str Tag to identify the widget. description : str The message to display. min : float Minimum value of the slider. max : float Maximum value of the slider. remember_value : bool, optional Whether to remember the last selected value. Defaults to False. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_check( self, tag: str, description: str, *args, remember_value=False, on_change: Optional[<built-in function callable>] = None, **kwargs):
495    def add_check(
496        self,
497        tag: str,
498        description: str,
499        *args,
500        remember_value=False,
501        on_change: Optional[callable] = None,
502        **kwargs,
503    ):
504        """
505        @unified
506        Add a checkbox widget to the container.
507
508        Parameters
509        ----------
510        tag : str
511            Tag to identify the widget.
512        description : str
513            The message to display.
514        remember_value : bool, optional
515            Whether to remember the last selected value. Defaults to False.
516        *args : tuple
517            Additional positional arguments for the widget.
518        **kwargs : dict
519            Additional keyword arguments for the widget.
520        """
521        if self.params is not None:
522            if tag in self.params:
523                kwargs["value"] = self.params[tag]
524        elif remember_value and tag in self.cfg:
525            kwargs["value"] = self.cfg[tag]
526        style = kwargs.pop("style", self._style)
527        self.elements[tag] = widgets.Checkbox(
528            description=description,
529            *args,
530            **kwargs,
531            layout=self._layout,
532            style=style,
533        )
534
535        if on_change is not None:
536            self.elements[tag].observe(on_change, names="value")

@unified Add a checkbox widget to the container.

Parameters

tag : str Tag to identify the widget. description : str The message to display. remember_value : bool, optional Whether to remember the last selected value. Defaults to False. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_int_text( self, tag, description: str = '', *args, remember_value=False, on_change: Optional[<built-in function callable>] = None, **kwargs):
538    def add_int_text(
539        self,
540        tag,
541        description: str = "",
542        *args,
543        remember_value=False,
544        on_change: Optional[callable] = None,
545        **kwargs,
546    ):
547        """
548        @unified
549        Add an integer text widget to the container.
550
551        Parameters
552        ----------
553        tag : str
554            Tag to identify the widget.
555        description : str, optional
556            The message to display. Defaults to "".
557        remember_value : bool, optional
558            Whether to remember the last entered value. Defaults to False.
559        *args : tuple
560            Additional positional arguments for the widget.
561        **kwargs : dict
562            Additional keyword arguments for the widget.
563        """
564        if self.params is not None:
565            if tag in self.params:
566                kwargs["value"] = self.params[tag]
567        elif remember_value and tag in self.cfg:
568            kwargs["value"] = self.cfg[tag]
569
570        style = kwargs.pop("style", self._style)
571        self.elements[tag] = widgets.IntText(
572            description=description,
573            *args,
574            **kwargs,
575            layout=self._layout,
576            style=style,
577        )
578
579        if on_change is not None:
580            self.elements[tag].observe(on_change, names="value")

@unified Add an integer text widget to the container.

Parameters

tag : str Tag to identify the widget. description : str, optional The message to display. Defaults to "". remember_value : bool, optional Whether to remember the last entered value. Defaults to False. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_bounded_int_text( self, tag, description: str, vmin: int, vmax: int, *args, remember_value=False, on_change: Optional[<built-in function callable>] = None, **kwargs):
582    def add_bounded_int_text(
583        self,
584        tag,
585        description: str,
586        vmin: int,
587        vmax: int,
588        *args,
589        remember_value=False,
590        on_change: Optional[callable] = None,
591        **kwargs,
592    ):
593        """
594        @unified
595        Add a bounded integer text widget to the container.
596
597        Parameters
598        ----------
599        tag : str
600            Tag to identify the widget.
601        description : str
602            The message to display.
603        vmin : int
604            Minimum value of the input field.
605        vmax : int
606            Maximum value of the input field.
607        remember_value : bool, optional
608            Whether to remember the last entered value. Defaults to False.
609        *args : tuple
610            Additional positional arguments for the widget.
611        **kwargs : dict
612            Additional keyword arguments for the widget.
613        """
614        if self.params is not None:
615            if tag in self.params:
616                kwargs["value"] = self.params[tag]
617        elif remember_value and tag in self.cfg:
618            kwargs["value"] = self.cfg[tag]
619        style = kwargs.pop("style", self._style)
620        self.elements[tag] = widgets.BoundedIntText(
621            min=vmin,
622            max=vmax,
623            description=description,
624            *args,
625            **kwargs,
626            layout=self._layout,
627            style=style,
628        )
629
630        if on_change is not None:
631            self.elements[tag].observe(on_change, names="value")

@unified Add a bounded integer text widget to the container.

Parameters

tag : str Tag to identify the widget. description : str The message to display. vmin : int Minimum value of the input field. vmax : int Maximum value of the input field. remember_value : bool, optional Whether to remember the last entered value. Defaults to False. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_float_text( self, tag, description: str = '', *args, remember_value=False, on_change: Optional[<built-in function callable>] = None, **kwargs):
633    def add_float_text(
634        self,
635        tag,
636        description: str = "",
637        *args,
638        remember_value=False,
639        on_change: Optional[callable] = None,
640        **kwargs,
641    ):
642        """
643        @unified
644        Add a float text widget to the container.
645
646        Parameters
647        ----------
648        tag : str
649            Tag to identify the widget.
650        description : str, optional
651            The message to display. Defaults to "".
652        remember_value : bool, optional
653            Whether to remember the last entered value. Defaults to False.
654        *args : tuple
655            Additional positional arguments for the widget.
656        **kwargs : dict
657            Additional keyword arguments for the widget.
658        """
659        if self.params is not None:
660            if tag in self.params:
661                kwargs["value"] = self.params[tag]
662        elif remember_value and tag in self.cfg:
663            kwargs["value"] = self.cfg[tag]
664        style = kwargs.pop("style", self._style)
665        self.elements[tag] = widgets.FloatText(
666            description=description,
667            *args,
668            **kwargs,
669            layout=self._layout,
670            style=style,
671        )
672
673        if on_change is not None:
674            self.elements[tag].observe(on_change, names="value")

@unified Add a float text widget to the container.

Parameters

tag : str Tag to identify the widget. description : str, optional The message to display. Defaults to "". remember_value : bool, optional Whether to remember the last entered value. Defaults to False. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_bounded_float_text( self, tag, description: str, vmin: int, vmax: int, *args, remember_value=False, on_change: Optional[<built-in function callable>] = None, **kwargs):
676    def add_bounded_float_text(
677        self,
678        tag,
679        description: str,
680        vmin: int,
681        vmax: int,
682        *args,
683        remember_value=False,
684        on_change: Optional[callable] = None,
685        **kwargs,
686    ):
687        """
688        @unified
689        Add a bounded float text widget to the container.
690
691        Parameters
692        ----------
693        tag : str
694            Tag to identify the widget.
695        description : str
696            The message to display.
697        vmin : int
698            Minimum value of the input field.
699        vmax : int
700            Maximum value of the input field.
701        remember_value : bool, optional
702            Whether to remember the last entered value. Defaults to False.
703        *args : tuple
704            Additional positional arguments for the widget.
705        **kwargs : dict
706            Additional keyword arguments for the widget.
707        """
708        if self.params is not None:
709            if tag in self.params:
710                kwargs["value"] = self.params[tag]
711        elif remember_value and tag in self.cfg:
712            kwargs["value"] = self.cfg[tag]
713        style = kwargs.pop("style", self._style)
714        self.elements[tag] = widgets.BoundedFloatText(
715            min=vmin,
716            max=vmax,
717            description=description,
718            *args,
719            **kwargs,
720            layout=self._layout,
721            style=style,
722        )
723
724        if on_change is not None:
725            self.elements[tag].observe(on_change, names="value")

@unified Add a bounded float text widget to the container.

Parameters

tag : str Tag to identify the widget. description : str The message to display. vmin : int Minimum value of the input field. vmax : int Maximum value of the input field. remember_value : bool, optional Whether to remember the last entered value. Defaults to False. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_dropdown( self, tag, options: list, description: str = '', *args, remember_value=False, on_change: Optional[<built-in function callable>] = None, **kwargs):
727    def add_dropdown(
728        self,
729        tag,
730        options: list,
731        description: str = "",
732        *args,
733        remember_value=False,
734        on_change: Optional[callable] = None,
735        **kwargs,
736    ):
737        """
738        @unified
739        Add a dropdown widget to the container.
740
741        Parameters
742        ----------
743        tag : str
744            Tag to identify the widget.
745        options : list
746            List of choices for the dropdown.
747        description : str, optional
748            The message to display. Defaults to "".
749        remember_value : bool, optional
750            Whether to remember the last selected value. Defaults to False.
751        *args : tuple
752            Additional positional arguments for the widget.
753        **kwargs : dict
754            Additional keyword arguments for the widget.
755        """
756        if remember_value and tag in self.cfg and self.cfg[tag] in options:
757            kwargs["value"] = self.cfg[tag]
758        if self.params is not None:
759            if tag in self.params:
760                kwargs["value"] = self.params[tag]
761        style = kwargs.pop("style", self._style)
762        self.elements[tag] = widgets.Dropdown(
763            options=options,
764            description=description,
765            *args,
766            **kwargs,
767            layout=self._layout,
768            style=style,
769        )
770
771        if on_change is not None:
772            self.elements[tag].observe(on_change, names="value")

@unified Add a dropdown widget to the container.

Parameters

tag : str Tag to identify the widget. options : list List of choices for the dropdown. description : str, optional The message to display. Defaults to "". remember_value : bool, optional Whether to remember the last selected value. Defaults to False. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_checkbox( self, tag: str, description: str, *args, remember_value=False, on_change: Optional[<built-in function callable>] = None, **kwargs):
774    def add_checkbox(
775        self,
776        tag: str,
777        description: str,
778        *args,
779        remember_value=False,
780        on_change: Optional[callable] = None,
781        **kwargs,
782    ):
783        """
784        @jupyter
785        Add a checkbox widget to the container.
786
787        Parameters
788        ----------
789        tag : str
790            Tag to identify the widget.
791        description : str
792            The message to display.
793        remember_value : bool, optional
794            Whether to remember the last selected value. Defaults to False.
795        *args : tuple
796            Additional positional arguments for the widget.
797        **kwargs : dict
798            Additional keyword arguments for the widget.
799        """
800        self.add_check(
801            tag,
802            description=description,
803            remember_value=remember_value,
804            *args,
805            **kwargs,
806        )
807
808        if on_change is not None:
809            self.elements[tag].observe(on_change, names="value")

@jupyter Add a checkbox widget to the container.

Parameters

tag : str Tag to identify the widget. description : str The message to display. remember_value : bool, optional Whether to remember the last selected value. Defaults to False. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_select_multiple( self, tag: str, options: list, description: str = '', *args, **kwargs):
811    def add_select_multiple(
812        self, tag: str, options: list, description: str = "", *args, **kwargs
813    ):
814        """
815        @jupyter
816        Add a multiple selection widget to the container.
817
818        Parameters
819        ----------
820        tag : str
821            Tag to identify the widget.
822        options : list
823            List of choices for the selection.
824        *args : tuple
825            Additional positional arguments for the widget.
826        **kwargs : dict
827            Additional keyword arguments for the widget.
828        """
829        style = kwargs.pop("style", self._style)
830        self.elements[tag] = widgets.SelectMultiple(
831            options=options,
832            description=description,
833            *args,
834            **kwargs,
835            layout=self._layout,
836            style=style,
837        )

@jupyter Add a multiple selection widget to the container.

Parameters

tag : str Tag to identify the widget. options : list List of choices for the selection. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_file_upload(self, tag, *args, accept=None, multiple=False, **kwargs):
839    def add_file_upload(
840        self, tag, *args, accept=None, multiple=False, **kwargs
841    ):
842        """
843        @jupyter
844        Add a file upload widget to the container.
845
846        Parameters
847        ----------
848        tag : str
849            Tag to identify the widget.
850        accept : str, optional
851            The file types to accept. Defaults to None.
852        multiple : bool, optional
853            Allow multiple files to be uploaded. Defaults to False.
854        *args : tuple
855            Additional positional arguments for the widget.
856        **kwargs : dict
857            Additional keyword arguments for the widget.
858        """
859        self.elements[tag] = FileChooser()
860        if accept is not None:
861            self.elements[tag].filter_pattern = accept

@jupyter Add a file upload widget to the container.

Parameters

tag : str Tag to identify the widget. accept : str, optional The file types to accept. Defaults to None. multiple : bool, optional Allow multiple files to be uploaded. Defaults to False. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_output(self, tag: str, *args, **kwargs):
863    def add_output(self, tag: str, *args, **kwargs):
864        """
865        @unified
866        Add an output widget to the container.
867
868        Parameters
869        ----------
870        tag : str
871            Tag to identify the widget.
872        *args : tuple
873            Additional positional arguments for the widget.
874        **kwargs : dict
875            Additional keyword arguments for the widget.
876        """
877        style = kwargs.pop("style", self._style)
878        self.elements[tag] = widgets.Output(
879            *args,
880            **kwargs,
881            layout=self._layout,
882            style=style,
883        )

@unified Add an output widget to the container.

Parameters

tag : str Tag to identify the widget. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def add_custom_widget( self, tag: str, custom_widget, *args, remember_value=False, on_change: Optional[<built-in function callable>] = None, **kwargs):
885    def add_custom_widget(
886        self,
887        tag: str,
888        custom_widget,
889        *args,
890        remember_value=False,
891        on_change: Optional[callable] = None,
892        **kwargs,
893    ):
894        """
895        @jupyter
896        Add a custom widget to the container.
897        Parameters
898        ----------
899        tag : str
900            Tag to identify the widget.
901        custom_widget : ipywidget to add
902            The custom widget to add.
903        *args : tuple
904            Additional positional arguments for the widget.
905        **kwargs : dict
906            Additional keyword arguments for the widget.
907        """
908        if self.params is not None:
909            if tag in self.params:
910                kwargs["value"] = self.params[tag]
911        elif remember_value and tag in self.cfg:
912            kwargs["value"] = self.cfg[tag]
913        style = kwargs.pop("style", self._style)
914        self.elements[tag] = custom_widget(
915            *args,
916            **kwargs,
917            layout=self._layout,
918            style=style,
919        )
920
921        if on_change is not None:
922            self.elements[tag].observe(on_change, names="value")

@jupyter Add a custom widget to the container.

Parameters

tag : str Tag to identify the widget. custom_widget : ipywidget to add The custom widget to add. args : tuple Additional positional arguments for the widget. *kwargs : dict Additional keyword arguments for the widget.

def save_parameters(self, path: str):
924    def save_parameters(self, path: str):
925        """
926        @unified
927        Save the widget values to a file.
928
929        Parameters
930        ----------
931        path : str
932            The path to save the file.
933        """
934        if not path.endswith(".yml"):
935            path += f"{self.title}_parameters.yml"
936        out = {}
937        for tag in self.elements:
938            if tag.startswith("label_"):
939                pass
940            elif hasattr(self.elements[tag], "value"):
941                out[tag] = self.elements[tag].value
942        with open(path, "w") as f:
943            yaml.dump(out, f)

@unified Save the widget values to a file.

Parameters

path : str The path to save the file.

def save_settings(self):
945    def save_settings(self):
946        """
947        @unified
948        Save the widget values to the configuration file.
949        """
950        for tag in self.elements:
951            if tag.startswith("label_"):
952                pass
953            elif hasattr(self.elements[tag], "value"):
954                if type(self.elements[tag].value) != tuple:
955                    self.cfg[tag] = self.elements[tag].value
956        config_file = CONFIG_PATH / f"{self.title}.yml"
957        config_file.parent.mkdir(exist_ok=True)
958
959        base_config = self._get_config(self.title)  # loads the config file
960        for key, value in self.cfg.items():
961            base_config[key] = value
962
963        with open(config_file, "w") as f:
964            yaml.dump(base_config, f)

@unified Save the widget values to the configuration file.

def show(self):
966    def show(self):
967        """
968        @unified
969        Display the widgets in the container.
970        """
971        self._main_display.children = tuple(self.elements.values())
972        clear_output()
973        display(self._main_display)

@unified Display the widgets in the container.

def clear_elements(self):
975    def clear_elements(self):
976        """
977        @unified
978        Clear all widgets from the container.
979        """
980        self.elements = {}
981        self._nLabels = 0
982        self._main_display.children = ()

@unified Clear all widgets from the container.