Skip to content

Multiple labels for Input (not multiclass) #51

Open

Description

@DanWertheimer

I'd like to create a widget that allows you to label text with two labels.

These would be along the lines of:
data: Some weird store name
label 1: Groceries
label 2: Tesco

these labels are two seperate things but both realted to the data shown. How would I implement this?
I've created a dual dropdown widget for showing these things, the issue that I have is that options is a list but now I'll have two lists with different values.

Activity

  1. janfreyberg commented on Mar 30, 2020

    @janfreyberg
    Owner

    Ah interesting - so it's almost a hierarchical setting? That makes sense to me, and using two dropdown widgets should work (with a bit of custom configuration). Can you post the code you have so far?

  2. DanWertheimer commented on Mar 31, 2020

    @DanWertheimer
    Author

    Honestly, I haven't done much other than create the widget. I'm trying to figure out the best way for the labeller to accept to options because the current code requires a single list. What would you suggest?

    Code below. It's very rough right now (kinda new to working with such complete packages)

    from collections import defaultdict
    from typing import Callable, DefaultDict, Sequence,Tuple, Any
    
    import ipywidgets as widgets
    import traitlets
    
    class DualDropdownButton(widgets.VBox):
        def __init__(self, options: Tuple[list,list], *args, **kwargs):
            """Create a dropdown button.
            Parameters
            ----------
            options : Sequence[str]
                The options to display in the widget.
            """
            super().__init__(*args, **kwargs)
            
            self.submit_callbacks: List[Callable[[Any], None]] = []
            self.undo_callbacks: List[Callable[[], None]] = []
            self.skip_callbacks: List[Callable[[], None]] = []
            
            self.options= options
            
            self.option_one = options[0]
            self.option_two = options[1]
    
            self.dropdown_one = widgets.Dropdown(
                options=[option for option in self.option_one],
                description="Label:",
            )
            
            self.dropdown_two = widgets.Dropdown(
                options=[option for option in self.option_two],
                description="Label:",
            )
            
            self.button = widgets.Button(
                description="Submit.",
                tooltip="Submit label.",
                button_style="success",
            )
            
            self.button.on_click(self._handle_click)
            
            self.children = [widgets.HBox([self.dropdown_one, self.dropdown_two , self.button])]
            
        def on_click(self, func: Callable) -> None:
                """Add a function to the list of calls made after a click.
                Parameters
                ----------
                func : Callable
                    The function to call when the button is clicked.
                """
                if not callable(func):
                    raise ValueError(
                        "You need to provide a callable object, but you provided "
                        + str(func)
                        + "."
                    )
                self.submission_functions.append(func)
                
        def on_submit(self, callback: Callable[[Any], None]):
            """Register a callback to handle data when the user clicks "Submit".
            .. note::
                Callbacks are called in order of registration - first registered,
                first called.
            Parameters
            ----------
            callback : Callable[[Any], None]
                A function that takes in data. Usually, this data is a list of
                dictionaries, but you are able to define data post-processors when
                you create an annotator that get called before this callback is
                called. Any return values are ignored.
            """
            self.submit_callbacks.append(callback)
        
        def on_undo(self, callback: Callable[[], None]):
            """Register a callback to handle when the user clicks "Undo".
            Note that any callback registered here is only called when the canvas
            is empty - while there are annotations on the canvas, "Undo" actually
            undoes the annotations, until the canvas is empty.
            Parameters
            ----------
            callback : Callable[[], None]
                A function to be called when users press "Undo". This should be
                a function that takes in no arguments; any return values are
                ignored.
            """
            self.undo_callbacks.append(callback)
        
        def on_skip(self, callback: Callable[[], None]):
            """Register a callback to handle when the user clicks "Skip".
            Parameters
            ----------
            callback : Callable[[], None]
                The function to be called when the user clicks "Skip". It should
                take no arguments, and any return values are ignored.
            """
            self.skip_callbacks.append(callback)
    
        def _handle_click(self, owner: widgets.Button) -> None:
            for func in self.submission_functions:
                func(owner)        
    

    Very open to help and for constructive criticism

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions