예제 #1
0
    def __init__(self, lp, filename='', **kwargs):

        self.__lp = lp
        self.filename = filename
        self.__accordion = Accordion()
        self.__auto_apply_cbx = Checkbox(description='Auto apply')
        self.__auto_save_cbx = Checkbox(description='Auto save')
        self.__apply_btn = Button(description='Apply changes')
        self.__save_btn = Button(description='Save changes')
        self.__add_category_btn = Button(description='Add category')
        self.__add_category_txt = Text(placeholder='category name')
        self.__initialize()

        super().__init__([
            VBox([
                HBox([
                    HBox((self.__apply_btn, self.__auto_apply_cbx)),
                    HBox((self.__save_btn, self.__auto_save_cbx)),
                    HBox((self.__add_category_btn, self.__add_category_txt))
                ],
                     layout=Layout(flex_flow='row wrap', margin='5px')),
                self.__accordion
            ],
                 layout=Layout(margin='5px'))
        ], **kwargs)
    def __init__(self):
        plt.close("all")
        self.backend = TextInputLoop(use_widget=True)
        self.highlighter = SentimentHighlighter(self.backend)
        self.backend.add_interface(self.highlighter)
        self.backend.start()

        self.cwd_label = Label(
            value="Working directory: {}".format(Path.cwd()),
            layout=dict(margin="2px 0px 0px 20px"),
        )
        self.save_path = Text(
            value=str(Path("saved_html.html")),
            description='Save path:',
            disabled=False,
            layout=dict(width="50%"),
        )
        self.save_button = Button(
            value=False,
            description='Save to HTML',
            disabled=False,
            button_style=
            'success',  # 'success', 'info', 'warning', 'danger' or ''
            tooltip='',
            icon='',
            layout=Layout(width='18%', margin="2px 0px 0px 20px"),
        )
        self.progress_label = Label(
            value="",
            layout=dict(margin="2px 0px 0px 20px"),
        )

        self.full_contrast = Checkbox(value=False,
                                      description='Full Contrast',
                                      disabled=False)
        self.do_highlighting = Checkbox(value=True,
                                        description='Do Highlighting',
                                        disabled=False)

        box1 = HBox(
            (self.do_highlighting, self.full_contrast),
            layout=Layout(align_content="flex-start"),
        )

        box2 = HBox(
            (self.save_path, self.save_button),
            layout=Layout(align_content="flex-start"),
        )

        self.storage_dashboard = VBox(
            (box1, self.cwd_label, box2, self.progress_label))

        # Set observers
        self.save_button.on_click(self._save)
        self.full_contrast.observe(self._special_options)
        self.do_highlighting.observe(self._special_options)

        # noinspection PyTypeChecker
        display(self.storage_dashboard)
예제 #3
0
 def __init__(self, value, **kwargs):
     self.value = value
     description = kwargs[
         'name'] if 'no_name' in kwargs and kwargs['no_name'] else 'value'
     self.__checkbox = Checkbox(value, description=description)
     self.__checkbox.observe(self.__on_checkbox_changed, names='value')
     kwargs['children'] = [self.__checkbox]
     super().__init__(**kwargs)
예제 #4
0
 def create_checkbox(self, *options, default=True):
     box = [
         Checkbox(value=default,
                  description=dict_name,
                  disabled=False,
                  indent=False) for dict_name in options
     ]
     for c in box:
         c.observe(self.show_result)
     return box
예제 #5
0
class BoolEditor(_Editor):
    """TODO: Add docstring here
    """
    _model_name = Unicode('BoolEditorModel').tag(sync=True)
    _view_name = Unicode('BoolEditorView').tag(sync=True)

    __checkbox = None

    value = Bool(False).tag(sync=False)

    def __init__(self, value, **kwargs):
        self.value = value
        description = kwargs[
            'name'] if 'no_name' in kwargs and kwargs['no_name'] else 'value'
        self.__checkbox = Checkbox(value, description=description)
        self.__checkbox.observe(self.__on_checkbox_changed, names='value')
        kwargs['children'] = [self.__checkbox]
        super().__init__(**kwargs)

    def __on_checkbox_changed(self, change):
        self.value = change['new']
예제 #6
0
def checkbox(default=True, label=None):
    """
    A checkbox widget.

    INPUT:

    - ``default`` -- (boolean) initial value

    - ``label`` -- optional label

    EXAMPLES::

        sage: from sage.repl.ipython_kernel.all_jupyter import checkbox
        sage: checkbox(label="toggle me")
        Checkbox(value=True, description=u'toggle me')
        sage: checkbox(default=0)
        Checkbox(value=False)
    """
    kwds = {"value": bool(default)}
    if label is not None:
        kwds["description"] = u(label)
    return Checkbox(**kwds)
예제 #7
0
                          description='Maximum flow:',
                          disabled=False,
                          style={'description_width': 'initial'})

buffer_value = BoundedFloatText(value=0.2,
                                min=0,
                                max=1,
                                step=0.01,
                                description='Buffer around location:',
                                disabled=False,
                                style={'description_width': 'initial'})

#Gauge option
check_gauge = Checkbox(value=False,
                       description='Use gauge location',
                       disabled=False,
                       indent=False,
                       style={'description_width': 'initial'})

use_gauge_location = Accordion(children=[check_gauge])

# user option
check_own = Checkbox(value=False,
                     description='Define my own location',
                     disabled=False,
                     indent=False,
                     style={'description_width': 'initial'})
input_lat = BoundedFloatText(value=0.0,
                             min=-99999999999999,
                             max=999999999999999,
                             step=0.0001,
예제 #8
0
    def __init__(self):
        self.start_button = Button(
            value=False,
            description='Start Camera',
            disabled=False,
            button_style=
            'success',  # 'success', 'info', 'warning', 'danger' or ''
            tooltip='Start the camera to take pictures for classifier ',
            icon='',
            layout=Layout(width='25%'),
        )

        self.save_button = Button(
            value=False,
            description='Save images',
            disabled=True,
            button_style=
            'danger',  # 'success', 'info', 'warning', 'danger' or ''
            tooltip='Save images to folder ',
            icon='',
            layout=Layout(width='18%', margin="2px 0px 0px 20px"),
        )
        self.load_button = Button(
            value=False,
            description='Load images',
            disabled=False,
            button_style=
            'success',  # 'success', 'info', 'warning', 'danger' or ''
            tooltip='Load images from folder ',
            icon='',
            layout=Layout(width='18%', margin="2px 0px 0px 20px"),
        )

        self.save_path = Text(
            value=str(Path("path", "to", "directory")),
            description='Save path:',
            disabled=False,
        )

        self.num_pictures = FloatText(
            value=12,
            description='#pictures:',
            disabled=False,
            layout=Layout(width='20%'),
        )

        self.use_augmentation = Checkbox(
            value=False,
            description='Augmentation',
            disabled=False,
            tooltip='Use Augmentation',
            icon='check',
        )

        self.progress_text = Label(
            value='',
            layout=Layout(margin="5px 0px 5px 20px"),
        )

        self.widget_box = VBox((
            HBox(
                (self.num_pictures, self.use_augmentation, self.start_button),
                layout=Layout(align_content="flex-start"),
            ),
            HBox(
                (self.progress_text, ),
                layout=Layout(align_content="flex-start"),
            ),
            HBox(
                (self.save_path, self.save_button, self.load_button),
                layout=Layout(align_content="flex-start"),
            ),
        ))

        self.start_button.on_click(self._start_video)
        self.save_button.on_click(self._save_images)
        self.load_button.on_click(self._load_images)

        self.collector = ImageCollector()
예제 #9
0
class ParameterEditor(VBox):
    """TODO: Add docstring here
    """

    filename = ''

    _model_name = Unicode('ParameterEditorModel').tag(sync=True)
    _model_module = Unicode(module_name).tag(sync=True)
    _model_module_version = Unicode(module_version).tag(sync=True)
    _view_name = Unicode('ParameterEditorView').tag(sync=True)
    _view_module = Unicode(module_name).tag(sync=True)
    _view_module_version = Unicode(module_version).tag(sync=True)

    __auto_apply = False
    __auto_save = False
    __accordion = None
    __auto_apply_cbx = None
    __auto_save_cbx = None
    __apply_btn = None
    __save_btn = None
    __add_category_btn = None
    __add_category_txt = None

    __lp = None

    def __init__(self, lp, filename='', **kwargs):

        self.__lp = lp
        self.filename = filename
        self.__accordion = Accordion()
        self.__auto_apply_cbx = Checkbox(description='Auto apply')
        self.__auto_save_cbx = Checkbox(description='Auto save')
        self.__apply_btn = Button(description='Apply changes')
        self.__save_btn = Button(description='Save changes')
        self.__add_category_btn = Button(description='Add category')
        self.__add_category_txt = Text(placeholder='category name')
        self.__initialize()

        super().__init__([
            VBox([
                HBox([
                    HBox((self.__apply_btn, self.__auto_apply_cbx)),
                    HBox((self.__save_btn, self.__auto_save_cbx)),
                    HBox((self.__add_category_btn, self.__add_category_txt))
                ],
                     layout=Layout(flex_flow='row wrap', margin='5px')),
                self.__accordion
            ],
                 layout=Layout(margin='5px'))
        ], **kwargs)

    def dumps(self):
        return self.__lp.dumps()

    def __initialize(self):
        if self.__lp.is_valid():
            children, titles = self.__build_gui()
            accordion = Accordion(children)
            for i, title in enumerate(titles):
                accordion.set_title(i, title)
            self.__accordion = accordion

            self.__auto_apply_cbx.observe(self.__on_auto_apply_cbx_change,
                                          names='value')
            self.__auto_save_cbx.observe(self.__on_auto_save_cbx_change,
                                         names='value')
            self.__apply_btn.on_click(
                lambda x: self.on_lpy_context_change(self.__lp.dumps()))
            self.__save_btn.on_click(lambda x: self.__save())
            self.__add_category_btn.on_click(lambda x: self.__add_category(
                self.__add_category_txt.value.strip()))

    def __add_category(self, name):
        if not name or name in self.__lp.get_category_names():
            return

        item_layout = Layout(margin='20px', flex_flow='row wrap')
        acc = self.__accordion
        box_scalars = HBox(layout=item_layout)
        box_curves = HBox(layout=item_layout)

        acc.children = (*self.__accordion.children,
                        VBox([
                            self.__menu('scalars', box_scalars, name),
                            box_scalars,
                            self.__menu('curves', box_curves, name), box_curves
                        ]))
        acc.set_title(len(acc.children) - 1, name)
        self.__lp.add_category(name)
        if self.__auto_save:
            self.__save()

    def __on_auto_apply_cbx_change(self, change):
        self.__auto_apply = change['owner'].value
        self.__apply_btn.disabled = self.__auto_apply
        if self.__auto_apply:
            self.on_lpy_context_change(self.__lp.dumps())

    def __on_auto_save_cbx_change(self, change):
        self.__auto_save = change['owner'].value
        self.__save_btn.disabled = self.__auto_save
        if self.__auto_save:
            self.__save()

    def on_lpy_context_change(self, context):
        pass

    def __build_gui(self):

        children = []
        titles = ['materials']
        item_layout = Layout(margin='20px', flex_flow='row wrap')

        if self.__lp:

            box_materials = HBox(layout=item_layout)

            for index, color in self.__lp.get_colors().items():
                editor = make_color_editor(color, index, no_name=True)
                if editor:
                    editor.observe(self.__on_editor_changed(color))
                    box_materials.children = (*box_materials.children, editor)

            children.append(
                VBox([self.__menu('materials', box_materials), box_materials]))

            for category_name in self.__lp.get_category_names():

                box_scalars = HBox(layout=item_layout)
                box_curves = HBox(layout=item_layout)

                for scalar in self.__lp.get_category_scalars(category_name):

                    editor = make_scalar_editor(scalar, False)
                    if editor:
                        editor.observe(self.__on_editor_changed(scalar))
                        box_scalars.children = (*box_scalars.children, editor)

                for param in self.__lp.get_category_graphicalparameters(
                        category_name):

                    editor = make_curve_editor(param, False)
                    if editor:
                        editor.observe(self.__on_editor_changed(param))
                        box_curves.children = (*box_curves.children, editor)

                children.append(
                    VBox([
                        self.__menu('scalars', box_scalars,
                                    category_name), box_scalars,
                        self.__menu('curves', box_curves, category_name),
                        box_curves
                    ]))
                titles.append(category_name)

        return (children, titles)

    def __menu(self, parameter_type, box, category_name=None):

        btn_add = Button(description='Add')
        ddn_add = Dropdown()

        if parameter_type == 'scalars':

            def fn_add(self):

                value = None

                if ddn_add.value == 'Integer':
                    value = 1
                elif ddn_add.value == 'Float':
                    value = 1.0
                elif ddn_add.value == 'Bool':
                    value = True

                name = f'{ddn_add.value}_{len(box.children)}'
                scalar = self.__lp.add_scalar(name,
                                              value,
                                              category=category_name)
                editor = make_scalar_editor(scalar)
                editor.observe(self.__on_editor_changed(scalar))
                box.children = (*box.children, editor)

                if self.__auto_save:
                    self.__save()
                if self.__auto_apply:
                    self.on_lpy_context_change(self.__lp.dumps())

            ddn_add.options = ['Integer', 'Float', 'Bool']

        elif parameter_type == 'materials':

            def fn_add(self):

                index = max(self.__lp.get_colors().keys()) + 1 if len(
                    self.__lp.get_colors().keys()) else 0

                self.__lp.set_color(
                    index, pgl.Material(ambient=(80, 80, 80), diffuse=1))
                editor = make_color_editor(self.__lp.get_color(index),
                                           index,
                                           no_name=True)
                editor.observe(
                    self.__on_editor_changed(self.__lp.get_color(index)))
                box.children = (*box.children, editor)

                if self.__auto_save:
                    self.__save()
                if self.__auto_apply:
                    self.on_lpy_context_change(self.__lp.dumps())

            ddn_add.options = ['Color']

        elif parameter_type == 'curves':

            def fn_add(self):

                name = f'{ddn_add.value}_{len(box.children)}'
                if ddn_add.value == 'Function':
                    curve = self.__lp.add_function(name,
                                                   category=category_name)
                else:
                    curve = self.__lp.add_curve(name, category=category_name)
                editor = make_curve_editor(curve)
                editor.observe(self.__on_editor_changed(curve))
                box.children = (*box.children, editor)

                if self.__auto_save:
                    self.__save()
                if self.__auto_apply:
                    self.on_lpy_context_change(self.__lp.dumps())

            ddn_add.options = ['Curve', 'Function']

        btn_add.on_click(lambda x: fn_add(self))

        return HBox((btn_add, ddn_add))

    def __validate_name(self, name):
        if not _property_name_regex.match(name):
            return False
        if name in self.lpy_context:
            return False
        for key in self.lpy_context.keys():
            if name in self.lpy_context[key]:
                return False
        return True

    def __save(self):
        if self.filename:
            params = self.__lp.dumps()
            with io.open(self.filename, 'w') as file:
                file.write(json.dumps(json.loads(params), indent=4))

    def __on_editor_changed(self, param):
        def on_param_changed(change):
            if 'new' in change:
                value = change['new']
                name = change['name']
                if isinstance(param, BaseScalar):
                    if name == 'name':
                        param.name = value
                    else:
                        param.value = value
                elif isinstance(param, tuple):
                    if name == 'value':
                        if isinstance(param[1],
                                      (pgl.NurbsCurve2D, pgl.BezierCurve2D)):
                            param[1].ctrlPointList = pgl.Point3Array(
                                [pgl.Vector3(p[0], p[1], 1) for p in value])
                        elif isinstance(param[1], pgl.Polyline2D):
                            param[1].pointList = pgl.Point2Array(
                                [pgl.Vector2(p[0], p[1]) for p in value])
                    else:
                        param[1].name = value
                if self.__auto_apply:
                    self.on_lpy_context_change(self.__lp.dumps())
                if self.__auto_save:
                    self.__save()

        def on_material_changed(change):
            if 'new' in change:
                if change['name'] == 'index':
                    self.__lp.unset_color(change['old'])
                    self.__lp.set_color(change['new'], param)
                else:
                    setattr(param, change['name'], change['new'])

                if self.__auto_apply:
                    self.on_lpy_context_change(self.__lp.dumps())
                if self.__auto_save:
                    self.__save()

        return on_material_changed if isinstance(
            param, pgl.Material) else on_param_changed
예제 #10
0
    def __init__(self, df: pd.DataFrame, col_name: str, df_name: str,
                 page_size: int):
        self._clusterer = Clusterer(df, col_name, df_name)
        self._clusterer.cluster("fingerprint")

        self._page_size = page_size

        # clustering dropdown and export code checkbox, used in the top row
        self._clustering_method_label = Label(
            " Clustering Method: ", layout=Layout(margin="2px 0 0 20px"))
        self._clustering_method_drop = Dropdown(
            options=[
                "fingerprint", "ngram-fingerprint", "phonetic-fingerprint",
                "levenshtein"
            ],
            layout=Layout(width="150px", margin="0 0 0 10px"),
        )
        self._clustering_method_drop.observe(self._cluster_method_change,
                                             names="value")
        self._export_code = Checkbox(
            value=True,
            description="export code",
            layout=Layout(width="165px", margin="0 0 0 482px"),
            style={"description_width": "initial"},
        )
        self._dropds = HBox(
            [
                self._clustering_method_label,
                self._clustering_method_drop,
                self._export_code,
            ],
            layout=Layout(height="35px", margin="10px 0 0 0"),
        )
        # text boxes for clustering parameters used in the top row
        self._ngram_text = Text(
            value=DEFAULT_NGRAM,
            description="n-gram",
            layout=Layout(width="130px"),
            continuous_update=False,
        )
        self._radius_text = Text(
            value=DEFAULT_RADIUS,
            description="Radius",
            layout=Layout(width="130px"),
            continuous_update=False,
        )
        self._block_chars_text = Text(
            value=DEFAULT_BLOCK_SIZE,
            description="Block Chars",
            layout=Layout(width="130px"),
            continuous_update=False,
        )
        self._ngram_text.observe(self._param_recluster, names="value")
        self._radius_text.observe(self._param_recluster, names="value")
        self._block_chars_text.observe(self._param_recluster, names="value")

        # create header labels, second row
        headers = HBox(
            [
                Label("Distinct values", layout=Layout(margin="0 0 0 10px")),
                Label("Total values", layout=Layout(margin="0 0 0 35px")),
                Label("Cluster values", layout=Layout(margin="0 0 0 95px")),
                Label("Merge?", layout=Layout(margin="0 0 0 295px")),
                Label("Representative value",
                      layout=Layout(margin="0 0 0 50px")),
            ],
            layout=Layout(margin="10px"),
        )

        # create buttons for bottom row
        self._sel_all = Checkbox(description="Select all",
                                 layout=Layout(width="165px"))
        self._sel_all.observe(self._select_all, names="value")

        merge_and_recluster = Button(description="Merge and Re-Cluster",
                                     layout=Layout(margin="0 0 0 466px",
                                                   width="150px"))
        merge_and_recluster.on_click(self._execute_merge)

        finish = Button(description="Finish",
                        layout=Layout(margin="0 0 0 10px"))
        finish.on_click(self._close)

        # next and previous page buttons
        self._next_button = Button(description="Next")
        self._next_button.on_click(self._next_page)

        self._prev_button = Button(description="Previous",
                                   layout=Layout(margin="0 0 0 20px"))
        self._prev_button.on_click(self._prev_page)

        # an index in the clusters Series indicating the start of the current page
        self._page_pos = 0
        # loading label, displayed when re-clustering or next page load
        self._loading_label = Label("Loading...",
                                    layout=Layout(margin="170px 0 0 440px"))
        # displayed when the user enters a non integer value into a clustering parameter text box
        self._invalid_param_label = Label(
            "Invalid clustering parameter, please enter an integer",
            layout=Layout(margin="170px 0 0 350px"),
        )

        self._reprs = [
            Text(layout=Layout(width="200px", margin="0 10px 0 40px"))
            for _ in range(self._page_size)
        ]
        self._checks = [
            Checkbox(indent=False,
                     layout=Layout(width="auto", margin="0 0 0 20px"))
            for _ in range(self._page_size)
        ]

        # VBox containing a VBox with all the clusters in the first row and an optional
        # second row containing next and previous page buttons
        self._cluster_and_next_prev = VBox()
        self._cluster_vbox = VBox(
            layout=Layout(height="450px", flex_flow="row wrap"))

        footer = HBox([self._sel_all, merge_and_recluster, finish])

        box_children = [
            self._dropds, headers, self._cluster_and_next_prev, footer
        ]

        box_layout = Layout(display="flex",
                            flex_flow="column",
                            align_items="stretch",
                            border="solid")
        self._box = Box(children=box_children, layout=box_layout)
        self._update_clusters()
예제 #11
0
class UserInterface:
    """
    A user interface used by the clean_duplication function.
    """

    # pylint: disable=too-many-instance-attributes

    _clusterer: Clusterer
    _page_size: int
    _clustering_method_label: Label
    _clustering_method_drop: Dropdown
    _export_code: Checkbox
    _sel_all: Checkbox
    _next_button: Button
    _prev_button: Button
    _page_pos: int
    _ngram_text: Text
    _radius_text: Text
    _block_chars_text: Text
    _dropds: HBox
    _reprs: List[Text]
    _checks: List[Checkbox]
    _cluster_vbox: VBox
    _box: Box
    _loading_label: Label
    _invalid_param_label: Label

    def __init__(self, df: pd.DataFrame, col_name: str, df_name: str,
                 page_size: int):
        self._clusterer = Clusterer(df, col_name, df_name)
        self._clusterer.cluster("fingerprint")

        self._page_size = page_size

        # clustering dropdown and export code checkbox, used in the top row
        self._clustering_method_label = Label(
            " Clustering Method: ", layout=Layout(margin="2px 0 0 20px"))
        self._clustering_method_drop = Dropdown(
            options=[
                "fingerprint", "ngram-fingerprint", "phonetic-fingerprint",
                "levenshtein"
            ],
            layout=Layout(width="150px", margin="0 0 0 10px"),
        )
        self._clustering_method_drop.observe(self._cluster_method_change,
                                             names="value")
        self._export_code = Checkbox(
            value=True,
            description="export code",
            layout=Layout(width="165px", margin="0 0 0 482px"),
            style={"description_width": "initial"},
        )
        self._dropds = HBox(
            [
                self._clustering_method_label,
                self._clustering_method_drop,
                self._export_code,
            ],
            layout=Layout(height="35px", margin="10px 0 0 0"),
        )
        # text boxes for clustering parameters used in the top row
        self._ngram_text = Text(
            value=DEFAULT_NGRAM,
            description="n-gram",
            layout=Layout(width="130px"),
            continuous_update=False,
        )
        self._radius_text = Text(
            value=DEFAULT_RADIUS,
            description="Radius",
            layout=Layout(width="130px"),
            continuous_update=False,
        )
        self._block_chars_text = Text(
            value=DEFAULT_BLOCK_SIZE,
            description="Block Chars",
            layout=Layout(width="130px"),
            continuous_update=False,
        )
        self._ngram_text.observe(self._param_recluster, names="value")
        self._radius_text.observe(self._param_recluster, names="value")
        self._block_chars_text.observe(self._param_recluster, names="value")

        # create header labels, second row
        headers = HBox(
            [
                Label("Distinct values", layout=Layout(margin="0 0 0 10px")),
                Label("Total values", layout=Layout(margin="0 0 0 35px")),
                Label("Cluster values", layout=Layout(margin="0 0 0 95px")),
                Label("Merge?", layout=Layout(margin="0 0 0 295px")),
                Label("Representative value",
                      layout=Layout(margin="0 0 0 50px")),
            ],
            layout=Layout(margin="10px"),
        )

        # create buttons for bottom row
        self._sel_all = Checkbox(description="Select all",
                                 layout=Layout(width="165px"))
        self._sel_all.observe(self._select_all, names="value")

        merge_and_recluster = Button(description="Merge and Re-Cluster",
                                     layout=Layout(margin="0 0 0 466px",
                                                   width="150px"))
        merge_and_recluster.on_click(self._execute_merge)

        finish = Button(description="Finish",
                        layout=Layout(margin="0 0 0 10px"))
        finish.on_click(self._close)

        # next and previous page buttons
        self._next_button = Button(description="Next")
        self._next_button.on_click(self._next_page)

        self._prev_button = Button(description="Previous",
                                   layout=Layout(margin="0 0 0 20px"))
        self._prev_button.on_click(self._prev_page)

        # an index in the clusters Series indicating the start of the current page
        self._page_pos = 0
        # loading label, displayed when re-clustering or next page load
        self._loading_label = Label("Loading...",
                                    layout=Layout(margin="170px 0 0 440px"))
        # displayed when the user enters a non integer value into a clustering parameter text box
        self._invalid_param_label = Label(
            "Invalid clustering parameter, please enter an integer",
            layout=Layout(margin="170px 0 0 350px"),
        )

        self._reprs = [
            Text(layout=Layout(width="200px", margin="0 10px 0 40px"))
            for _ in range(self._page_size)
        ]
        self._checks = [
            Checkbox(indent=False,
                     layout=Layout(width="auto", margin="0 0 0 20px"))
            for _ in range(self._page_size)
        ]

        # VBox containing a VBox with all the clusters in the first row and an optional
        # second row containing next and previous page buttons
        self._cluster_and_next_prev = VBox()
        self._cluster_vbox = VBox(
            layout=Layout(height="450px", flex_flow="row wrap"))

        footer = HBox([self._sel_all, merge_and_recluster, finish])

        box_children = [
            self._dropds, headers, self._cluster_and_next_prev, footer
        ]

        box_layout = Layout(display="flex",
                            flex_flow="column",
                            align_items="stretch",
                            border="solid")
        self._box = Box(children=box_children, layout=box_layout)
        self._update_clusters()

    def _update_clusters(self) -> None:
        """
        Updates the clusters currently being displayed.
        """
        line = HBox(
            children=[Label("-" * 186, layout=Layout(margin="0 0 0 18px"))])
        self._sel_all.value = False

        cluster_page = self._clusterer.get_page(
            self._page_pos, self._page_pos + self._page_size)

        label_layout = Layout(height="22px", width="360px")
        box_children = [line]
        for idx, cluster in enumerate(cluster_page):
            labels = []
            for cluster_val, cnt in cluster:
                if cnt > 1:
                    cluster_val += f" ({cnt} rows)"
                labels.append(Label(cluster_val, layout=label_layout))

            totals_vals = sum(cnt for _, cnt in cluster)
            distinct_vals = len(cluster)

            self._reprs[idx].value = cluster[0][0]
            self._checks[idx].value = False
            box_children.append(
                HBox([
                    Label(str(distinct_vals),
                          layout=Layout(width="60px", margin="0 0 0 60px")),
                    Label(str(totals_vals),
                          layout=Layout(width="60px", margin="0 0 0 50px")),
                    VBox(children=labels, layout=Layout(margin="0 0 0 80px")),
                    self._checks[idx],
                    self._reprs[idx],
                ]))

            box_children.append(line)

        # no clusters to display
        if len(cluster_page) == 0:
            box_children = [
                Label(
                    "No clusters, try a different clustering method",
                    layout=Layout(margin="170px 0 0 360px"),
                )
            ]

        self._cluster_vbox.children = box_children
        cluster_and_next_prev = [self._cluster_vbox]
        self._add_next_prev_button_row(cluster_and_next_prev)
        self._cluster_and_next_prev.children = cluster_and_next_prev

    def _update_dropds(self, clustering_method: str) -> None:
        """
        Update the dropdowns row of the UI to display the required text boxes for passing
        parameters needed for the given clustering method.
        """
        if clustering_method in ("fingerprint", "phonetic-fingerprint"):
            self._export_code.layout.margin = "0 0 0 482px"
            self._dropds.children = [
                self._clustering_method_label,
                self._clustering_method_drop,
                self._export_code,
            ]

        if clustering_method == "ngram-fingerprint":
            self._export_code.layout.margin = "0 0 0 348px"
            self._dropds.children = [
                self._clustering_method_label,
                self._clustering_method_drop,
                self._ngram_text,
                self._export_code,
            ]

        if clustering_method == "levenshtein":
            self._export_code.layout.margin = "0 0 0 214px"
            self._dropds.children = [
                self._clustering_method_label,
                self._clustering_method_drop,
                self._radius_text,
                self._block_chars_text,
                self._export_code,
            ]

    def _param_recluster(self, _: Dict[str, Any]) -> None:
        """
        Re-cluster the dataframe with the new clustering parameters.
        Triggered when the value in a clustering parameter textbox is changed.
        """
        self._display_message(self._loading_label)
        try:
            self._clusterer.set_cluster_params(*self._cluster_params())
            cluster_method = self._clustering_method_drop.value
            self._clusterer.cluster(cluster_method)
            self._page_pos = 0
            self._update_clusters()
        except ValueError:
            self._display_message(self._invalid_param_label)

    def _cluster_params(self) -> Tuple[int, int, int]:
        """
        Retrieve clustering parameters from their respective text boxes.
        """
        ngram = self._ngram_text.value if self._ngram_text.value else DEFAULT_NGRAM
        radius = self._radius_text.value if self._radius_text.value else DEFAULT_RADIUS
        block_size = self._block_chars_text.value if self._block_chars_text else DEFAULT_BLOCK_SIZE
        return int(ngram), int(radius), int(block_size)

    def _select_all(self, change: Dict[str, Any]) -> None:
        """
        Triggered when the select all checkbox is selected or unselected.
        Changes the value of the cluster checkboxes to match the state of the select all checkbox.
        """
        for check in self._checks:
            check.value = change["new"]

    def _cluster_method_change(self, change: Dict[str, Any]) -> None:
        """
        Triggered when the cluster method dropdown state is changed.
        Re-clusters the DataFrame with the new clustering method.
        """
        self._update_dropds(change["new"])
        self._display_message(self._loading_label)
        cluster_method = self._clustering_method_drop.value
        self._clusterer.cluster(cluster_method)
        self._page_pos = 0
        self._update_clusters()

    def _add_next_prev_button_row(
            self, box_children: List[Union[HBox, VBox]]) -> None:
        """
        Adds a next page or previous page button, if the operation is valid.
        """
        next_prev = []
        prev_is_valid = self._page_pos - self._page_size >= 0
        next_is_valid = self._page_pos + self._page_size < len(
            self._clusterer.clusters)

        if prev_is_valid and next_is_valid:
            self._next_button.layout.margin = "0 0 0 628px"
            next_prev.append(self._prev_button)
            next_prev.append(self._next_button)

        elif prev_is_valid:
            next_prev.append(self._prev_button)

        elif next_is_valid:
            self._next_button.layout.margin = "0 0 0 795px"
            next_prev.append(self._next_button)

        if next_is_valid or prev_is_valid:
            box_children.append(HBox(next_prev, layout={"height": "50px"}))

    def _next_page(self, _: Dict[str, Any]) -> None:
        """
        Display the next page of clusters by increasing the page position.
        """
        self._display_message(self._loading_label)
        self._page_pos += self._page_size
        self._update_clusters()
        self._sel_all_on_page()

    def _prev_page(self, _: Dict[str, Any]) -> None:
        """
        Display the previous page of clusters by decreasing the page position.
        """
        self._display_message(self._loading_label)
        self._page_pos -= self._page_size
        self._update_clusters()
        self._sel_all_on_page()

    def _display_message(self, message_label: Label) -> None:
        """
        Display a message to the user, used for the loading screen
        and invalid clustering parameter screen
        """
        self._cluster_vbox.children = [message_label]
        # don't display next and prev buttons
        self._cluster_and_next_prev.children = [
            self._cluster_and_next_prev.children[0]
        ]

    def _sel_all_on_page(self) -> None:
        """
        Select all checkboxes on the current page of clusters if the
        select all checkbox is selected.
        """
        if self._sel_all.value:
            for check in self._checks:
                check.value = True

    def _close(self, _: Dict[str, Any]) -> None:
        """
        Close the UI and display the final dataframe in the next jupyter notebook cell.
        """
        self._clusterer.final_df()
        self._box.close()

    def _execute_merge(self, _: Dict[str, Any]) -> None:
        """
        Merge the selected clusters and re-cluster the dataframe. If the export code checkbox is
        selected the required replace function calls and add them to the jupyter notebook cell.
        """
        self._display_message(self._loading_label)

        do_merge = [check.value for check in self._checks]
        new_values = [text.value for text in self._reprs]
        cluster_page = self._clusterer.get_page(
            self._page_pos, self._page_pos + self._page_size)

        if self._export_code.value:
            self._clusterer.live_export_code(cluster_page, do_merge,
                                             new_values)

        cluster_method = self._clustering_method_drop.value
        self._clusterer.execute_merge_code(cluster_page, do_merge, new_values)
        self._clusterer.cluster(cluster_method)
        self._update_page_if_empty()
        self._update_clusters()

    def _update_page_if_empty(self) -> None:
        """
        Decrease the page if the last page is empty.
        Needed for when all clusters on the last page are merged.
        """
        if self._page_pos >= len(self._clusterer.clusters):
            self._page_pos -= self._page_size

    def display(self) -> Box:
        """Display the UI."""
        return self._box
class ViewSentiment:
    def __init__(self):
        plt.close("all")
        self.backend = TextInputLoop(use_widget=True)
        self.highlighter = SentimentHighlighter(self.backend)
        self.backend.add_interface(self.highlighter)
        self.backend.start()

        self.cwd_label = Label(
            value="Working directory: {}".format(Path.cwd()),
            layout=dict(margin="2px 0px 0px 20px"),
        )
        self.save_path = Text(
            value=str(Path("saved_html.html")),
            description='Save path:',
            disabled=False,
            layout=dict(width="50%"),
        )
        self.save_button = Button(
            value=False,
            description='Save to HTML',
            disabled=False,
            button_style=
            'success',  # 'success', 'info', 'warning', 'danger' or ''
            tooltip='',
            icon='',
            layout=Layout(width='18%', margin="2px 0px 0px 20px"),
        )
        self.progress_label = Label(
            value="",
            layout=dict(margin="2px 0px 0px 20px"),
        )

        self.full_contrast = Checkbox(value=False,
                                      description='Full Contrast',
                                      disabled=False)
        self.do_highlighting = Checkbox(value=True,
                                        description='Do Highlighting',
                                        disabled=False)

        box1 = HBox(
            (self.do_highlighting, self.full_contrast),
            layout=Layout(align_content="flex-start"),
        )

        box2 = HBox(
            (self.save_path, self.save_button),
            layout=Layout(align_content="flex-start"),
        )

        self.storage_dashboard = VBox(
            (box1, self.cwd_label, box2, self.progress_label))

        # Set observers
        self.save_button.on_click(self._save)
        self.full_contrast.observe(self._special_options)
        self.do_highlighting.observe(self._special_options)

        # noinspection PyTypeChecker
        display(self.storage_dashboard)

    def _special_options(self, _=None):
        self.highlighter.full_contrast = self.full_contrast.value
        self.highlighter.do_highlighting = self.do_highlighting.value
        self.highlighter.refresh()

    def _reset_progress(self):
        self.progress_label.value = ""

    def _save(self, _=None):
        if self.highlighter.c_modifiers is not None:
            # Convert to HTML
            html = modified_text_to_html(
                text=self.highlighter.c_text,
                modifiers=self.highlighter.c_modifiers)

            # Get save path
            path = Path(self.save_path.value)

            # Save HTML
            with path.open("w") as file:
                file.write(html)

            self.progress_label.value = "Saved!"
            timer = Timer(4.0, self._reset_progress)
            timer.start()