Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple labels for Input (not multiclass) #51

Open
DanWertheimer opened this issue Mar 30, 2020 · 2 comments
Open

Multiple labels for Input (not multiclass) #51

DanWertheimer opened this issue Mar 30, 2020 · 2 comments

Comments

@DanWertheimer
Copy link

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.

@janfreyberg
Copy link
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?

@DanWertheimer
Copy link
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
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants