示例#1
0
    def _make_selection_repr_buttons(self):
        vbox = VBox()
        children = []

        rep_names = REPR_NAMES[:]
        excluded_names = ['ball+stick', 'distance']
        for name in excluded_names:
            rep_names.remove(name)

        for index, name in enumerate(rep_names):
            button = ToggleButton(description=name)

            def make_func():
                def on_toggle_button_value_change(change, button=button):
                    new = change['new']  # True/False
                    if new:
                        self._view.add_representation(button.description)
                    else:
                        self._view._remove_representations_by_name(
                            button.description)

                return on_toggle_button_value_change

            button.observe(make_func(), names='value')
            children.append(button)

        boxes = []
        for index, arr in enumerate(np.array_split(children, 4)):
            box = HBox([child for child in arr])
            boxes.append(box)
        vbox.children = boxes
        return vbox
示例#2
0
    def create_highlight_toggle(self,
                                tag,
                                stats=None):  #TODO move constants out
        if stats is None:
            stats = self.get_stats(tag)

        tooltip = self.tag_tooltip(tag, stats)
        toggle_btn = ToggleButton(
            value=False,
            description='',
            disabled=False,
            button_style='',  # 'success', 'info', 'warning', 'danger' or ''
            tooltip='Press to toggle highlighting of the tag region.',
            icon='binoculars',  # (FontAwesome names without the `fa-` prefix)
            layout=Layout(height='35px',
                          width='35px',
                          borders='none',
                          align_items='center'))

        def highlight(toggle_value):
            self.model.plot.backend.highlight_selection(
                float(tag.access[0]),
                float(tag.access[1]) + 1, float(tag.address[0]),
                float(tag.address[1]) + 1, toggle_value, tag)

        toggle_btn.observe(highlight, 'value')

        return toggle_btn, tooltip
示例#3
0
    def controls(self):
        get_supercell = ToggleButton(
            value=False,
            description='Get supercell',
            disabled=False,
            button_style='',
            tooltip='Click to show supercell'
        )
        get_supercell.observe(self.supercell_callback, 'value')

        run_command = Button(
            description='Run Command',
            disabled=False
        )
        run_command.on_click(self.run_cmd_callback)

        self.command_text = Text(
            value='spin on',
            placeholder='spin on',
            description='Command:',
            disabled=False
        )

        data_filter_vbox = VBox(
            [HBox([get_supercell]), HBox([self.command_text, run_command])])

        return data_filter_vbox
示例#4
0
def start_demo():
    images_widget = ImageSelector(IMAGES, max_width=450)
    images_box = VBox(
        children=[HTML('<h1>Select Image</h1>'), images_widget.widget])
    styles_widget = ImageSelector(STYLES, max_width=450)
    styles_box = VBox(
        children=[HTML('<h1>Select Style</h1>'), styles_widget.widget])
    selectors = HBox(children=[images_box, styles_box],
                     layout=Layout(justify_content="space-between"))

    confirm_button = ToggleButton(value=False,
                                  description='Stylise',
                                  disabled=False,
                                  button_style='success',
                                  tooltip='Description',
                                  icon='check')

    confirm_box = HBox(children=[confirm_button],
                       layout=Layout(justify_content='space-around'))

    def on_click(change):
        stylised_img = stylise(image=images_widget.image,
                               style=styles_widget.image)
        stylised_widget = Image(value=to_binary(stylised_img),
                                width=stylised_img.size[0],
                                height=stylised_img.size[1],
                                format='png')
        stylised_box = HBox(children=[stylised_widget],
                            layout=Layout(justify_content='space-around'))
        full_display.children = [selectors, confirm_box, stylised_box]

    confirm_button.observe(on_click, 'value')
    full_display = VBox(children=[selectors, confirm_box])
    return full_display
示例#5
0
    def _make_repr_playground(self):
        vbox = VBox()
        children = []

        rep_names = REPRESENTATION_NAMES[:]
        excluded_names = ['ball+stick', 'distance']
        for name in excluded_names:
            rep_names.remove(name)

        repr_selection = Text(value='*')
        repr_selection.layout.width = default.DEFAULT_TEXT_WIDTH
        repr_selection_box = HBox([Label('selection'), repr_selection])
        setattr(repr_selection_box, 'value', repr_selection.value)

        for index, name in enumerate(rep_names):
            button = ToggleButton(description=name)

            def make_func():
                def on_toggle_button_value_change(change, button=button):
                    selection = repr_selection.value
                    new = change['new']  # True/False
                    if new:
                        self._view.add_representation(button.description,
                                                      selection=selection)
                    else:
                        self._view._remove_representations_by_name(
                            button.description)

                return on_toggle_button_value_change

            button.observe(make_func(), names='value')
            children.append(button)

        button_clear = Button(description='clear',
                              button_style='info',
                              icon='fa-eraser')

        @button_clear.on_click
        def on_clear(button_clear):
            self._view.clear()
            for kid in children:
                # unselect
                kid.value = False

        vbox.children = children + [repr_selection, button_clear]
        _make_autofit(vbox)
        self.widget_quick_repr = vbox
        return self.widget_quick_repr
示例#6
0
    def _make_repr_playground(self):
        vbox = VBox()
        children = []

        rep_names = REPRESENTATION_NAMES[:]
        excluded_names = ['ball+stick', 'distance']
        for name in excluded_names:
            rep_names.remove(name)

        repr_selection = Text(value='*')
        repr_selection.layout.width = default.DEFAULT_TEXT_WIDTH
        repr_selection_box  = HBox([Label('selection'), repr_selection])
        setattr(repr_selection_box, 'value', repr_selection.value)

        for index, name in enumerate(rep_names):
            button = ToggleButton(description=name)

            def make_func():
                def on_toggle_button_value_change(change, button=button):
                    selection = repr_selection.value
                    new = change['new'] # True/False
                    if new:
                        self._view.add_representation(button.description, selection=selection)
                    else:
                        self._view._remove_representations_by_name(button.description)
                return on_toggle_button_value_change

            button.observe(make_func(), names='value')
            children.append(button)

        button_clear = Button(description='clear', button_style='info',
                icon='fa-eraser')

        @button_clear.on_click
        def on_clear(button_clear):
            self._view.clear()
            for kid in children:
                # unselect
                kid.value = False

        vbox.children = children + [repr_selection, button_clear]
        _make_autofit(vbox)
        self.widget_quick_repr = vbox
        return self.widget_quick_repr
class GUI(object):

    _BUTTONS = {
        "backstep": {
            "icon": "step-backward",
            "tooltip": "Step to the previous instruction",
        },
        "step": {
            "icon": "step-forward",
            "tooltip": "Step to the next instruction",
        },
        "previous": {
            "icon": "reply",
            "tooltip": "Go to th previous sourceline",
        },
        "next": {
            "icon": "share",
            "tooltip": "Go to the next sourceline",
        },
        "start": {
            "icon": "arrow-up",
            "tooltip": "Go to the start of the program",
        },
        "finish": {
            "icon": "arrow-down",
            "tooltip": "Go to the end of the program",
        },
        "reverse": {
            "icon": "fast-backward",
            "tooltip": "Continue execution backwards until breakpoint is hit",
        },
        "continue": {
            "icon": "fast-forward",
            "tooltip": "Continue execution until breakpoint is hit",
        },
    }

    def __init__(self):
        # Stores the respective line number and variable changes for each
        # exection step
        self._tracer = TimeTravelTracer()
        self._current_state = None
        self._debugger = None

        self._code_output = HTML()
        self._var_output = Output()
        self._watchpoint_output = Output()
        self._breakpoint_output = Output()

        self._diff_slider = IntSlider(
            min=1,
            readout=False,
            layout=Layout(width="99%"),
            tooltip="Execution timeline",
        )
        self._diff_slider.observe(self._handle_diff_slider, names="value")

        self._autoplay = Play(
            tooltip="Automatic playback of the execution",
            layout=Layout(height="30px"),
        )
        self._auto_link = jsdlink((self._autoplay, "value"),
                                  (self._diff_slider, "value"))

        self._speed_slider = IntSlider(description="Delay (ms)",
                                       min=100,
                                       max=1000,
                                       step=100,
                                       value=500)
        self._speed_link = jsdlink((self._speed_slider, "value"),
                                   (self._autoplay, "interval"))

        self._reverse_autoplay = ToggleButton(
            value=False,
            icon="history",
            tooltip="Reverse autoplay",
            layout=Layout(width="40px"),
        )
        self._reverse_autoplay.observe(self._handle_reverse_button)

        self._watchpoint_input = Text(
            layout=Layout(width="150px"),
            placeholder="Watch expression",
        )
        self._add_watchpoint = Button(
            icon="plus",
            tooltip="Add an expression or variable to watch",
            layout=Layout(width="50px"),
        )
        self._add_watchpoint.on_click(self.watch_command)

        self._watchpoint_dropdown = Dropdown(layout=Layout(width="150px"), )
        self._remove_watchpoint = Button(
            icon="trash",
            tooltip="Remove a watchpoint",
            layout=Layout(width="50px"),
        )
        self._remove_watchpoint.on_click(self.unwatch_command)

        self._breakpoint_layout = GridspecLayout(3, 1)

        self._add_breakpoint = Button(
            icon="plus",
            tooltip="Add a breakpoint",
            name="breakpoint_button",
            layout=Layout(width="40px"),
        )
        self._add_breakpoint.on_click(self._handle_breakpoint)

        self._disable_breakpoint_button = Button(
            icon="eye-slash",
            tooltip="Disable breakpoint",
            layout=Layout(width="50px"),
        )
        self._disable_breakpoint_button.on_click(self.disable_command)

        self._remove_breakpoint_button = Button(
            icon="trash",
            tooltip="Remove breakpoint",
            layout=Layout(width="50px"),
        )
        self._remove_breakpoint_button.on_click(self.delete_command)

        self._breakpoint_dropdown = Dropdown(layout=Layout(width="70px"))

        self._function_dropdown = Dropdown(layout=Layout(width="200px"))
        self._function_dropdown.disabled = True
        self._breakpoint_type = Dropdown(
            options=["Line", "Function", "Conditional"],
            value="Line",
            layout=Layout(width="100px"),
        )

        self._breakpoint_type.observe(self._handle_breakpoint_type,
                                      names="value")

        self._condition_input = Text(placeholder="Enter condition",
                                     layout=Layout(width="200px"))
        self._condition_input.disabled = True

        self._line_input = Text(
            placeholder="Line Number",
            name="line_input",
            layout=Layout(width="100px"),
        )

        self._breakpoint_layout = VBox([
            HBox([
                self._add_breakpoint,
                self._breakpoint_type,
                self._function_dropdown,
                self._line_input,
                self._condition_input,
                self._breakpoint_dropdown,
                self._remove_breakpoint_button,
                self._disable_breakpoint_button,
            ]),
            self._breakpoint_output,
        ])

        self._search_input = Text(placeholder="Search...")
        self._search_input.observe(self._handle_search_input, names="value")

        self._search_results = Output()
        self._search_layout = VBox([
            self._search_input,
            self._search_results,
        ])

        # Remove shadows from scrolling
        style = """
            <style>
               .jupyter-widgets-output-area .output_scroll {
                    border-radius: unset !important;
                    -webkit-box-shadow: unset !important;
                    box-shadow: unset !important;
                }
            </style>
            """
        display(HTML(style))

        for key, item in self._BUTTONS.items():
            self.register_button(key, **item)

        self._code_layout = GridspecLayout(4, 4, grid_gap="20px")

        self._code_layout[0:4, 0:3] = HBox(
            [self._code_output],
            layout=Layout(height="500px",
                          overflow_y="scroll",
                          border="2px solid black"),
        )
        self._code_layout[0:2, 3] = self._var_output
        self._code_layout[2:4, 3] = VBox([
            HBox([self._add_watchpoint, self._watchpoint_input]),
            HBox([self._remove_watchpoint, self._watchpoint_dropdown]),
            self._watchpoint_output,
        ])

        self._code_nav_layout = VBox([
            HBox([
                *self.get_buttons(),
                self._autoplay,
                self._reverse_autoplay,
                self._speed_slider,
            ]),
            self._diff_slider,
            self._code_layout,
        ])

        self._main_layout = Tab(
            [
                self._code_nav_layout,
                self._breakpoint_layout,
                self._search_layout,
            ],
            layout=Layout(height="650px"),
        )

        self._main_layout.set_title(0, "Code")
        self._main_layout.set_title(1, "Breakpoints")
        self._main_layout.set_title(2, "Search")

        display(self._main_layout)

    def __enter__(self, *args, **kwargs):
        self._tracer.set_trace()

    def __exit__(self, *args, **kwargs):
        diffs, source_map = self._tracer.get_trace()
        search_engine = SearchEngine()
        self._debugger = TimeTravelDebugger(diffs, source_map, self.update,
                                            search_engine)
        self._debugger.start_debugger()
        self._diff_slider.max = len(diffs) - 1
        self._function_dropdown.options = self._debugger.source_map.keys()

    def get_buttons(self, *keys):
        if not keys:
            return [
                self._BUTTONS[key]["button"] for key in self._BUTTONS.keys()
            ]
        return [self._BUTTONS[key]["button"] for key in keys]

    def register_button(self, key, **kwargs):
        button = Button(description="", layout=Layout(width="40px"), **kwargs)
        func = getattr(self, key + "_command")
        button.on_click(func)
        self._BUTTONS[key]["button"] = button

    def update(self, state=None):
        if state is not None:
            self._current_state = state

        self._diff_slider.value = self._debugger._state_machine._exec_point

        self._BUTTONS["previous"]["button"].disabled = self._debugger.at_start
        self._BUTTONS["start"]["button"].disabled = self._debugger.at_start
        self._BUTTONS["backstep"]["button"].disabled = self._debugger.at_start
        self._BUTTONS["next"]["button"].disabled = self._debugger.at_end
        self._BUTTONS["finish"]["button"].disabled = self._debugger.at_end
        self._BUTTONS["step"]["button"].disabled = self._debugger.at_end

        self._breakpoint_dropdown.options = [
            b.id for b in self._debugger.breakpoints
        ]
        self._watchpoint_dropdown.options = [
            b.id for b in self._debugger.watchpoints
        ]

        self.list_command()

        with self._var_output:
            clear_output(wait=True)
            self.print_command()

        with self._breakpoint_output:
            clear_output(wait=True)
            self.breakpoints_command()

        with self._watchpoint_output:
            clear_output(wait=True)
            self.list_watch_command()

    def log(self, *objects, sep=" ", end="\n", flush=False):
        """Like print(), but always sending to file given at initialization,
        and always flushing"""
        print(*objects, sep=sep, end=end, flush=True)

    # COMMANDS
    def print_command(self, arg=""):
        """Print all variables or pass an expression to evaluate in the
        current context"""
        # Shorthand such that the following code is not as lengthy
        curr_vars = self._current_state
        template = "|`{}`|{}|`{!r}`|"
        header = "| Variable | Type | Value |"
        split = "| --- | --- | --- |"

        variable_table = header + "\n" + split + "\n"
        variable_table += "\n".join(
            template.format(var, type(curr_vars[var]), curr_vars[var])
            for var in curr_vars if not var.startswith("__"))

        display(Markdown(variable_table))

    def step_command(self, arg=""):
        """ Step to the next instruction """
        self._debugger.step_forward()

    def backstep_command(self, arg=""):
        """ Step to the previous instruction """
        self._debugger.step_backward()

    def list_command(self, arg=""):
        """Show current function. If arg is given, show its source code."""
        display_current_line = self._debugger.curr_line

        code = self._debugger.get_source_for_func()

        source_lines = open(code["filename"]).read()

        css = f"""
        <style>
        {cssfile}
        </style>
        """

        lexer = lexers.get_lexer_by_name("python")
        formatter = formatters.HtmlFormatter(
            linenos=True,
            anchorlinenos=True,
            full=True,
            linespans=True,
            wrapcode=True,
        )
        coloured = highlight(source_lines, lexer=lexer, formatter=formatter)

        doc = html.fromstring(coloured)

        current_line_breakpoint = False

        # Highlight all breakpoints on the current file
        for bp in self._debugger.breakpoints:
            if self._debugger.curr_diff.file_name != bp.abs_filename:
                continue
            if bp.breakpoint_type != BPType.FUNC:
                elem = doc.get_element_by_id(f"True-{bp.lineno}", None)
                if bp.lineno == display_current_line:
                    current_line_breakpoint = True
                if elem is not None:
                    elem.set("class", "breakpoint")
                    if not bp.active:
                        elem.set("class", "inactive")

        elem = doc.get_element_by_id(f"True-{display_current_line}", None)
        if elem is not None:
            if not current_line_breakpoint and not self._autoplay._playing:
                elem.set("class", "currentline")
            elif self._autoplay._playing:
                elem.set("class", "currentline-running")
            else:
                elem.set("class", "hit")

        coloured = html.tostring(doc).decode("utf-8").strip()

        self._code_output.value = css + coloured

    def next_command(self, arg=""):
        """ Step to the next source line """
        self._debugger.next()

    def previous_command(self, arg=""):
        """ Step to the previous source line """
        self._debugger.previous()

    def finish_command(self, arg=""):
        """ Finish the current function execution """
        self._debugger.finish()

    def start_command(self, arg=""):
        """ Go to start of the current function call """
        self._debugger.start()

    def continue_command(self, arg=""):
        """ Continue execution forward until a breakpoint is hit """
        self._debugger.continue_()

    def reverse_command(self, arg=""):
        """ Continue execution backward until a breakpoint is hit """
        self._debugger.reverse()

    def watch_command(self, change):
        """ Insert a watchpoint """
        arg = self._watchpoint_input.value
        self._debugger.add_watchpoint(expression=arg)
        self._watchpoint_input.value = ""
        self.update()

    def list_watch_command(self):
        header = "| ID | Expression | Value |\n"
        split = "|---|---|---|\n"
        template = "|{}|`{}`|`{!r}`|\n"
        wpstr = header + split

        for wp in self._debugger.watchpoints:
            wpstr += template.format(*wp)

        display(Markdown(wpstr))

    def unwatch_command(self, change):
        """ Remove a watchpoint """
        arg = self._watchpoint_dropdown.value
        if not arg:
            return
        if not self._debugger.remove_watchpoint(int(arg)):
            print(f"Watchpoint with id {arg} does not exist.")
        else:
            print(f"Successfully removed watchpoint {arg}.")
            self.update()

    def break_command(self, arg=""):
        """ Insert a breakpoint at the given location """
        res = None
        # Find out which type of breakpoint we want to insert
        if arg.isnumeric():
            # Line breakpoint
            res = self._debugger.add_breakpoint(arg, "line")
        elif ":" not in arg:
            # Function breakpoint for different file
            res = self._debugger.add_breakpoint(arg, "func")
        else:
            filename, function_name = arg.split(":")
            res = self._debugger.add_breakpoint(function_name,
                                                "func",
                                                filename=filename)

        if res is not None:
            print(f"Breakpoint {res.id} added.")
        else:
            print("Could not add breakpoint.")

    def breakpoints_command(self, arg=""):
        """ List all breakpoints """
        header = "| ID | Type | Location | Status | Condition |\n"
        split = "|---|---|---|---|---|\n"

        bpstr = header + split

        for bp in self._debugger.breakpoints:
            bpstr += "|" + "|".join(bp) + "|\n"

        display(Markdown(bpstr))

    def delete_command(self, change):
        """ Remove the given breakpoint """
        arg = self._breakpoint_dropdown.value
        if not arg:
            return
        self._debugger.remove_breakpoint(int(arg))
        self.update()

    def disable_command(self, arg=""):
        """ Disable the given breakpoint """
        arg = self._breakpoint_dropdown.value
        if not arg:
            return
        self._debugger.disable_breakpoint(int(arg))
        self.update()

    def enable_command(self, arg=""):
        """ Enable the given breakpoint """
        self._debugger.enable_breakpoint(int(arg))

    def _handle_diff_slider(self, change):
        braked = self._debugger.step_to_index(
            change["new"], ignore_breakpoints=self._autoplay._playing)
        if braked:
            self._autoplay._playing = False

    def _handle_reverse_button(self, change):
        self._autoplay.step = -self._autoplay.step

    def _handle_breakpoint(self, change):
        type = self._breakpoint_type.value
        function = self._function_dropdown.value
        line = self._line_input.value
        condition = self._condition_input.value

        if type != "Function":
            if not line.isnumeric() or line is None:
                self._line_input.value = ""
                self._line_input.placeholder = "Please enter a valid number!"
                return

        if type == "Conditional":
            try:
                eval(condition)
            except SyntaxError:
                if self._condition_input.value:
                    self._condition_input.placeholder = "Invalid expression!"
                self._condition_input.value = ""
                return

            except NameError:
                pass

        if type == "Function":
            self._debugger.add_breakpoint(funcname=function)
        if type == "Line":
            self._debugger.add_breakpoint(lineno=line)
        if type == "Conditional":
            self._debugger.add_breakpoint(lineno=line, cond=condition)

        self.update()

    def _handle_breakpoint_type(self, change):
        self._function_dropdown.disabled = change["new"] != "Function"
        self._condition_input.disabled = change["new"] != "Conditional"
        self._line_input.disabled = change["new"] == "Function"

    def _handle_search_input(self, change):
        try:
            input = change["new"]
            event_type, query = input.split(" ", 1)
            events = self._debugger.search(event_type, query)
        except:
            return

        with self._search_results:
            clear_output()
            for event in events:
                goto = Button(
                    icon="angle-right",
                    layout=Layout(width="30px", height="30px"),
                )
                goto.on_click(lambda change: self._debugger.step_to_index(
                    event.exec_point, ignore_breakpoints=True))
                display(HBox([goto, Label(value=str(event))]))
示例#8
0
class TrendsWithPickTokensGUI:
    def __init__(self,
                 token_selector: TokensSelector,
                 update_handler: Callable = None):
        self.token_selector: TokensSelector = token_selector
        self.update_handler: Callable = update_handler

        self._page_size = IntSlider(
            description="Count",
            min=0,
            max=100,
            step=1,
            value=3,
            continuous_update=False,
            layout=Layout(width="300px"),
        )
        self._forward = Button(
            description=">>",
            button_style="Success",
            layout=Layout(width="40px", color="green"),
        )
        self._back = Button(
            description="<<",
            button_style="Success",
            layout=Layout(width="40px", color="green"),
        )
        self._split = ToggleButton(description="Split",
                                   layout=Layout(width="80px", color="green"))
        self._output = Output(layout=Layout(width="80%"))

    def setup(self):

        self._page_size.observe(self._update, "value")
        self._split.observe(self.split_changed, "value")
        self._forward.on_click(self._stepper_clicked)
        self._back.on_click(self._stepper_clicked)
        self.token_selector.on_selection_change_handler(self._update)

    def _stepper_clicked(self, b):

        _selected_indices = self.token_selector.get_selected_indices()
        _current_index = min(
            _selected_indices) if len(_selected_indices) > 0 else 0

        if b.description == "<<":
            _current_index = max(_current_index - self.page_size, 0)

        if b.description == ">>":
            _current_index = min(_current_index + self.page_size,
                                 len(self.token_selector) - self.page_size)

        self.token_selector.set_selected_indices(
            list(range(_current_index, _current_index + self.page_size)))

    def _update(self):
        if self.update_handler is not None:
            with self._output:
                tokens = self.selected_tokens()
                self.update_handler(self, tokens)

    def split_changed(self, *_):
        self._update()

    def layout(self):
        return VBox([
            HBox([self._back, self._forward, self._page_size, self._split]),
            HBox([self.token_selector.widget, self._output],
                 layout=Layout(width="98%")),
        ])

    def display(self, trends_data: TrendsData):
        self.token_selector.display(
            trends_data.gof_data.most_deviating_overview)

    @property
    def page_size(self) -> int:
        return self._page_size.value

    @property
    def split(self) -> bool:
        return self._split.value

    @property
    def selected_tokens(self) -> Sequence[str]:
        tokens: Sequence[str] = self.token_selector.get_selected_tokens()
        if len(tokens) == 0:
            tokens = self.token_selector[:self.page_size]
        return tokens

    @staticmethod
    def create(
        corpus: VectorizedCorpus,
        tokens: pd.DataFrame,
        n_columns: int = 3,
        token_sector_cls: TokensSelector = SelectMultipleTokensSelector,
        tokens_selected=None,
    ) -> "TrendsWithPickTokensGUI":

        gui = TrendsWithPickTokensGUI(
            token_selector=token_sector_cls(tokens),
            update_handler=lambda tokens, split:
            (tokens_selected or TrendsWithPickTokensGUI.default_tokens_plotter)
            (tokens=tokens, corpus=corpus, n_columns=n_columns, split=split),
        )
        return gui

    @staticmethod
    def default_tokens_plotter(tokens: Sequence[str], corpus: VectorizedCorpus,
                               n_columns: int, split: bool):
        indices: List[int] = [corpus.token2id[token] for token in tokens]
        p = plotter.yearly_token_distribution_multiple_line_plot(
            corpus,
            indices,
            width=1000,
            height=600,
            n_columns=n_columns if split else None,
        )
        if p is None:
            return
        show(p)
class InteractiveLogging():
    def __init__(self, settings, test_name=None, default_window='hanning'):

        if default_window is None:
            default_window = 'None'
        self.settings = settings
        self.test_name = test_name
        self.dataset = datastructure.DataSet()

        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out = Output()
        self.out_top = Output(layout=Layout(height='120px'))

        # Initialise variables
        self.current_view = 'Time'
        self.N_frames = 1
        self.overlap = 0.5
        self.iw_fft_power = 0
        self.iw_tf_power = 0
        self.legend_loc = 'lower right'

        # puts plot inside widget so can have buttons next to plot
        self.outplot = Output(layout=Layout(width='85%'))

        # BUTTONS
        items_measure = [
            'Log Data', 'Delete Last Measurement', 'Reset (clears all data)',
            'Load Data'
        ]
        items_view = ['View Time', 'View FFT', 'View TF']
        items_calc = ['Calc FFT', 'Calc TF', 'Calc TF average']
        items_axes = ['xmin', 'xmax', 'ymin', 'ymax']
        items_save = ['Save Dataset', 'Save Figure']
        items_iw = ['multiply iw', 'divide iw']

        items_legend = ['Left', 'on/off', 'Right']

        self.buttons_measure = [
            Button(description=i, layout=Layout(width='33%'))
            for i in items_measure
        ]
        self.buttons_measure[0].button_style = 'success'
        self.buttons_measure[0].style.font_weight = 'bold'
        self.buttons_measure[1].button_style = 'warning'
        self.buttons_measure[1].style.font_weight = 'bold'
        self.buttons_measure[2].button_style = 'danger'
        self.buttons_measure[2].style.font_weight = 'bold'
        self.buttons_measure[3].button_style = 'primary'
        self.buttons_measure[3].style.font_weight = 'bold'

        self.buttons_view = [
            Button(description=i, layout=Layout(width='95%'))
            for i in items_view
        ]
        self.buttons_view[0].button_style = 'info'
        self.buttons_view[1].button_style = 'info'
        self.buttons_view[2].button_style = 'info'

        self.buttons_calc = [
            Button(description=i, layout=Layout(width='99%'))
            for i in items_calc
        ]
        self.buttons_calc[0].button_style = 'primary'
        self.buttons_calc[1].button_style = 'primary'
        self.buttons_calc[2].button_style = 'primary'

        self.buttons_iw_fft = [
            Button(description=i, layout=Layout(width='50%')) for i in items_iw
        ]
        self.buttons_iw_fft[0].button_style = 'info'
        self.buttons_iw_fft[1].button_style = 'info'

        self.buttons_iw_tf = [
            Button(description=i, layout=Layout(width='50%')) for i in items_iw
        ]
        self.buttons_iw_tf[0].button_style = 'info'
        self.buttons_iw_tf[1].button_style = 'info'

        self.buttons_match = Button(description='Match Amplitudes',
                                    layout=Layout(width='99%'))
        self.buttons_match.button_style = 'info'

        self.buttons_save = [
            Button(description=i, layout=Layout(width='50%'))
            for i in items_save
        ]
        self.buttons_save[0].button_style = 'success'
        self.buttons_save[0].style.font_weight = 'bold'
        self.buttons_save[1].button_style = 'success'
        self.buttons_save[1].style.font_weight = 'bold'

        self.button_warning = Button(
            description=
            'WARNING: Data may be clipped. Press here to delete last measurement.',
            layout=Layout(width='100%'))
        self.button_warning.button_style = 'danger'
        self.button_warning.style.font_weight = 'bold'

        self.button_X = Button(description='Auto X',
                               layout=Layout(width='95%'))
        self.button_Y = Button(description='Auto Y',
                               layout=Layout(width='95%'))
        self.button_X.button_style = 'success'
        self.button_Y.button_style = 'success'

        self.buttons_legend = [
            Button(description=i, layout=Layout(width='31%'))
            for i in items_legend
        ]
        self.buttons_legend_toggle = ToggleButton(description='Click-and-drag',
                                                  layout=Layout(
                                                      width='95%',
                                                      alignitems='start'))

        # TEXT/LABELS/DROPDOWNS
        self.item_iw_fft_label = Label(value='iw power={}'.format(0),
                                       layout=Layout(width='100%'))
        self.item_iw_tf_label = Label(value='iw power={}'.format(0),
                                      layout=Layout(width='100%'))
        self.item_label = Label(value="Frame length = {:.2f} seconds.".format(
            settings.stored_time /
            (self.N_frames - self.overlap * self.N_frames + self.overlap)))
        self.item_axis_label = Label(value="Axes control:",
                                     layout=Layout(width='95%'))
        self.item_view_label = Label(value="View data:",
                                     layout=Layout(width='95%'))
        self.item_legend_label = Label(value="Legend position:",
                                       layout=Layout(width='95%'))
        self.item_blank_label = Label(value="", layout=Layout(width='95%'))

        self.text_axes = [
            FloatText(value=0, description=i, layout=Layout(width='95%'))
            for i in items_axes
        ]
        self.text_axes = [self.button_X] + [self.button_Y] + self.text_axes
        self.drop_window = Dropdown(options=['None', 'hanning'],
                                    value=default_window,
                                    description='Window:',
                                    layout=Layout(width='99%'))
        self.slide_Nframes = IntSlider(value=1,
                                       min=1,
                                       max=30,
                                       step=1,
                                       description='N_frames:',
                                       continuous_update=True,
                                       readout=False,
                                       layout=Layout(width='99%'))
        self.text_Nframes = IntText(value=1,
                                    description='N_frames:',
                                    layout=Layout(width='99%'))

        # VERTICAL GROUPS

        group0 = VBox([
            self.buttons_calc[0], self.drop_window,
            HBox(self.buttons_iw_fft)
        ],
                      layout=Layout(width='33%'))
        group1 = VBox([
            self.buttons_calc[1], self.drop_window, self.slide_Nframes,
            self.text_Nframes, self.item_label,
            HBox(self.buttons_iw_tf), self.buttons_match
        ],
                      layout=Layout(width='33%'))
        group2 = VBox([
            self.buttons_calc[2], self.drop_window,
            HBox(self.buttons_iw_tf), self.buttons_match
        ],
                      layout=Layout(width='33%'))

        group_view = VBox(
            [self.item_axis_label] + self.text_axes +
            [self.item_legend_label, self.buttons_legend_toggle] +
            [HBox(self.buttons_legend), self.item_view_label] +
            self.buttons_view,
            layout=Layout(width='20%'))

        # ASSEMBLE
        display(self.out_top)
        display(HBox([self.button_warning]))
        display(HBox(self.buttons_measure))
        display(HBox([self.outplot, group_view]))
        display(HBox([group0, group1, group2]))
        display(HBox(self.buttons_save))
        self.button_warning.layout.visibility = 'hidden'

        # second part to putting plot inside widget
        with self.outplot:
            self.p = plotting.PlotData(figsize=(7.5, 4))

        ## Make buttons/boxes interactive

        self.text_axes[2].observe(self.xmin, names='value')
        self.text_axes[3].observe(self.xmax, names='value')
        self.text_axes[4].observe(self.ymin, names='value')
        self.text_axes[5].observe(self.ymax, names='value')

        self.button_X.on_click(self.auto_x)
        self.button_Y.on_click(self.auto_y)

        self.buttons_legend[0].on_click(self.legend_left)
        self.buttons_legend[1].on_click(self.legend_onoff)
        self.buttons_legend[2].on_click(self.legend_right)
        self.buttons_legend_toggle.observe(self.legend_toggle)

        self.slide_Nframes.observe(self.nframes_slide)
        self.text_Nframes.observe(self.nframes_text)

        self.buttons_measure[0].on_click(self.measure)
        self.buttons_measure[1].on_click(self.undo)
        self.buttons_measure[2].on_click(self.reset)
        self.buttons_measure[3].on_click(self.load_data)

        self.buttons_view[0].on_click(self.view_time)
        self.buttons_view[1].on_click(self.view_fft)
        self.buttons_view[2].on_click(self.view_tf)

        self.buttons_calc[0].on_click(self.fft)
        self.buttons_calc[1].on_click(self.tf)
        self.buttons_calc[2].on_click(self.tf_av)

        self.buttons_iw_fft[0].on_click(self.xiw_fft)
        self.buttons_iw_fft[1].on_click(self.diw_fft)
        self.buttons_iw_tf[0].on_click(self.xiw_tf)
        self.buttons_iw_tf[1].on_click(self.diw_tf)

        self.buttons_match.on_click(self.match)

        self.buttons_save[0].on_click(self.save_data)
        self.buttons_save[1].on_click(self.save_fig)

        self.button_warning.on_click(self.undo)

        self.refresh_buttons()

        # Put output text at bottom of display
        display(self.out)

        with self.out_top:
            try:
                streams.start_stream(settings)
                self.rec = streams.REC
            except:
                print('Data stream not initialised.')
                print(
                    'Possible reasons: pyaudio or PyDAQmx not installed, or acquisition hardware not connected.'
                )
                print('Please note that it won' 't be possible to log data.')

    def xmin(self, v):
        xmin = self.text_axes[2].value
        xlim = self.p.ax.get_xlim()
        self.p.ax.set_xlim([xmin, xlim[1]])

    def xmax(self, v):
        xmax = self.text_axes[3].value
        xlim = self.p.ax.get_xlim()
        self.p.ax.set_xlim([xlim[0], xmax])

    def ymin(self, v):
        ymin = self.text_axes[4].value
        ylim = self.p.ax.get_ylim()
        self.p.ax.set_ylim([ymin, ylim[1]])

    def ymax(self, v):
        ymax = self.text_axes[5].value
        ylim = self.p.ax.get_ylim()
        self.p.ax.set_ylim([ylim[0], ymax])

    def auto_x(self, b):
        self.p.auto_x()

    def auto_y(self, b):
        self.p.auto_y()

    def legend_left(self, b):
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            self.legend_loc = 'lower left'
            self.p.update_legend(self.legend_loc)

    def legend_right(self, b):
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            self.legend_loc = 'lower right'
            self.p.update_legend(self.legend_loc)

    def legend_onoff(self, b):
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            visibility = self.p.ax.get_legend().get_visible()
            self.p.ax.get_legend().set_visible(not visibility)

    def legend_toggle(self, b):
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            self.p.ax.get_legend().set_visible(True)
            self.p.legend.set_draggable(self.buttons_legend_toggle.value)

    def nframes_slide(self, v):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            self.N_frames = self.slide_Nframes.value
            self.text_Nframes.value = self.N_frames
            if len(self.dataset.time_data_list) is not 0:
                stored_time = self.dataset.time_data_list[
                    0].settings.stored_time
            elif len(self.dataset.tf_data_list) is not 0:
                stored_time = self.dataset.tf_data_list[0].settings.stored_time
            else:
                stored_time = 0
                print('Time or TF data settings not found')

            self.item_label.value = "Frame length = {:.2f} seconds.".format(
                stored_time /
                (self.N_frames - self.overlap * self.N_frames + self.overlap))
            if self.current_view is 'TF':
                self.tf(None)

    def nframes_text(self, v):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            self.N_frames = self.text_Nframes.value
            self.slide_Nframes.value = self.N_frames
            if len(self.dataset.time_data_list) is not 0:
                stored_time = self.dataset.time_data_list[
                    0].settings.stored_time
            elif len(self.dataset.tf_data_list) is not 0:
                stored_time = self.dataset.tf_data_list[0].settings.stored_time
            else:
                stored_time = 0
                print('Time or TF data settings not found')
            self.item_label.value = "Frame length = {:.2f} seconds.".format(
                stored_time /
                (self.N_frames - self.overlap * self.N_frames + self.overlap))
            if self.current_view is 'TF':
                self.tf(None)

    def measure(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            self.rec.trigger_detected = False
            self.buttons_measure[0].button_style = ''
            if self.settings.pretrig_samples is None:
                self.buttons_measure[0].description = 'Logging ({}s)'.format(
                    self.settings.stored_time)
            else:
                self.buttons_measure[
                    0].description = 'Logging ({}s, with trigger)'.format(
                        self.settings.stored_time)

            d = acquisition.log_data(self.settings,
                                     test_name=self.test_name,
                                     rec=self.rec)
            self.dataset.add_to_dataset(d.time_data_list)
            N = len(self.dataset.time_data_list)
            self.p.update(self.dataset.time_data_list,
                          sets=[N - 1],
                          channels='all')
            self.p.auto_x()
            #            self.p.auto_y()
            self.p.ax.set_ylim([-1, 1])
            self.current_view = 'Time'
            self.buttons_measure[0].button_style = 'success'
            self.buttons_measure[0].description = 'Log Data'

            if np.any(np.abs(d.time_data_list[-1].time_data) > 0.95):
                self.button_warning.layout.visibility = 'visible'
            else:
                self.button_warning.layout.visibility = 'hidden'

            xlim = self.p.ax.get_xlim()
            ylim = self.p.ax.get_ylim()
            self.text_axes[2].value = xlim[0]
            self.text_axes[3].value = xlim[1]
            self.text_axes[4].value = ylim[0]
            self.text_axes[5].value = ylim[1]
            self.refresh_buttons()

    def undo(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            self.dataset.remove_last_data_item('TimeData')
            self.dataset.freq_data_list = datastructure.FreqDataList()
            self.dataset.tf_data_list = datastructure.TfDataList()
            N = len(self.dataset.time_data_list)
            self.p.update(self.dataset.time_data_list,
                          sets=[N - 1],
                          channels='all')
            self.button_warning.layout.visibility = 'hidden'
            self.refresh_buttons()

    def reset(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.dataset = datastructure.DataSet()
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            N = len(self.dataset.time_data_list)
            self.p.update(self.dataset.time_data_list,
                          sets=[N - 1],
                          channels='all')
            self.refresh_buttons()

    def load_data(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            d = file.load_data()
            if d is not None:
                self.dataset.add_to_dataset(d.time_data_list)
                self.dataset.add_to_dataset(d.freq_data_list)
                self.dataset.add_to_dataset(d.tf_data_list)
                self.dataset.add_to_dataset(d.cross_spec_data_list)
                self.dataset.add_to_dataset(d.sono_data_list)
            else:
                print('No data loaded')

            if len(self.dataset.time_data_list) is not 0:
                self.p.update(self.dataset.time_data_list,
                              sets='all',
                              channels='all')
            elif len(self.dataset.freq_data_list) is not 0:
                self.p.update(self.dataset.freq_data_list,
                              sets='all',
                              channels='all')
            elif len(self.dataset.tf_data_list) is not 0:
                self.p.update(self.dataset.tf_data_list,
                              sets='all',
                              channels='all')
            else:
                print('No data to view')

            self.refresh_buttons()

            self.p.auto_x()
            self.p.auto_y()

            xlim = self.p.ax.get_xlim()
            ylim = self.p.ax.get_ylim()
            self.text_axes[2].value = xlim[0]
            self.text_axes[3].value = xlim[1]
            self.text_axes[4].value = ylim[0]
            self.text_axes[5].value = ylim[1]

    def view_time(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            self.refresh_buttons()
            N = len(self.dataset.time_data_list)
            if N is not 0:
                self.p.update(self.dataset.time_data_list)
                if self.current_view is not 'Time':
                    self.current_view = 'Time'
                    self.p.auto_x()
                    self.p.auto_y()

                xlim = self.p.ax.get_xlim()
                ylim = self.p.ax.get_ylim()
                self.text_axes[2].value = xlim[0]
                self.text_axes[3].value = xlim[1]
                self.text_axes[4].value = ylim[0]
                self.text_axes[5].value = ylim[1]
            else:
                print('no time data to display')

    def view_fft(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            N = len(self.dataset.freq_data_list)
            self.refresh_buttons()
            if N is not 0:
                self.p.update(self.dataset.freq_data_list)
                if self.current_view is not 'FFT':
                    self.current_view = 'FFT'
                    self.p.auto_x()
                    self.p.auto_y()

                xlim = self.p.ax.get_xlim()
                ylim = self.p.ax.get_ylim()
                self.text_axes[2].value = xlim[0]
                self.text_axes[3].value = xlim[1]
                self.text_axes[4].value = ylim[0]
                self.text_axes[5].value = ylim[1]
            else:
                print('no FFT data to display')

    def view_tf(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            N = len(self.dataset.tf_data_list)
            self.refresh_buttons()
            if N is not 0:
                self.p.update(self.dataset.tf_data_list)
                if self.current_view is not 'TF':
                    self.current_view = 'TF'
                    self.p.auto_x()
                    self.p.auto_y()
                xlim = self.p.ax.get_xlim()
                ylim = self.p.ax.get_ylim()
                self.text_axes[2].value = xlim[0]
                self.text_axes[3].value = xlim[1]
                self.text_axes[4].value = ylim[0]
                self.text_axes[5].value = ylim[1]
            else:
                print('no TF data to display')

    def fft(self, b):
        window = self.drop_window.value
        if window is 'None':
            window = None
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            self.dataset.calculate_fft_set(window=window)
            self.p.update(self.dataset.freq_data_list)
            if self.current_view is not 'FFT':
                self.current_view = 'FFT'
                self.p.auto_x()
                self.p.auto_y()

            xlim = self.p.ax.get_xlim()
            ylim = self.p.ax.get_ylim()
            self.text_axes[2].value = xlim[0]
            self.text_axes[3].value = xlim[1]
            self.text_axes[4].value = ylim[0]
            self.text_axes[5].value = ylim[1]
            self.refresh_buttons()

    def tf(self, b):
        N_frames = self.N_frames
        window = self.drop_window.value
        if window is 'None':
            window = None
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            self.dataset.calculate_tf_set(window=window,
                                          N_frames=N_frames,
                                          overlap=self.overlap)
            self.p.update(self.dataset.tf_data_list)
            if self.current_view is not 'TF':
                self.current_view = 'TF'
                self.p.auto_x()
                self.p.auto_y()
            xlim = self.p.ax.get_xlim()
            ylim = self.p.ax.get_ylim()
            self.text_axes[2].value = xlim[0]
            self.text_axes[3].value = xlim[1]
            self.text_axes[4].value = ylim[0]
            self.text_axes[5].value = ylim[1]
            self.refresh_buttons()

    def tf_av(self, b):
        window = self.drop_window.value
        if window is 'None':
            window = None
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            self.dataset.calculate_tf_averaged(window=window)
            self.p.update(self.dataset.tf_data_list)
            if self.current_view is not 'TFAV':
                self.current_view = 'TFAV'
                self.p.auto_x()
                self.p.auto_y()

            xlim = self.p.ax.get_xlim()
            ylim = self.p.ax.get_ylim()
            self.text_axes[2].value = xlim[0]
            self.text_axes[3].value = xlim[1]
            self.text_axes[4].value = ylim[0]
            self.text_axes[5].value = ylim[1]
            self.refresh_buttons()

    def xiw_fft(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            if self.current_view is 'FFT':
                s = self.p.get_selected_channels()
                n_sets, n_chans = np.shape(s)
                for ns in range(n_sets):
                    newdata = analysis.multiply_by_power_of_iw(
                        self.dataset.freq_data_list[ns],
                        power=1,
                        channel_list=s[ns, :])
                    self.dataset.freq_data_list[ns] = newdata
                self.p.update(self.dataset.freq_data_list)
                self.p.auto_y()
                self.iw_fft_power += 1
                print('Multiplied by (iw)**{}'.format(self.iw_fft_power))
            else:
                print('First press <Calc FFT>')

    def diw_fft(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            if self.current_view is 'FFT':
                s = self.p.get_selected_channels()
                n_sets, n_chans = np.shape(s)
                for ns in range(n_sets):
                    newdata = analysis.multiply_by_power_of_iw(
                        self.dataset.freq_data_list[ns],
                        power=-1,
                        channel_list=s[ns, :])
                    self.dataset.freq_data_list[ns] = newdata
                self.p.update(self.dataset.freq_data_list)
                self.p.auto_y()
                self.iw_fft_power -= 1
                print('Multiplied by (iw)**{}'.format(self.iw_fft_power))
            else:
                print('First press <Calc FFT>')

    def xiw_tf(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            if (self.current_view is 'TF') or (self.current_view is 'TFAV'):
                s = self.p.get_selected_channels()
                n_sets, n_chans = np.shape(s)
                for ns in range(n_sets):
                    newdata = analysis.multiply_by_power_of_iw(
                        self.dataset.tf_data_list[ns],
                        power=1,
                        channel_list=s[ns, :])
                    self.dataset.tf_data_list[ns] = newdata
                self.p.update(self.dataset.tf_data_list)
                self.p.auto_y()
                self.iw_tf_power += 1
                print('Multiplied selected channel by (iw)**{}'.format(
                    self.iw_tf_power))
            else:
                print('First press <Calc TF> or <Calc TF average>')

    def diw_tf(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            if (self.current_view is 'TF') or (self.current_view is 'TFAV'):
                s = self.p.get_selected_channels()
                n_sets, n_chans = np.shape(s)
                for ns in range(n_sets):
                    newdata = analysis.multiply_by_power_of_iw(
                        self.dataset.tf_data_list[ns],
                        power=-1,
                        channel_list=s[ns, :])
                    self.dataset.tf_data_list[ns] = newdata
                self.p.update(self.dataset.tf_data_list)
                self.p.auto_y()
                self.iw_tf_power -= 1
                print('Multiplied selected channel by (iw)**{}'.format(
                    self.iw_tf_power))
            else:
                print('First press <Calc TF> or <Calc TF average>')

    def match(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            if (self.current_view is 'TF') or (self.current_view is 'TFAV'):
                freq_range = self.p.ax.get_xlim()
                current_calibration_factors = self.dataset.tf_data_list.get_calibration_factors(
                )
                reference = current_calibration_factors[0][0]
                factors = analysis.best_match(self.dataset.tf_data_list,
                                              freq_range=freq_range,
                                              set_ref=0,
                                              ch_ref=0)
                factors = [reference * x for x in factors]
                self.dataset.tf_data_list.set_calibration_factors_all(factors)
                self.p.update(self.dataset.tf_data_list)
                print('scale factors:')
                print(factors)
                #self.p.auto_y()
            else:
                print(
                    'First press <View TF> or <Calc TF> or <Calc TF average>')

    def save_data(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            print('Saving dataset:')
            print(self.dataset)
            self.dataset.save_data()

    def save_fig(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            file.save_fig(self.p, figsize=(9, 5))

    def refresh_buttons(self):
        if len(self.dataset.time_data_list) is 0:
            self.buttons_view[0].button_style = ''
        else:
            self.buttons_view[0].button_style = 'info'

        if len(self.dataset.freq_data_list) is 0:
            self.buttons_view[1].button_style = ''
        else:
            self.buttons_view[1].button_style = 'info'

        if len(self.dataset.tf_data_list) is 0:
            self.buttons_view[2].button_style = ''
        else:
            self.buttons_view[2].button_style = 'info'
示例#10
0
    def create_param_widget(self, param, value):
        from ipywidgets import Layout, HBox
        children = (HBox(),)
        if isinstance(value, bool):
            from ipywidgets import Label, ToggleButton
            p = Label(value=param, layout=Layout(width='10%'))
            t = ToggleButton(description=str(value), value=value)

            def on_bool_change(change):
                t.description = str(change['new'])
                self.params[self._method][param] = change['new']
                self.replot_peaks()

            t.observe(on_bool_change, names='value')

            children = (p, t)

        elif isinstance(value, float):
            from ipywidgets import FloatSlider, FloatText, BoundedFloatText, \
                Label
            from traitlets import link
            p = Label(value=param, layout=Layout(flex='0 1 auto', width='10%'))
            b = BoundedFloatText(value=0, min=1e-10,
                                 layout=Layout(flex='0 1 auto', width='10%'),
                                 font_weight='bold')
            a = FloatText(value=2 * value,
                          layout=Layout(flex='0 1 auto', width='10%'))
            f = FloatSlider(value=value, min=b.value, max=a.value,
                            step=np.abs(a.value - b.value) * 0.01,
                            layout=Layout(flex='1 1 auto', width='60%'))
            l = FloatText(value=f.value,
                          layout=Layout(flex='0 1 auto', width='10%'),
                          disabled=True)
            link((f, 'value'), (l, 'value'))

            def on_min_change(change):
                if f.max > change['new']:
                    f.min = change['new']
                    f.step = np.abs(f.max - f.min) * 0.01

            def on_max_change(change):
                if f.min < change['new']:
                    f.max = change['new']
                    f.step = np.abs(f.max - f.min) * 0.01

            def on_param_change(change):
                self.params[self._method][param] = change['new']
                self.replot_peaks()

            b.observe(on_min_change, names='value')
            f.observe(on_param_change, names='value')
            a.observe(on_max_change, names='value')
            children = (p, l, b, f, a)

        elif isinstance(value, int):
            from ipywidgets import IntSlider, IntText, BoundedIntText, \
                Label
            from traitlets import link
            p = Label(value=param, layout=Layout(flex='0 1 auto', width='10%'))
            b = BoundedIntText(value=0, min=1e-10,
                               layout=Layout(flex='0 1 auto', width='10%'),
                               font_weight='bold')
            a = IntText(value=2 * value,
                        layout=Layout(flex='0 1 auto', width='10%'))
            f = IntSlider(value=value, min=b.value, max=a.value,
                          step=1,
                          layout=Layout(flex='1 1 auto', width='60%'))
            l = IntText(value=f.value,
                        layout=Layout(flex='0 1 auto', width='10%'),
                        disabled=True)
            link((f, 'value'), (l, 'value'))

            def on_min_change(change):
                if f.max > change['new']:
                    f.min = change['new']
                    f.step = 1

            def on_max_change(change):
                if f.min < change['new']:
                    f.max = change['new']
                    f.step = 1

            def on_param_change(change):
                self.params[self._method][param] = change['new']
                self.replot_peaks()

            b.observe(on_min_change, names='value')
            f.observe(on_param_change, names='value')
            a.observe(on_max_change, names='value')
            children = (p, l, b, f, a)
        container = HBox(children)
        return container
示例#11
0
class ScholarUpdate:
    """Widget for curating database"""

    def __init__(self, querier, worklist, force=False, debug=False, index=0, rules=None):
        reload()
        self.rules = rules or config.BIBTEX_TO_INFO
        self.worklist = worklist
        self.force = force
        self.querier = querier
        self.next_page_widget = Button(description="Next Work", icon="fa-arrow-right")
        self.reload_widget = Button(description="Reload", icon="fa-refresh")
        self.previous_page_widget = Button(description="Previous Work", icon="fa-arrow-left")
        self.debug_widget = ToggleButton(value=debug, description="Debug")
        self.textarea_widget = ToggleButton(value=False, description="TextArea")
        self.page_number_widget = Label(value="")
        self.output_widget = Output()
        self.next_page_widget.on_click(self.next_page)
        self.reload_widget.on_click(self.reload)
        self.previous_page_widget.on_click(self.previous_page)
        self.textarea_widget.observe(self.show)
        self.runner_widget = RunWidget() if config.RUN_WIDGET else ReplaceCellWidget()
        self.view = VBox([
            HBox([
                self.previous_page_widget,
                self.reload_widget,
                self.next_page_widget,
                self.debug_widget,
                self.textarea_widget,
                self.page_number_widget
            ]),
            self.output_widget,
            self.runner_widget.view,
        ])
        self.index = index
        self.varname = ""
        self.work = None
        self.articles = []
        self.reload(show=False)


    def next_page(self, b):
        """Go to next page"""
        self.index = min(len(self.worklist) - 1, self.index + 1)
        self.reload(b)

    def previous_page(self, b):
        """Go to previous page"""
        self.query = max(0, self.index - 1)
        self.reload(b)

    def set_index(self):
        """Set page index"""
        self.page_number_widget.value = str(self.index)
        self.next_page_widget.disabled = self.index == len(self.worklist) - 1
        self.previous_page_widget.disabled = self.index == 0

    def show(self, b=None):
        """Show comparison"""
        self.output_widget.clear_output()
        with self.output_widget:
            if not self.articles:
                print(self.varname, "<unknown>")
                return
            try:
                print(self.varname, getattr(self.work, self.rules.get(
                    "<scholar_ok>", "_some_invalid_attr_for_scholar_ok"
                ), False))
                var, work, articles = self.varname, self.work, self.articles
                meta = extract_info(articles[0])
                table = "<table>{}</table>"
                rows = ["<tr><th></th><th>{}</th><th>{}</th></tr>".format(var, "Scholar")]
                changes = set_by_info(work, meta, rules=self.rules)
                set_text = changes_dict_to_set_attribute(var, changes["set"])
                for key, value in changes["show"].items():
                    if value is not None:
                        meta_value, work_value = value
                        rows.append("<tr><td>{}</td><td>{}</td><td>{}</td></tr>".format(
                            key, work_value, meta_value
                        ))
                textarea = ""
                if self.textarea_widget.value:
                    textarea = "<textarea rows='{}' style='width: 100%'>{}</textarea>".format(len(rows), set_text)
                else:
                    self.runner_widget.set_code(set_text)
                display(HTML(table.format("".join(rows))+"<br>"+textarea))
            except:
                traceback.print_exc(file=sys.stdout)
                print(self.varname, "<error>")

    def reload(self, b=None, show=True):
        """Reload"""
        self.output_widget.clear_output()
        with self.output_widget:
            if self.debug_widget.value:
                ScholarConf.LOG_LEVEL = 3
            else:
                ScholarConf.LOG_LEVEL = 2
            reload()
            self.querier.tasks.clear()

            if self.index >= len(self.worklist):
                self.set_index()
                return
            self.varname = self.worklist[self.index]
            self.work = work_by_varname(self.varname)
            print(self.varname, oget(self.work, "scholar_ok", False, cvar=config.SCHOLAR_MAP))
            if oget(self.work, "scholar_ok", False, cvar=config.SCHOLAR_MAP) and not self.force:
                self.set_index()
                return
            from .selenium_scholar import SearchScholarQuery
            query = SearchScholarQuery()

            query.set_scope(False)
            query.set_words(config.query_str(self.work))
            query.set_num_page_results(1)
            self.querier.send_query(query)

            self.articles = self.querier.articles
        if show:
            self.show()

        self.set_index()

    def browser(self):
        """Present widget"""
        self.show()
        return self.view

    def _ipython_display_(self):
        """ Displays widget """
        self.show()
        display(self.view)
示例#12
0
    ui = HBox([vbox1, out])
    display(ui)

    def on_click(change):
        change['owner'].value = False

    def on_click_case(change):
        xlimit.min = df_num[change['new']].min()
        xlimit.max = df_num[change['new']].max()
        xlimit.step = (df_num[change['new']].max() -
                       df_num[change['new']].min()) / 100
        xlimit.value = [
            df_num[change['new']].min(), df_num[change['new']].max()
        ]

    save_but.observe(on_click, 'value')
    col.observe(on_click_case, 'value')


def drop_numerical_50percent_zero(df_num, df_Y):
    """Drop attribute with more than 50% zeros if and only if label_0 and label_1 has same percentage

    Parameters
    ----------
    df_num : DataFrame
    df_Y : DataFrame

    Returns
    -------
    DataFrame
        Return modified df_num
示例#13
0
    def setup_widgets(self, image_folder='images'):
        image_folder = self.base_path + '/' + image_folder
        self.image_list = os.listdir(image_folder)

        # Data Filter Setup
        download_robot_file = Button(
            description='Download Robot File',
            disabled=False,
            button_style='',
            tooltip='Click to download robot file of the current plate',
        )

        download_prep_file = Button(
            description='Download Reagent Prep',
            disabled=False,
            button_style='',
            tooltip='Click to download reagent preperation file for the current plate',
        )

        reset_plot = Button(
            description='Reset',
            disabled=False,
            tooltip='Reset the colors of the plot'
        )

        xy_check = Button(
            description='Show X-Y axes',
            disabled=False,
            button_style='',
            tooltip='Click to show X-Y axes'
        )

        show_hull_check = ToggleButton(
            value=True,
            description='Show Convex Hull',
            disabled=False,
            button_style='',
            tooltip='Toggle to show/hide convex hull',
            icon='check'
        )

        download_robot_file.on_click(self.download_robot_callback)
        download_prep_file.on_click(self.download_prep_callback)
        reset_plot.on_click(self.reset_plot_callback)
        xy_check.on_click(self.set_xy_camera)
        show_hull_check.observe(self.toggle_mesh, 'value')

        # Experiment data tab setup
        self.experiment_table = HTML()
        self.experiment_table.value = "Please click on a point to explore experiment details"

        self.image_data = {}
        for img_filename in os.listdir(image_folder):
            with open("{}/{}".format(image_folder, img_filename), "rb") as f:
                b = f.read()
                self.image_data[img_filename] = b

        self.image_widget = Image(
            value=self.image_data['not_found.png'],
            layout=Layout(height='400px', width='650px')
        )

        experiment_view_vbox = VBox(
            [HBox([self.experiment_table, self.image_widget])])

        self.thermal_plot = self.init_thermal_plot()
        plate_options = self.get_plate_options()
        self.selected_plate = plate_options[0]
        self.generate_thermal(self.selected_plate)
        self.plate_dropdown = Dropdown(options=plate_options,
                                       description='Plate:',
                                       )
        self.plate_dropdown.observe(self.change_plates, 'value')

        #tab = Tab()
        #tab.children = [experiment_view_vbox]
        #tab.set_title(0, 'Experiment Details')
        #tab.set_title(1, 'XRD data')

        plot_tabs = Tab([VBox([self.fig,
                               HBox([xy_check, show_hull_check, reset_plot])]),
                         VBox([self.thermal_plot,
                               HBox([self.plate_dropdown, download_robot_file, download_prep_file])]),
                         ])
        plot_tabs.set_title(0, 'Chemical Space')
        plot_tabs.set_title(1, 'Plate')

        self.full_widget = VBox([plot_tabs, experiment_view_vbox])
        self.full_widget.layout.align_items = 'center'
示例#14
0
def get():
    """Get the parcel's dataset for the given location or ids"""
    info = Label(
        "1. Select the region and the year to get parcel information.")

    values = config.read()
    # Set the max number of parcels that can be downloaded at once.
    plimit = int(values['set']['plimit'])

    def aois_options():
        values = config.read()
        options = {}
        if values['set']['data_source'] == '0':
            for desc in values['api']['options']['aois']:
                aoi = f"{values['api']['options']['aois'][desc]}"
                options[(desc, aoi)] = values['api']['options']['years'][aoi]
        elif values['set']['data_source'] == '1':
            for aoi in values['ds_conf']:
                desc = f"{values['ds_conf'][aoi]['desc']}"
                confgs = values['ds_conf'][aoi]['years']
                options[(f'{desc} ({aoi})', aoi)] = [y for y in confgs]
        return options

    def aois_years():
        values = config.read()
        years = {}
        if values['set']['data_source'] == '0':
            for desc in values['api']['options']['aois']:
                aoi = values['api']['options']['aois'][desc]
                years[aoi] = values['api']['options']['years'][aoi]
        elif values['set']['data_source'] == '1':
            for aoi in values['ds_conf']:
                desc = f"{values['ds_conf'][aoi]['desc']}"
                years[aoi] = [y for y in values['ds_conf'][aoi]['years']]
        return years

    try:
        aois = Dropdown(
            options=tuple(aois_options()),
            value=values['set']['ds_conf'],
            description='AOI:',
            disabled=False,
        )
    except:
        aois = Dropdown(
            options=tuple(aois_options()),
            description='AOI:',
            disabled=False,
        )

    year = Dropdown(
        options=next(iter(aois_options().values())),
        description='Year:',
        disabled=False,
    )
    button_refresh = Button(layout=Layout(width='35px'), icon='fa-refresh')

    @button_refresh.on_click
    def button_refresh_on_click(b):
        aois.options = tuple(aois_options())
        year.options = aois_years()[aois.value]

    def table_options_change(change):
        try:
            year.options = aois_years()[change.new]
        except:
            aois.options = tuple(aois_options())
            year.options = aois_years()[aois.value]

    aois.observe(table_options_change, 'value')

    info_method = Label("2. Select a method to get the data.")

    method = ToggleButtons(
        options=[('Parcel ID', 2), ('Coordinates', 1), ('Map marker', 3),
                 ('Polygon', 4)],
        value=None,
        description='',
        disabled=False,
        button_style='info',
        tooltips=[
            'Enter lat lon', 'Enter parcel ID', 'Select a point on a map',
            'Get parcels id in a polygon'
        ],
    )

    plon = Text(value='5.664',
                placeholder='Add lon',
                description='Lon:',
                disabled=False)

    plat = Text(value='52.694',
                placeholder='Add lat',
                description='Lat:',
                disabled=False)

    wbox_lat_lot = VBox(children=[plat, plon])

    info_pid = Label(
        "Multiple parcel id codes can be added (comma ',' separated, e.g.: 11111, 22222)."
    )

    pid = Textarea(value='34296',
                   placeholder='12345, 67890',
                   description='Parcel(s) ID:',
                   disabled=False)

    wbox_pids = VBox(children=[info_pid, pid])

    bt_get_ids = Button(description="Find parcels",
                        disabled=False,
                        button_style='info',
                        tooltip='Find parcels within the polygon.',
                        icon='')

    get_ids_box = HBox(
        [bt_get_ids,
         Label("Find the parcels that are in the polygon.")])

    ppoly_out = Output()

    progress = Output()

    def outlog(*text):
        with progress:
            print(*text)

    def outlog_poly(*text):
        with ppoly_out:
            print(*text)

    @bt_get_ids.on_click
    def bt_get_ids_on_click(b):
        with ppoly_out:
            try:
                get_requests = data_source()
                ppoly_out.clear_output()
                polygon = get_maps.polygon_map.feature_collection['features'][
                    -1]['geometry']['coordinates'][0]
                polygon_str = '-'.join(
                    ['_'.join(map(str, c)) for c in polygon])
                outlog_poly(f"Geting parcel ids within the polygon...")
                polyids = json.loads(
                    get_requests.ppoly(aois.value, year.value, polygon_str,
                                       False, True))
                outlog_poly(
                    f"'{len(polyids['ogc_fid'])}' parcels where found:")
                outlog_poly(polyids['ogc_fid'])
                file = config.get_value(['files', 'pids_poly'])
                with open(file, "w") as text_file:
                    text_file.write('\n'.join(map(str, polyids['ogc_fid'])))
            except Exception as err:
                outlog("No parcel ids found:", err)

    method_out = Output(layout=Layout(border='1px solid black'))

    def method_options(obj):
        with method_out:
            method_out.clear_output()
            if obj['new'] == 1:
                display(wbox_lat_lot)
            elif obj['new'] == 2:
                display(wbox_pids)
            elif obj['new'] == 3:
                display(
                    get_maps.base_map(
                        aois.value,
                        int(config.get_value(['set', 'data_source']))))
            elif obj['new'] == 4:
                display(
                    VBox([
                        get_maps.polygon(
                            aois.value,
                            int(config.get_value(['set', 'data_source']))),
                        get_ids_box, ppoly_out
                    ]))

    method.observe(method_options, 'value')

    info_type = Label("3. Select datasets to download.")

    table_options = HBox([aois, button_refresh, year])

    # ########### Time series options #########################################
    pts_bt = ToggleButton(
        value=False,
        description='Time series',
        disabled=False,
        button_style='success',  # success
        tooltip='Get parcel information',
        icon='toggle-off',
        layout=Layout(width='50%'))

    pts_bands = data_options.pts_bands()

    pts_tstype = SelectMultiple(
        options=data_options.pts_tstype(),
        value=['s2'],
        rows=3,
        description='TS type:',
        disabled=False,
    )

    pts_band = Dropdown(
        options=list(pts_bands['s2']),
        value='',
        description='Band:',
        disabled=False,
    )

    def pts_tstype_change(change):
        if len(pts_tstype.value) <= 1:
            pts_band.disabled = False
            try:
                pts_b = change.new[0]
                pts_band.options = pts_bands[pts_b]
            except:
                pass
        else:
            pts_band.value = ''
            pts_band.disabled = True

    pts_tstype.observe(pts_tstype_change, 'value')

    pts_options = VBox(children=[pts_tstype, pts_band])

    # ########### Chip images options #########################################
    pci_bt = ToggleButton(value=False,
                          description='Chip images',
                          disabled=False,
                          button_style='success',
                          tooltip='Get parcel information',
                          icon='toggle-off',
                          layout=Layout(width='50%'))

    pci_start_date = DatePicker(value=datetime.date(2019, 6, 1),
                                description='Start Date',
                                disabled=False)

    pci_end_date = DatePicker(value=datetime.date(2019, 6, 30),
                              description='End Date',
                              disabled=False)

    pci_plevel = RadioButtons(
        options=['LEVEL2A', 'LEVEL1C'],
        value='LEVEL2A',
        description='Proces. level:',  # Processing level
        disabled=False,
        layout=Layout(width='50%'))

    pci_chipsize = IntSlider(value=640,
                             min=100,
                             max=5120,
                             step=10,
                             description='Chip size:',
                             disabled=False,
                             continuous_update=False,
                             orientation='horizontal',
                             readout=True,
                             readout_format='d')

    pci_bands = data_options.pci_bands()

    pci_satellite = RadioButtons(options=list(pci_bands),
                                 value='Sentinel 2',
                                 disabled=True,
                                 layout=Layout(width='100px'))

    pci_band = SelectMultiple(options=list(pci_bands['Sentinel 2']),
                              value=['B04'],
                              rows=11,
                              description='Band:',
                              disabled=False)

    sats_plevel = HBox([pci_satellite, pci_plevel])

    def on_sat_change(change):
        sat = change.new
        pci_band.options = pci_bands[sat]

    pci_satellite.observe(on_sat_change, 'value')

    pci_options = VBox(children=[
        pci_start_date, pci_end_date, sats_plevel, pci_chipsize, pci_band
    ])

    # ########### General options #############################################
    pts_wbox = VBox(children=[])
    pci_wbox = VBox(children=[])

    def pts_observe(button):
        if button['new']:
            pts_bt.icon = 'toggle-on'
            pts_wbox.children = [pts_options]
        else:
            pts_bt.icon = 'toggle-off'
            pts_wbox.children = []

    def pci_observe(button):
        if button['new']:
            pci_bt.icon = 'toggle-on'
            pci_wbox.children = [pci_options]
        else:
            pci_bt.icon = 'toggle-off'
            pci_wbox.children = []

    pts_bt.observe(pts_observe, names='value')
    pci_bt.observe(pci_observe, names='value')

    pts = VBox(children=[pts_bt, pts_wbox], layout=Layout(width='40%'))
    pci = VBox(children=[pci_bt, pci_wbox], layout=Layout(width='40%'))

    data_types = HBox(children=[pts, pci])

    info_get = Label("4. Download the selected data.")

    bt_get = Button(description='Download',
                    disabled=False,
                    button_style='warning',
                    tooltip='Send the request',
                    icon='download')

    path_temp = config.get_value(['paths', 'temp'])
    path_data = config.get_value(['paths', 'data'])

    info_paths = HTML("".join([
        "<style>div.c {line-height: 1.1;}</style>",
        "<div class='c';>By default data will be stored in the temp folder ",
        f"({path_temp}), you will be asked to empty the temp folder each time ",
        "you start the notebook.<br>In your personal data folder ",
        f"({path_data}) you can permanently store the data.</div>"
    ]))

    paths = RadioButtons(options=[
        (f"Temporary folder: '{path_temp}'.", path_temp),
        (f"Personal data folder: '{path_data}'.", path_data)
    ],
                         layout={'width': 'max-content'},
                         value=path_temp)

    paths_box = Box([Label(value="Select folder:"), paths])

    def file_len(fname):
        with open(fname) as f:
            for i, l in enumerate(f):
                pass
        return i + 1

    def get_data(parcel):
        values = config.read()
        get_requests = data_source()
        pid = parcel['ogc_fid'][0]
        source = int(config.get_value(['set', 'data_source']))
        if source == 0:
            datapath = f'{paths.value}{aois.value}{year.value}/parcel_{pid}/'
        elif source == 1:
            ds_conf = config.get_value(['set', 'ds_conf'])
            datapath = f'{paths.value}{ds_conf}/parcel_{pid}/'
        file_pinf = f"{datapath}{pid}_information"

        outlog(data_handler.export(parcel, 10, file_pinf))

        if pts_bt.value is True:
            outlog(f"Getting time series for parcel: '{pid}',",
                   f"({pts_tstype.value} {pts_band.value}).")
            for pts in pts_tstype.value:
                ts = json.loads(
                    get_requests.pts(aois.value, year.value, pid, pts,
                                     pts_band.value))
                band = ''
                if pts_band.value != '':
                    band = f"_{pts_band.value}"
                file_ts = f"{datapath}{pid}_time_series_{pts}{band}"
                outlog(data_handler.export(ts, 11, file_ts))
        if pci_bt.value is True:
            files_pci = f"{datapath}{pid}_chip_images/"
            outlog(f"Getting '{pci_band.value}' chip images for parcel: {pid}")
            with progress:
                get_requests.rcbl(parcel, pci_start_date.value,
                                  pci_end_date.value, pci_band.value,
                                  pci_satellite.value, pci_chipsize.value,
                                  files_pci)
            filet = f'{datapath}/{pid}_chip_images/{pid}_images_list.{pci_band.value[0]}.csv'
            if file_len(filet) > 1:
                outlog(
                    f"Completed, all GeoTIFFs for bands '{pci_band.value}' are ",
                    f"downloaded in the folder: '{datapath}/{pid}_chip_images'"
                )
            else:
                outlog(
                    "No files where downloaded, please check your configurations"
                )

    def get_from_location(lon, lat):
        get_requests = data_source()
        outlog(f"Finding parcel information for coordinates: {lon}, {lat}")
        parcel = json.loads(
            get_requests.ploc(aois.value, year.value, lon, lat, True))
        pid = parcel['ogc_fid'][0]
        outlog(f"The parcel '{pid}' was found at this location.")
        try:
            get_data(parcel)
        except Exception as err:
            print(err)

    def get_from_id(pids):
        get_requests = data_source()
        outlog(f"Getting parcels information for: '{pids}'")
        for pid in pids:
            try:
                parcel = json.loads(
                    get_requests.pid(aois.value, year.value, pid, True))
                get_data(parcel)
            except Exception as err:
                print(err)

    @bt_get.on_click
    def bt_get_on_click(b):
        progress.clear_output()
        if method.value == 1:
            try:
                with progress:
                    get_requests = data_source()
                    lon, lat = plon.value, plat.value
                    get_from_location(lon, lat)
            except Exception as err:
                outlog(
                    f"Could not get parcel information for location '{lon}', '{lat}': {err}"
                )

        elif method.value == 2:
            try:
                with progress:
                    pids = pid.value.replace(" ", "").split(",")
                    get_from_id(pids)
            except Exception as err:
                outlog(f"Could not get parcel information: {err}")

        elif method.value == 3:
            try:
                marker = get_maps.base_map.map_marker
                lon = str(round(marker.location[1], 2))
                lat = str(round(marker.location[0], 2))
                get_from_location(lon, lat)
            except Exception as err:
                outlog(f"Could not get parcel information: {err}")
        elif method.value == 4:
            try:
                file = config.get_value(['files', 'pids_poly'])
                with open(file, "r") as text_file:
                    pids = text_file.read().split('\n')
                outlog("Geting data form the parcels:")
                outlog(pids)
                if len(pids) <= plimit:
                    get_from_id(pids)
                else:
                    outlog(
                        "You exceeded the maximum amount of selected parcels ",
                        f"({plimit}) to get data. Please select smaller area.")
            except Exception as err:
                outlog("No pids file found.", err)
        else:
            outlog(f"Please select method to get parcel information.")

    return VBox([
        info, table_options, info_method, method, method_out, info_type,
        data_types, info_get, info_paths, paths_box, bt_get, progress
    ])
class InteractiveView():
    def __init__(self):

        self.dataset = datastructure.DataSet()

        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out = Output()
        self.out_top = Output()

        # Initialise
        self.current_view = 'Time'
        self.N_frames = 1
        self.overlap = 0.5

        # BUTTONS
        items_load = ['Load Data', 'Reset (deletes loaded data)']
        items_view = ['View Time', 'View FFT', 'View TF']
        items_axes = ['xmin', 'xmax', 'ymin', 'ymax']
        items_save = ['Save Dataset', 'Save Figure']
        items_legend = ['Left', 'on/off', 'Right']

        self.buttons_load = [
            Button(description=i, layout=Layout(width='50%'))
            for i in items_load
        ]
        self.buttons_load[0].button_style = 'primary'
        self.buttons_load[0].style.font_weight = 'bold'
        self.buttons_load[1].button_style = 'warning'
        self.buttons_load[1].style.font_weight = 'bold'

        self.buttons_view = [
            Button(description=i, layout=Layout(width='99%'))
            for i in items_view
        ]
        self.buttons_view[0].button_style = 'info'
        self.buttons_view[1].button_style = 'info'
        self.buttons_view[2].button_style = 'info'

        self.buttons_match = Button(description='Match Amplitudes',
                                    layout=Layout(width='99%'))
        self.buttons_match.button_style = 'info'

        self.buttons_save = [
            Button(description=i, layout=Layout(width='50%'))
            for i in items_save
        ]
        self.buttons_save[0].button_style = 'success'
        self.buttons_save[0].style.font_weight = 'bold'
        self.buttons_save[1].button_style = 'success'
        self.buttons_save[1].style.font_weight = 'bold'

        self.button_X = Button(description='Auto X',
                               layout=Layout(width='10%'))
        self.button_Y = Button(description='Auto Y',
                               layout=Layout(width='10%'))
        self.button_X.button_style = 'success'
        self.button_Y.button_style = 'success'

        self.buttons_legend = [
            Button(description=i, layout=Layout(width='16%'))
            for i in items_legend
        ]
        self.buttons_legend_toggle = ToggleButton(description='Click-and-drag',
                                                  layout=Layout(
                                                      width='16%',
                                                      alignitems='start'))

        # TEXT/LABELS/DROPDOWNS
        self.item_axis_label = Label(value="Adjust axes manually:",
                                     layout=Layout(width='16%'))
        self.text_axes = [
            FloatText(value=0, description=i, layout=Layout(width='16%'))
            for i in items_axes
        ]
        self.text_axes = [self.button_X] + [self.button_Y] + [
            self.item_axis_label
        ] + self.text_axes
        self.item_legend_label = Label(value="Legend position:",
                                       layout=Layout(width='16%'))
        self.item_blank_label = Label(value="", layout=Layout(width='20%'))

        group1 = VBox([self.buttons_view[0]], layout=Layout(width='33%'))
        group2 = VBox([self.buttons_view[1]], layout=Layout(width='33%'))
        group3 = VBox([self.buttons_view[2], self.buttons_match],
                      layout=Layout(width='33%'))

        # ASSEMBLE
        display(HBox(self.buttons_load))
        self.p = plotting.PlotData()
        display(HBox(self.text_axes))
        display(
            HBox([self.item_blank_label, self.item_legend_label] +
                 self.buttons_legend + [self.buttons_legend_toggle]))
        display(HBox([group1, group2, group3]))
        display(HBox(self.buttons_save))

        # Make interactive
        self.text_axes[3].observe(self.xmin, names='value')
        self.text_axes[4].observe(self.xmax, names='value')
        self.text_axes[5].observe(self.ymin, names='value')
        self.text_axes[6].observe(self.ymax, names='value')

        self.button_X.on_click(self.auto_x)
        self.button_Y.on_click(self.auto_y)

        self.buttons_legend[0].on_click(self.legend_left)
        self.buttons_legend[1].on_click(self.legend_onoff)
        self.buttons_legend[2].on_click(self.legend_right)
        self.buttons_legend_toggle.observe(self.legend_toggle)

        self.buttons_load[0].on_click(self.load_data)
        self.buttons_load[1].on_click(self.undo)

        self.buttons_view[0].on_click(self.time)
        self.buttons_view[1].on_click(self.fft)
        self.buttons_view[2].on_click(self.tf)

        self.buttons_match.on_click(self.match)

        self.buttons_save[0].on_click(self.save_data)
        self.buttons_save[1].on_click(self.save_fig)

        self.refresh_buttons()

        # Put output text at bottom
        display(self.out)

    def xmin(self, v):
        xmin = self.text_axes[3].value
        xlim = self.p.ax.get_xlim()
        self.p.ax.set_xlim([xmin, xlim[1]])

    def xmax(self, v):
        xmax = self.text_axes[4].value
        xlim = self.p.ax.get_xlim()
        self.p.ax.set_xlim([xlim[0], xmax])

    def ymin(self, v):
        ymin = self.text_axes[5].value
        ylim = self.p.ax.get_ylim()
        self.p.ax.set_ylim([ymin, ylim[1]])

    def ymax(self, v):
        ymax = self.text_axes[6].value
        ylim = self.p.ax.get_ylim()
        self.p.ax.set_ylim([ylim[0], ymax])

    def auto_x(self, b):
        self.p.auto_x()

    def auto_y(self, b):
        self.p.auto_y()

    def legend_left(self, b):
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            self.legend_loc = 'lower left'
            self.p.update_legend(self.legend_loc)

    def legend_right(self, b):
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            self.legend_loc = 'lower right'
            self.p.update_legend(self.legend_loc)

    def legend_onoff(self, b):
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            visibility = self.p.ax.get_legend().get_visible()
            self.p.ax.get_legend().set_visible(not visibility)

    def legend_toggle(self, b):
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out_top:
            self.p.ax.get_legend().set_visible(True)
            self.p.legend.set_draggable(self.buttons_legend_toggle.value)

    def load_data(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        self.out_top.clear_output(wait=False)
        with self.out:
            d = file.load_data()
            if d is not None:
                self.dataset.add_to_dataset(d.time_data_list)
                self.dataset.add_to_dataset(d.freq_data_list)
                self.dataset.add_to_dataset(d.tf_data_list)
                self.dataset.add_to_dataset(d.cross_spec_data_list)
                self.dataset.add_to_dataset(d.sono_data_list)
            else:
                print('No data loaded')

            if len(self.dataset.time_data_list) is not 0:
                self.p.update(self.dataset.time_data_list,
                              sets='all',
                              channels='all')
            elif len(self.dataset.freq_data_list) is not 0:
                self.p.update(self.dataset.freq_data_list,
                              sets='all',
                              channels='all')
            elif len(self.dataset.tf_data_list) is not 0:
                self.p.update(self.dataset.tf_data_list,
                              sets='all',
                              channels='all')
            else:
                print('No data to view')

            self.refresh_buttons()

            self.p.auto_x()
            self.p.auto_y()

            xlim = self.p.ax.get_xlim()
            ylim = self.p.ax.get_ylim()
            self.text_axes[3].value = xlim[0]
            self.text_axes[4].value = xlim[1]
            self.text_axes[5].value = ylim[0]
            self.text_axes[6].value = ylim[1]

    def undo(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.dataset = datastructure.DataSet()
        self.out.clear_output(wait=False)
        with self.out:
            N = len(self.dataset.time_data_list)
            self.p.update(self.dataset.time_data_list,
                          sets=[N - 1],
                          channels='all')

    def time(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        with self.out:
            N = len(self.dataset.time_data_list)
            if N is not 0:
                self.p.update(self.dataset.time_data_list)
                if self.current_view is not 'Time':
                    self.current_view = 'Time'
                    self.p.auto_x()
                    self.p.auto_y()

                xlim = self.p.ax.get_xlim()
                ylim = self.p.ax.get_ylim()
                self.text_axes[3].value = xlim[0]
                self.text_axes[4].value = xlim[1]
                self.text_axes[5].value = ylim[0]
                self.text_axes[6].value = ylim[1]
            else:
                print('no time data to display')

    def fft(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        with self.out:
            N = len(self.dataset.freq_data_list)
            if N is not 0:
                self.p.update(self.dataset.freq_data_list)
                if self.current_view is not 'FFT':
                    self.current_view = 'FFT'
                    self.p.auto_x()
                    self.p.auto_y()

                xlim = self.p.ax.get_xlim()
                ylim = self.p.ax.get_ylim()
                self.text_axes[3].value = xlim[0]
                self.text_axes[4].value = xlim[1]
                self.text_axes[5].value = ylim[0]
                self.text_axes[6].value = ylim[1]
            else:
                print('no FFT data to display')

    def tf(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        with self.out:
            N = len(self.dataset.tf_data_list)
            if N is not 0:
                self.p.update(self.dataset.tf_data_list)
                if self.current_view is not 'TF':
                    self.current_view = 'TF'
                    self.p.auto_x()
                    self.p.auto_y()
                xlim = self.p.ax.get_xlim()
                ylim = self.p.ax.get_ylim()
                self.text_axes[3].value = xlim[0]
                self.text_axes[4].value = xlim[1]
                self.text_axes[5].value = ylim[0]
                self.text_axes[6].value = ylim[1]
            else:
                print('no TF data to display')

    def match(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        with self.out:
            if self.current_view is 'TF':
                freq_range = self.p.ax.get_xlim()
                current_calibration_factors = self.dataset.tf_data_list.get_calibration_factors(
                )
                reference = current_calibration_factors[0][0]
                factors = analysis.best_match(self.dataset.tf_data_list,
                                              freq_range=freq_range,
                                              set_ref=0,
                                              ch_ref=0)
                factors = [reference * x for x in factors]
                self.dataset.tf_data_list.set_calibration_factors_all(factors)
                self.p.update(self.dataset.tf_data_list)
                print('scale factors:')
                print(factors)
                #self.p.auto_y()
            else:
                print('First press <View TF>')

    def save_data(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        with self.out:
            print('Saving dataset:')
            print(self.dataset)
            self.dataset.save_data()

    def save_fig(self, b):
        # the 'out' construction is to refresh the text output at each update
        # to stop text building up in the widget display
        self.out.clear_output(wait=False)
        with self.out:
            file.save_fig(self.p, figsize=(9, 5))

    def refresh_buttons(self):
        if len(self.dataset.time_data_list) is 0:
            self.buttons_view[0].button_style = ''
        else:
            self.buttons_view[0].button_style = 'info'

        if len(self.dataset.freq_data_list) is 0:
            self.buttons_view[1].button_style = ''
        else:
            self.buttons_view[1].button_style = 'info'

        if len(self.dataset.tf_data_list) is 0:
            self.buttons_view[2].button_style = ''
        else:
            self.buttons_view[2].button_style = 'info'
示例#16
0
def interactive_numerical_plot(df_num, df_Y):
    """Plot Interactive KDE graph. Allow user to choose variable, set xlim and save figure. df_Y only allow binary class

    Parameters
    ----------
    df_num : DataFrame
    df_Y : Series

    Returns
    -------
    None

    """
    from ipywidgets import HBox, Checkbox, FloatRangeSlider, VBox, ToggleButton, interactive_output, Dropdown
    from IPython.display import display

    def plot_num_and_save(xlimit, save_but, col, clip_box, clip_limit):
        nonlocal df_num, df_Y
        plt.close('all')

        if clip_box:
            clip_df_num = df_num.copy()
            clip_df_num.loc[clip_df_num[col] > clip_limit[1], col] = np.nan
            clip_df_num.loc[clip_df_num[col] < clip_limit[0], col] = np.nan
        else:
            clip_df_num = df_num


#         for i,col in zip(range(clip_df_num[col].shape[1]),clip_df_num[col]):
        fig, ax = plt.subplots(1, 1, figsize=(10, 5))
        sns.kdeplot(clip_df_num[col][df_Y == 0],
                    label='label0').set_title(clip_df_num[col].name)
        sns.kdeplot(clip_df_num[col][df_Y == 1], label='label1')
        ax.set_xlim(xlimit[0], xlimit[1])
        plt.show()

        if save_but:
            fig.savefig('./plots/{}.png'.format(clip_df_num[col].name),
                        bbox_inches='tight')

    xlimit = FloatRangeSlider(
        value=[df_num.iloc[:, 1].min(), df_num.iloc[:, 1].max()],
        min=df_num.iloc[:, 1].min(),
        max=df_num.iloc[:, 1].max(),
        step=(df_num.iloc[:, 1].max() - df_num.iloc[:, 1].min()) / 100,
        continuous_update=False,
        description='X_limit')
    save_but = ToggleButton(description='Save Figure')
    col = Dropdown(options=df_num.columns.tolist())
    clip_box = Checkbox(value=False, description='Clip ?')
    clip_limit = FloatRangeSlider(
        value=[df_num.iloc[:, 1].min(), df_num.iloc[:, 1].max()],
        min=df_num.iloc[:, 1].min(),
        max=df_num.iloc[:, 1].max(),
        step=(df_num.iloc[:, 1].max() - df_num.iloc[:, 1].min()) / 100,
        continuous_update=False,
        description='X_limit')

    out = interactive_output(
        plot_num_and_save, {
            'xlimit': xlimit,
            'save_but': save_but,
            'col': col,
            'clip_box': clip_box,
            'clip_limit': clip_limit
        })
    #     save_but = Button(description='Save Fig')
    vbox1 = VBox([xlimit, save_but, col, clip_box, clip_limit])
    ui = HBox([vbox1, out])
    display(ui)

    def on_click(change):
        change['owner'].value = False

    def on_click_case(change):
        try:
            xlimit.min = df_num[change['new']].min()
            xlimit.max = df_num[change['new']].max()
            clip_limit.min = df_num[change['new']].min()
            clip_limit.max = df_num[change['new']].max()

        except:
            xlimit.max = df_num[change['new']].max()
            xlimit.min = df_num[change['new']].min()
            clip_limit.max = df_num[change['new']].max()
            clip_limit.min = df_num[change['new']].min()

        xlimit.step = (df_num[change['new']].max() -
                       df_num[change['new']].min()) / 100
        xlimit.value = [
            df_num[change['new']].min(), df_num[change['new']].max()
        ]
        clip_limit.step = (df_num[change['new']].max() -
                           df_num[change['new']].min()) / 100
        clip_limit.value = [
            df_num[change['new']].min(), df_num[change['new']].max()
        ]

    save_but.observe(on_click, 'value')
    col.observe(on_click_case, 'value')
示例#17
0
class ScholarUpdate:
    """Widget for curating database"""

    def __init__(self, querier, worklist, force=False, debug=False, index=0):
        reload()
        self.worklist = worklist
        self.force = force
        self.querier = querier
        self.next_page_widget = Button(description='Next Work', icon='fa-arrow-right')
        self.reload_widget = Button(description='Reload', icon='fa-refresh')
        self.previous_page_widget = Button(description='Previous Work', icon='fa-arrow-left')
        self.debug_widget = ToggleButton(value=debug, description="Debug")
        self.textarea_widget = ToggleButton(value=False, description="TextArea")
        self.page_number_widget = Label(value="")
        self.output_widget = Output()
        self.next_page_widget.on_click(self.next_page)
        self.reload_widget.on_click(self.reload)
        self.previous_page_widget.on_click(self.previous_page)
        self.textarea_widget.observe(self.show)
        self.view = VBox([
            HBox([
                self.previous_page_widget,
                self.reload_widget,
                self.next_page_widget,
                self.debug_widget,
                self.textarea_widget,
                self.page_number_widget
            ]),
            self.output_widget
        ])
        self.index = index
        self.varname = ""
        self.work = None
        self.articles = []
        self.reload(show=False)


    def next_page(self, b):
        """Go to next page"""
        self.index = min(len(self.worklist) - 1, self.index + 1)
        self.reload(b)

    def previous_page(self, b):
        """Go to previous page"""
        self.query = max(0, self.index - 1)
        self.reload(b)

    def set_index(self):
        """Set page index"""
        self.page_number_widget.value = str(self.index)
        self.next_page_widget.disabled = self.index == len(self.worklist) - 1
        self.previous_page_widget.disabled = self.index == 0

    def show(self, b=None):
        """Show comparison"""
        self.output_widget.clear_output()
        with self.output_widget:
            if not self.articles:
                print(self.varname, "<unknown>")
                return
            try:
                print(self.varname, getattr(self.work, "scholar_ok", False))
                var, work, articles = self.varname, self.work, self.articles
                meta = extract_info(articles[0])
                table = "<table>{}</table>"
                if not hasattr(work, 'entrytype'):
                    work.entrytype = work.place.type
                tool = {'y', 'x', 'i', 'display', 'pyref', "place", 'ID', 'year_index', 'file', 'excerpt', 'div'}
                if "place" in meta and not "place1" in meta:
                    meta["place1"] = meta["place"]
                work.place1 = "{} ({})".format(work.place.name, work.place.acronym)

                keys = {k for k in work.__dict__.keys() if not k.startswith("__")} - tool
                meta_keys = meta.keys() - tool
                order = {"name": 0, "authors": 1, "entrytype": 2, "place1": 3, "year": 4}
                rows = ["<tr><th></th><th>{}</th><th>{}</th></tr>".format(var, "Scholar")]
                sets = []
                shared = sorted(list(meta_keys & keys), key=lambda x: (order.get(x, len(order)), x))
                for key in shared:
                    value = str(meta[key])
                    add = False
                    if key in ('place1', 'year'): # Always show. Don't replace
                        add = True
                    elif getattr(work, key) != value: # Show changes
                        add = True
                        sets.append("set_attribute('{}', '{}', '{}')".format(var, key, value))
                    elif key in order: # Always show. Replace
                        add = True
                    if add:
                        rows.append("<tr><td>{}</td><td>{}</td><td>{}</td></tr>".format(key, getattr(work, key), value))
                for key in meta_keys - keys:
                    value = str(meta[key])
                    rows.append("<tr><td>{}</td><td>{}</td><td>{}</td></tr>".format(key, "", value))
                    sets.append("set_attribute('{}', '{}', '{}')".format(var, key, value))

                if not hasattr(work, "scholar_ok"):
                    sets.append("set_attribute('{}', 'scholar_ok', True)".format(var))
                sets.append("None")
                textarea = ""
                if self.textarea_widget.value:
                    textarea = "<textarea rows='{}' style='width: 100%'>{}</textarea>".format(len(rows), "\n".join(sets))
                else:
                    display_cell("# Temp\n"+ "\n".join(sets))
                display(HTML(table.format("".join(rows))+"<br>"+textarea))
            except:
                traceback.print_exc(file=sys.stdout)
                print(self.varname, '<error>')

    def reload(self, b=None, show=True):
        """Reload"""
        self.output_widget.clear_output()
        with self.output_widget:
            if self.debug_widget.value:
                ScholarConf.LOG_LEVEL = 3
            else:
                ScholarConf.LOG_LEVEL = 2
            reload()
            self.querier.tasks.clear()

            if self.index >= len(self.worklist):
                self.set_index()
                return
            self.varname = self.worklist[self.index]
            self.work = work_by_varname(self.varname)
            print(self.varname, getattr(self.work, "scholar_ok", False))
            if getattr(self.work, "scholar_ok", False) and not self.force:
                self.set_index()
                return
            from .selenium_scholar import SearchScholarQuery
            query = SearchScholarQuery()

            query.set_scope(False)
            query.set_words(self.work.name + " " + self.work.authors)
            query.set_num_page_results(1)
            self.querier.send_query(query)

            self.articles = self.querier.articles
        if show:
            self.show()

        self.set_index()

    def browser(self):
        """Present widget"""
        self.show()
        return self.view

    def _ipython_display_(self):
        """ Displays widget """
        self.show()
        display(self.view)
示例#18
0
class SliceViewer(VBox):
    def __init__(self,
                 volume=None,
                 default_directory=os.getcwd(),
                 title='',
                 enhancement_steps=1000,
                 **kwargs):
        def on_chosen_path_change(old_path, new_path):
            self.dataset = FolderDataset(new_path)
            # TODO: If the path doesn't contain images, display a warning

        # A widget for changing the image folder
        self.pathchooser = PathChooser(
            chosen_path_desc='Image folder:',
            default_directory=default_directory,
            on_chosen_path_change=on_chosen_path_change,
        )
        self.pathchooser.layout.margin = '0 0 10px 0'

        # The number of increments of the min/max slider
        self.enhancement_steps = enhancement_steps

        self.scales = {
            'x': LinearScale(),
            'y': LinearScale(),
        }

        # The currently displayed image will be in bytes at `self.image_plot.image.value`
        self.image_plot = BQImage(
            image=IPyImage(),
            scales=self.scales,
        )

        self.figure = Figure(
            marks=[self.image_plot],
            padding_x=0,
            padding_y=0,
            animation_duration=1000,
            fig_margin={
                'top': 0,
                'right': 0,
                'bottom': 0,
                'left': 0,
            },
            layout=Layout(
                grid_area='figure',
                margin='0',
                width='320px',
                height='320px',
            ),
        )

        # Custom toolbar
        toolbar_width = '100%'
        toolbar_margin = '0px 0 2px 0'
        self.pan_zoom = PanZoom(scales={
            'x': [self.scales['x']],
            'y': [self.scales['y']],
        }, )

        self.save_button = Button(
            description='Save Image',
            tooltip='Save Image',
            icon='save',
            layout=Layout(
                width=toolbar_width,
                # flex='1 1 auto',
                margin=toolbar_margin,
            ),
        )
        self.save_button.on_click(self.save_current_image)

        self.hide_button = Button(
            description='Hide Image',
            tooltip='Hide Image',
            icon='eye-slash',
            layout=Layout(
                width=toolbar_width,
                # flex='1 1 auto',
                margin=toolbar_margin,
            ))
        self.hide_button.on_click(self.hide_current_image)

        self.pan_zoom_toggle_button = ToggleButton(
            description='Pan / Zoom',
            tooltip='Pan/Zoom',
            icon='arrows',
            layout=Layout(
                width=toolbar_width,
                # flex='1 1 auto',
                margin=toolbar_margin,
            ),
        )
        self.pan_zoom_toggle_button.observe(self.on_pan_zoom_toggle,
                                            names='value')

        self.reset_pan_zoom_button = Button(
            description='Undo Zoom',
            tooltip='Reset pan/zoom',
            icon='refresh',
            layout=Layout(
                width=toolbar_width,
                # flex='1 1 auto',
                margin=toolbar_margin,
            ),
        )
        self.reset_pan_zoom_button.on_click(self.reset_pan_zoom)

        self.reset_enhancements_button = Button(
            description='Un-Enhance',
            tooltip='Reset enhancements',
            icon='ban',
            layout=Layout(
                width=toolbar_width,
                # flex='1 1 auto',
                margin=toolbar_margin,
            ),
        )
        self.reset_enhancements_button.on_click(self.reset_enhancements)

        self.mini_map = IPyImage(layout=Layout(
            grid_area='mini-map',
            margin='0',
        ))
        self.mini_map.width = 180
        self.mini_map.height = 180
        # PERFORMANCE CONCERN
        # Ideally instead of four observations, this would observe 'scales' on `self.pan_zoom`
        # However, it doesn't fire updates
        # Ref: https://github.com/bloomberg/bqplot/issues/800
        self.image_plot.scales['x'].observe(self.on_pan_zoom_change('x_min'),
                                            names='min')
        self.image_plot.scales['x'].observe(self.on_pan_zoom_change('x_max'),
                                            names='max')
        self.image_plot.scales['y'].observe(self.on_pan_zoom_change('y_min'),
                                            names='min')
        self.image_plot.scales['y'].observe(self.on_pan_zoom_change('y_max'),
                                            names='max')

        self.plane_toggle = ToggleButtons(
            options=['yz', 'xz', 'xy'],
            description='',
            disabled=False,
            button_style='',
            tooltips=[
                'Step in x direction', 'Step in y direction',
                'Step in z direction'
            ],
            layout=Layout(
                width='200px',
                # flex='1 1 auto',
                margin='7px 0 auto auto',
            ),
        )
        self.plane_toggle.style.button_width = 'auto'
        self.plane_toggle.observe(self.on_plane_change, names='value')

        self.toolbar = VBox(
            children=[
                self.save_button,
                self.hide_button,
                self.pan_zoom_toggle_button,
                self.reset_pan_zoom_button,
                self.reset_enhancements_button,
            ],
            layout=Layout(
                grid_area='toolbar',
                margin='0',
            ),
        )

        # Image enhancements
        self.min_max_slider = FloatRangeSlider(
            value=[0, 255],
            min=0,
            max=255,
            step=255 / self.enhancement_steps,
            description='Min/Max:',
            orientation='horizontal',
            readout=True,
            readout_format='.1f',
            continuous_update=True,
            layout=Layout(
                grid_area='min-max-slider',
                margin='10px 0 10px -10px',
                width='100%',
            ),
        )
        self.min_max_slider.observe(self.on_min_max_change, names='value')

        self.index_slider = IntSlider(
            value=0,
            min=0,
            max=1,
            step=1,
            description='Index:',
            orientation='horizontal',
            readout=True,
            readout_format='d',
            continuous_update=True,
            layout=Layout(
                grid_area='index-slider',
                margin='8px -20px 10px -36px',
                width='100%',
            ),
        )
        self.index_slider.observe(self.on_image_index_change, names='value')

        # Animation
        self.play = Play(
            value=self.index_slider.value,
            min=self.index_slider.min,
            max=self.index_slider.max,
            step=self.index_slider.step,
        )
        jslink((self.play, 'value'), (self.index_slider, 'value'))
        # Keep 'max' in sync as well
        self.index_slider.observe(self.on_index_slider_max_change, names='max')

        self.bottom_bar = HBox(
            children=[
                self.play,
                self.index_slider,
                self.plane_toggle,
            ],
            layout=Layout(
                grid_area='bottom-bar',
                margin=f'10px -20px 0 0',
                # overflow='hidden',
            ))

        # Layout
        self.gridbox = GridBox(children=[
            self.figure,
            self.toolbar,
            self.mini_map,
            self.min_max_slider,
            self.bottom_bar,
        ], )
        # Initially hidden without data
        self.gridbox.layout.display = 'none'

        self._dataset = None
        if volume is not None:
            self.dataset = VolumeDataset(volume)
            # Hide pathchooser when using a volume
            self.pathchooser.layout.display = 'none'

        # Call VBox super class __init__
        super().__init__(
            children=[
                self.pathchooser,
                self.gridbox,
            ],
            layout=Layout(width='auto'),
            **kwargs,
        )

    @property
    def dataset(self):
        """
        Get the dataset that the SliceViewer is displaying.
        """
        return self._dataset

    @dataset.setter
    def dataset(self, dataset):
        """
        Set the dataset that the SliceViewer is displaying.
        """
        if dataset:
            # TODO: set initial pan_zoom_scales
            # image_as_array = dataset[0]
            # width, height = image_as_array.shape
            # self.get_initial_pan_zoom_scales()
            self.index_slider.max = len(dataset) - 1
            # self.play.max = self.index_slider.max
            # Could be simpler with 0 margins, but for now is written generically
            self.plane_toggle.disabled = not isinstance(dataset, VolumeDataset)
            self.gridbox.layout = Layout(
                width='auto',
                # height='500px',
                grid_gap='0px 10px',
                # grid_template_columns='auto auto auto',
                grid_template_columns=f'{self.figure_size[0]}px 180px',
                # grid_template_rows=f'134px {self.figure_size[1] - 110}px 52px 52px',
                grid_template_rows=f'140px 180px 36px 60px',
                grid_template_areas='''
                    "figure toolbar"
                    "figure mini-map"
                    "min-max-slider min-max-slider"
                    "bottom-bar bottom-bar"
                ''',
            )
            self.gridbox.layout.display = None
        else:
            self.gridbox.layout.display = 'none'
        self._dataset = dataset
        # Crucially, this also calls self.redraw
        self.reset_enhancements()

    @property
    def figure_size(self):
        """
        Get the figure layout width and height as integers.
        """
        width = int(self.figure.layout.width[:-2])
        height = int(self.figure.layout.height[:-2])
        return [width, height]

    @figure_size.setter
    def figure_size(self, size):
        """
        Set the figure layout width and height with the provided list.
        """
        width, height = size
        self.figure.layout.width = f'{width}px'
        self.figure.layout.height = f'{height}px'

    @property
    def current_image(self):
        """
        Get the current image from backing `self.dataset` according to `self.index_slider`.
        It should be a normalized numpy array.
        """
        return self.dataset[self.index_slider.value]

    @property
    def value_range(self):
        """
        Get the value ranges of the unormalized dataset.
        """
        low = getattr(self.dataset, 'min', 0)
        high = getattr(self.dataset, 'max', 255)
        return [low, high]

    @output.capture()
    def get_current_image_name(self):
        """
        Return the name of the current image selected according to `self.index_slider`.
        """
        if not self.dataset:
            return ''
        else:
            index = self.index_slider.value
            image_names = getattr(self.dataset, 'image_names', [])
            if image_names:
                return image_names[index]
            else:
                return f'sliceviewer-image-{index}.jpg'

    @output.capture()
    def get_current_scales(self):
        """
        Get the current image_plot scales in a plain dictionary.
        """
        scales = self.image_plot.scales
        plain_scales = {
            'x': [scales['x'].min, scales['x'].max],
            'y': [scales['y'].min, scales['y'].max],
        }
        # Coerce None to 0
        plain_scales['x'] = [x if x else 0 for x in plain_scales['x']]
        plain_scales['y'] = [y if y else 0 for y in plain_scales['y']]
        return plain_scales

    @output.capture()
    def redraw(self, image_as_array=None):
        """
        Redraw main image and mini-map. Defaults to enhanced current image.
        """
        # Main image
        if image_as_array is None:
            image_as_array = self.enhance_image(self.current_image)
        image = PIL_to_bytes(numpy_to_PIL(image_as_array))
        self.image_plot.image = IPyImage(value=image)
        # Mini-map
        self.redraw_mini_map(image_as_array=image_as_array)

    @output.capture()
    def redraw_mini_map(self, image_as_array=None, scales=None):
        """
        Redraw the mini-map. Defaults to enhanced current image.
        """
        if image_as_array is None:
            image_as_array = self.enhance_image(self.current_image)
        if scales is None:
            scales = self.get_current_scales()
        mini_map = self.draw_mini_map(image_as_array, scales)
        self.mini_map.value = PIL_to_bytes(numpy_to_PIL(mini_map))

    @output.capture()
    def on_image_index_change(self, change):
        """
        Load and display the new image.
        """
        enhanced = self.enhance_image(self.current_image)
        self.redraw(image_as_array=enhanced)

    @output.capture()
    def on_index_slider_max_change(self, change):
        """
        Sync play.max with index_slider.max and reset index slider.
        """
        self.play.max = change.new

    @output.capture()
    def get_initial_pan_zoom_scales(self):
        """
        Calculate the necessary pan_zoom scales to fill-in the main viewport
        when the input image is not square.
        """
        raise NotImplementedError

    @output.capture()
    def on_pan_zoom_toggle(self, change):
        """
        Update the `self.figure` interaction.
        """
        if change.new:
            self.figure.interaction = self.pan_zoom
        else:
            self.figure.interaction = None

    @output.capture()
    def reset_pan_zoom(self, button):
        """
        Reset figure/plot scales.
        """
        self.image_plot.scales['x'].min = None
        self.image_plot.scales['x'].max = None
        self.image_plot.scales['y'].min = None
        self.image_plot.scales['y'].max = None
        self.redraw_mini_map()

    @output.capture()
    def draw_mini_map(self, image_as_array, scales):
        """
        Draw a mini version of image_as_array with a rectangle indicating pan/zoom location.
        """
        # Commented code is preparation for non-square image
        # canvas_as_array = draw_checkerboard_canvas(
        #     height=int(self.mini_map.height),
        #     width=int(self.mini_map.width),
        # )
        # offsets, image_as_array = get_offsets_and_resize_for_canvas(
        #     image_as_array,
        #     canvas_as_array,
        # )
        shape = image_as_array.shape
        # Convert grayscale to RGB
        mini_map = to_rgb(image_as_array)
        # Draw a red square indicating the zoom location
        xs = [int(x * shape[1]) for x in scales['x']]
        ys = [int((1.0 - y) * shape[0]) for y in scales['y']]

        # Make sure values are in range
        def clamp(values, low, high):
            temp = [v if v > low else low for v in values]
            return [v if v < high else high for v in temp]

        # This will give a border width of 2 pixels
        xs.extend([x + 1 for x in xs])
        ys.extend([y - 1 for y in ys])
        xs = clamp(xs, 0, shape[1] - 2)
        ys = clamp(ys, 0, shape[0] - 2)
        for x in xs + [x + 1 for x in xs]:
            for y in range(ys[1], ys[0] + 1):
                # Color these locations full-on red
                mini_map[y][x][0] = 1.0
        for y in ys + [y + 1 for y in ys]:
            for x in range(xs[0], xs[1] + 1):
                # Color these locations full-on red
                mini_map[y][x][0] = 1.0
        return mini_map
        # Commented code is preparation for non-square image
        # canvas_as_array = to_rgb(canvas_as_array)
        # canvas_as_array[offsets[0]:, offsets[1]:] = mini_map
        # return canvas_as_array

    @output.capture()
    def on_pan_zoom_change(self, change_type):
        """
        Return a function that produces new scales when the user pans or zooms.

        :param change_type: One of ['x_min', 'x_max', 'y_min', 'y_max']
        """
        def handle_case(change):
            if change.new == None:
                return
            scales = self.get_current_scales()
            cases = {
                'x_min': {
                    'x': [change.new, scales['x'][1]],
                    'y': scales['y'],
                },
                'x_max': {
                    'x': [scales['x'][0], change.new],
                    'y': scales['y'],
                },
                'y_min': {
                    'x': scales['x'],
                    'y': [change.new, scales['y'][1]],
                },
                'y_max': {
                    'x': scales['x'],
                    'y': [scales['y'][0], change.new],
                },
            }
            new_scales = cases[change_type]
            self.redraw_mini_map(scales=new_scales)

        return handle_case

    @output.capture()
    def reset_enhancements(self, button=None):
        """
        Reset all of the image enhancement sliders.
        """
        [low, high] = self.value_range
        self.min_max_slider.min = low
        self.min_max_slider.max = high
        self.min_max_slider.value = [low, high]
        self.min_max_slider.step = (high - low) / self.enhancement_steps
        self.redraw()

    @output.capture()
    def save_current_image(self, button):
        """
        Save the current image with any processing applied.
        """
        directory = getattr(self.dataset, 'directory', os.getcwd())
        processed_directory = os.path.join(directory, 'ipysliceviewer')
        if not os.path.exists(processed_directory):
            os.makedirs(processed_directory)
        filepath = os.path.join(processed_directory,
                                self.get_current_image_name())
        with open(filepath, 'wb') as f:
            f.write(self.image_plot.image.value)

    @output.capture()
    def hide_current_image(self, button):
        """
        Hide the current image and remember this as a setting.
        This is like a soft form of deleting the image.
        """
        # Need more thought on how this should be remembered across restarts for the current dataset
        # Rough idea: text file or similar containing SliceViewer settings, just need to figure out
        # a good naming scheme for datasets - possibly can take name from Experimenter or SliceViewer's own text box
        raise NotImplementedError

    @output.capture()
    def enhance_image(self, image_as_array):
        """
        Apply enhancement sliders to image_as_array and return as a numpy array
        """
        # These values are not normalized even though the image above is
        # (this allows the user to work with the input range)
        new_min, new_max = self.min_max_slider.value
        # So, we'll convert them before using them to scale the normalized image
        [low, high] = self.value_range

        def rescale(x, low, high):
            return (x - low) / (high - low)

        new_min = rescale(new_min, low, high)
        new_max = rescale(new_max, low, high)
        processed_image = rescale(to_rgb(image_as_array), new_min, new_max)
        processed_image = np.clip(processed_image, 0, 1)
        return processed_image

    @output.capture()
    def on_min_max_change(self, change):
        """
        Handle changes to the min/max slider.
        """
        self.redraw()

    @output.capture()
    def on_plane_change(self, change):
        """
        Called when the slice plane is toggled.
        """
        if hasattr(self.dataset, 'plane'):
            self.dataset.plane = change.new
            old_max = self.index_slider.max
            new_max = len(self.dataset) - 1
            self.index_slider.max = new_max
            self.index_slider.value = min(self.index_slider.value, new_max)
            # Guarantee the image updates even if index does not change
            self.redraw()
示例#19
0
class ImageSelector():
    def __init__(self, image_dict, max_width=None):
        self.max_width = max_width
        self.image_dict = image_dict
        self.default_image = list(image_dict.keys())[0]
        self.image = self.image_dict[self.default_image]
        # Image Selector
        self.image_selector = Dropdown(options=list(self.image_dict) + ['+ Add new image'])
        self.image_selector.observe(self.on_selector_change, 'value')
        self.selector_box = HBox(children=[self.image_selector], layout=Layout(justify_content='space-around'))
        # Image Display
        width, height = self.get_size(*self.image.size)
        self.image_display = Image(value=to_binary(self.image),
                                   format='png',
                                   width=width,
                                   height=height)
        self.display_box = HBox(children=[self.image_display], layout=Layout(justify_content='center'))
        self.widget = VBox(children=[self.selector_box, self.display_box],
                           layout=Layout(align_content='inherit'))

    def get_size(self, width, height):
        if self.max_width is not None:
            new_width = min(self.max_width, width)
            height = int((new_width/width) * height)
            return new_width, height
        return width, height

    def change_image(self, image):
        self.image = image
        self.image_display.width, self.image_display.height = self.get_size(*image.size)
        self.image_display.value = to_binary(image)

    def on_selector_change(self, change):
        if self.image_selector.value in self.image_dict:
            self.change_image(self.image_dict[self.image_selector.value])
            self.widget.children = [self.selector_box, self.display_box]
        else:
            self.upload_widget = FileUpload(accept='image/*', multiple=False)
            self.name_widget = Text(description='<b>Image Name</b>', style={'description_width': 'initial'})
            self.ok_widget = ToggleButton(
                            value=False,
                            description='Add',
                            disabled=False,
                            button_style='success',
                            tooltip='Description',
                            icon='check')

            self.add_widget = HBox(children=[self.upload_widget, self.name_widget, self.ok_widget],
                                   layout=Layout(justify_content='space-around'))

            self.widget.children = [self.selector_box, self.add_widget]
            self.upload_widget.observe(self.on_upload, 'value')
            self.ok_widget.observe(self.on_add, 'value')
    #

    def on_upload(self, change):
        image_binary = list(self.upload_widget.value.values())[0]['content']
        image = PImage.open(BytesIO(image_binary))
        self.change_image(image)
        self.widget.children = [self.selector_box, self.add_widget, self.display_box]

    def on_add(self, change):
        if self.upload_widget.value:
            image_binary = list(self.upload_widget.value.values())[0]['content']
            self.image_dict[self.name_widget.value] = PImage.open(BytesIO(image_binary))
            self.image_selector.options = list(self.image_dict) + ['+ Add new image']
            self.image_selector.value = self.name_widget.value
示例#20
0
    def setup_widgets(self, image_folder='data/images'):
        image_folder = self.base_path + '/' + image_folder
        self.image_list = os.listdir(image_folder)

        # Data Filter Setup
        reset_plot = Button(
            description='Reset',
            disabled=False,
            tooltip='Reset the colors of the plot'
        )

        xy_check = Button(
            description='Show X-Y axes',
            disabled=False,
            button_style='',
            tooltip='Click to show X-Y axes'
        )

        show_success_hull = ToggleButton(
            value=True,
            description='Show sucess hull',
            disabled=False,
            button_style='',
            tooltip='Toggle to show/hide success hull',
            icon='check'
        )

        unique_inchis = self.full_perovskite_data['_rxn_organic-inchikey'].unique(
        )

        self.select_amine = Dropdown(
            options=[row['Chemical Name'] for
                     i, row in self.inchis.iterrows()
                     if row['InChI Key (ID)'] in unique_inchis],
            description='Amine:',
            disabled=False,
        )

        reset_plot.on_click(self.reset_plot_callback)
        xy_check.on_click(self.set_xy_camera)
        show_success_hull.observe(self.toggle_success_mesh, 'value')
        self.select_amine.observe(self.select_amine_callback, 'value')

        # Experiment data tab setup
        self.experiment_table = HTML()
        self.experiment_table.value = "Please click on a point"
        "to explore experiment details"

        self.image_data = {}
        for img_filename in os.listdir(image_folder):
            with open("{}/{}".format(image_folder, img_filename), "rb") as f:
                b = f.read()
                self.image_data[img_filename] = b

        self.image_widget = Image(
            value=self.image_data['not_found.png'],
            layout=Layout(height='400px', width='650px')
        )

        experiment_view_vbox = VBox(
            [HBox([self.experiment_table, self.image_widget])])

        plot_tabs = Tab([VBox([self.fig,
                               HBox([self.select_amine]),
                               HBox([xy_check, show_success_hull,
                                     reset_plot])]),
                         ])
        plot_tabs.set_title(0, 'Chemical Space')

        self.full_widget = VBox([plot_tabs, experiment_view_vbox])
        self.full_widget.layout.align_items = 'center'
示例#21
0
def get():
    """Get the parcel's dataset for the given location or ids"""
    debug = False
    info = Label("1. Select the aoi to get parcel data.")

    values = config.read()
    ppoly_out = Output()
    progress = Output()

    def outlog(*text):
        with progress:
            print(*text)

    def outlog_poly(*text):
        with ppoly_out:
            print(*text)

    def aois_options():
        values = config.read()
        options = {}
        if values['set']['data_source'] == 'api':
            api_values = config.read('api_options.json')
            for aoi in api_values['aois']:
                options[(aoi.upper(), aoi)] = api_values['aois'][aoi]['years']
        elif values['set']['data_source'] == 'direct':
            values = config.read('api_options.json')
            for aoi in values['dataset']:
                options[(f"{aoi.upper()} ({aoi})", aoi)] = [aoi.split('_')[-1]]
        return options

    def aois_years():
        values = config.read()
        years = {}
        if values['set']['data_source'] == 'api':
            api_values = config.read('api_options.json')
            for aoi in api_values['aois']:
                years[aoi] = api_values['aois'][aoi]['years']
        elif values['set']['data_source'] == 'direct':
            values = config.read()
            for aoi in values['dataset']:
                years[aoi] = [aoi.split('_')[-1]]
        return years

    try:
        aois = Dropdown(
            options=tuple(aois_options()),
            value=values['set']['dataset'],
            description='AOI:',
        )
    except Exception:
        aois = Dropdown(
            options=tuple(aois_options()),
            description='AOI:',
        )

    def years_disabled():
        values = config.read()
        if values['set']['data_source'] == 'direct':
            return True
        else:
            return False

    year = Dropdown(
        options=next(iter(aois_options().values())),
        description='Year:',
        disabled=years_disabled(),
    )
    button_refresh = Button(layout=Layout(width='35px'), icon='fa-refresh')

    @button_refresh.on_click
    def button_refresh_on_click(b):
        values = config.read()
        if values['set']['data_source'] == 'api':
            from cbm.datas import api
            available_options = json.loads(api.get_options())
            try:
                api_options = normpath(
                    join(config.path_conf, 'api_options.json'))
                os.makedirs(dirname(api_options), exist_ok=True)
                with open(api_options, "w") as f:
                    json.dump(available_options, f, indent=4)
                outlog(f"File saved at: {api_options}")
            except Exception as err:
                outlog(f"Could not create the file 'api_options.json': {err}")

            outlog(f"The API options are updated.")
        aois.options = tuple(aois_options())
        year.options = aois_years()[aois.value]
        year.disabled = years_disabled()

    def table_options_change(change):
        api_values = config.read('api_options.json')
        id_examples = api_values['aois'][change.new]['id_examples']
        try:
            id_examples_label.value = ', '.join(str(x) for x in id_examples)
            year.options = aois_years()[change.new]
            year.disabled = years_disabled()
            pid.value = str(id_examples[0])
        except Exception:
            id_examples_label.value = ', '.join(str(x) for x in id_examples)
            aois.options = tuple(aois_options())
            year.options = aois_years()[aois.value]
            year.disabled = years_disabled()
            pid.value = str(id_examples[0])

    aois.observe(table_options_change, 'value')

    info_method = Label("2. Select a method to download parcel data.")

    method = ToggleButtons(
        options=[('Parcel ID', 2), ('Coordinates', 1), ('Map marker', 3),
                 ('Polygon', 4)],
        value=None,
        description='',
        disabled=False,
        button_style='info',
        tooltips=[
            'Enter lon lat', 'Enter parcel ID', 'Select a point on a map',
            'Get parcels id in a polygon'
        ],
    )

    plon = Text(value='5.664', placeholder='Add lon', description='Lon:')
    plat = Text(value='52.694', placeholder='Add lat', description='Lat:')
    wbox_lat_lot = VBox(children=[plat, plon])

    api_values = config.read('api_options.json')
    id_examples = api_values['aois'][aois.value]['id_examples']

    id_examples_label = Label(', '.join(str(x) for x in id_examples))
    info_pid = HBox(
        [Label("Multiple parcel ids can be added, e.g.: "), id_examples_label])

    pid = Textarea(
        value=str(id_examples[0]),
        placeholder='12345, 67890',
        description='Parcel(s) ID:',
    )

    wbox_pids = VBox(children=[info_pid, pid])

    bt_get_ids = Button(description="Find parcels",
                        disabled=False,
                        button_style='info',
                        tooltip='Find parcels within the polygon.',
                        icon='')

    get_ids_box = HBox(
        [bt_get_ids,
         Label("Find the parcels that are in the polygon.")])

    @bt_get_ids.on_click
    def bt_get_ids_on_click(b):
        with ppoly_out:
            try:
                # get_requests = data_source()
                ppoly_out.clear_output()
                polygon = get_maps.polygon_map.feature_collection['features'][
                    -1]['geometry']['coordinates'][0]
                polygon_str = '-'.join(
                    ['_'.join(map(str, c)) for c in polygon])
                outlog_poly(f"Geting parcel ids within the polygon...")
                polyids = parcel_info.by_polygon(aois.value, year.value,
                                                 polygon_str, ptype.value,
                                                 False, True)
                outlog_poly(
                    f"'{len(polyids['ogc_fid'])}' parcels where found:")
                outlog_poly(polyids['ogc_fid'])
                file = normpath(
                    join(config.get_value(['paths', 'temp']),
                         'pids_from_polygon.txt'))
                with open(file, "w") as text_file:
                    text_file.write('\n'.join(map(str, polyids['ogc_fid'])))
            except Exception as err:
                outlog("No parcel ids found:", err)

    method_out = Output(layout=Layout(border='1px solid black'))

    def method_options(obj):
        with method_out:
            method_out.clear_output()
            if obj['new'] == 1:
                display(wbox_lat_lot)
            elif obj['new'] == 2:
                display(wbox_pids)
            elif obj['new'] == 3:
                display(
                    get_maps.base_map(aois.value,
                                      config.get_value(['set',
                                                        'data_source'])))
            elif obj['new'] == 4:
                display(
                    VBox([
                        get_maps.polygon(
                            aois.value,
                            config.get_value(['set', 'data_source'])),
                        get_ids_box, ppoly_out
                    ]))

    method.observe(method_options, 'value')

    info_type = Label("3. Select datasets to download.")

    ptype = Text(value=None,
                 placeholder='(Optional) Parcel Type',
                 description='pType:',
                 disabled=False)

    table_options = HBox([aois, button_refresh, ptype, year])

    # ########### Time series options #########################################
    pts_bt = ToggleButton(
        value=False,
        description='Time series',
        button_style='success',  # success
        tooltip='Get parcel information',
        icon='toggle-off',
        layout=Layout(width='50%'))

    pts_bands = data_options.pts_bands()

    pts_tstype = SelectMultiple(
        options=[("Sentinel-2 Level 2A", 's2'),
                 ("S1 Backscattering Coefficients", 'bs'),
                 ("S1 6-day Coherence (20m)", 'c6')],
        value=['s2'],
        rows=3,
        description='TS type:',
        disabled=False,
    )

    pts_band = Dropdown(
        options=list(pts_bands['s2']),
        value='',
        description='Band:',
        disabled=False,
    )

    def pts_tstype_change(change):
        if len(pts_tstype.value) <= 1:
            pts_band.disabled = False
            try:
                pts_b = change.new[0]
                pts_band.options = pts_bands[pts_b]
            except Exception:
                pass
        else:
            pts_band.value = ''
            pts_band.disabled = True

    pts_tstype.observe(pts_tstype_change, 'value')

    pts_options = VBox(children=[pts_tstype, pts_band])

    # ########### Chip images options #########################################
    pci_bt = ToggleButton(value=False,
                          description='Chip images',
                          disabled=False,
                          button_style='success',
                          tooltip='Get parcel information',
                          icon='toggle-off',
                          layout=Layout(width='50%'))

    pci_start_date = DatePicker(
        value=datetime.date(2020, 6, 1),
        description='Start Date',
    )

    pci_end_date = DatePicker(
        value=datetime.date(2020, 6, 30),
        description='End Date',
    )

    pci_plevel = RadioButtons(
        options=['LEVEL2A', 'LEVEL1C'],
        value='LEVEL2A',
        description='Proces. level:',  # Processing level
        disabled=False,
        layout=Layout(width='50%'))

    pci_chipsize = IntSlider(value=640,
                             min=100,
                             max=5120,
                             step=10,
                             description='Chip size:',
                             disabled=False,
                             continuous_update=False,
                             orientation='horizontal',
                             readout=True,
                             readout_format='d')

    pci_bands = data_options.pci_bands()

    pci_satellite = RadioButtons(options=list(pci_bands),
                                 value='Sentinel 2',
                                 disabled=True,
                                 layout=Layout(width='100px'))

    pci_band = SelectMultiple(options=list(pci_bands['Sentinel 2']),
                              value=['B04'],
                              rows=11,
                              description='Band:',
                              disabled=False)

    sats_plevel = HBox([pci_satellite, pci_plevel])

    def on_sat_change(change):
        sat = change.new
        pci_band.options = pci_bands[sat]

    pci_satellite.observe(on_sat_change, 'value')

    pci_options = VBox(children=[
        pci_start_date, pci_end_date, sats_plevel, pci_chipsize, pci_band
    ])

    # ########### General options #############################################
    pts_wbox = VBox(children=[])
    pci_wbox = VBox(children=[])

    def pts_observe(button):
        if button['new']:
            pts_bt.icon = 'toggle-on'
            pts_wbox.children = [pts_options]
        else:
            pts_bt.icon = 'toggle-off'
            pts_wbox.children = []

    def pci_observe(button):
        if button['new']:
            pci_bt.icon = 'toggle-on'
            pci_wbox.children = [pci_options]
        else:
            pci_bt.icon = 'toggle-off'
            pci_wbox.children = []

    pts_bt.observe(pts_observe, names='value')
    pci_bt.observe(pci_observe, names='value')

    pts = VBox(children=[pts_bt, pts_wbox], layout=Layout(width='40%'))
    pci = VBox(children=[pci_bt, pci_wbox], layout=Layout(width='40%'))

    data_types = HBox(children=[pts, pci])

    info_get = Label("4. Download the selected data.")

    bt_get = Button(description='Download',
                    button_style='warning',
                    tooltip='Send the request',
                    icon='download')

    path_temp = config.get_value(['paths', 'temp'])
    path_data = config.get_value(['paths', 'data'])

    info_paths = HTML("".join([
        "<style>div.c {line-height: 1.1;}</style>",
        "<div class='c';>By default data will be stored in the temp folder ",
        f"({path_temp}), you will be asked to empty the temp folder each time ",
        "you start the notebook.<br>In your personal data folder ",
        f"({path_data}) you can permanently store the data.</div>"
    ]))

    paths = RadioButtons(options=[
        (f"Temporary folder: '{path_temp}'.", path_temp),
        (f"Personal data folder: '{path_data}'.", path_data)
    ],
                         layout={'width': 'max-content'},
                         value=path_temp)

    paths_box = Box([Label(value="Select folder:"), paths])

    def file_len(fname):
        with open(fname) as f:
            for i, l in enumerate(f):
                pass
        return i + 1

    def get_data(parcel):
        get_requests = data_source()
        pid = str(parcel['pid'][0])
        source = config.get_value(['set', 'data_source'])
        if source == 'api':
            datapath = normpath(join(paths.value, aois.value, year.value, pid))
        elif source == 'direct':
            dataset = config.get_value(['set', 'dataset'])
            datapath = normpath(join(paths.value, dataset, pid))
        file_pinf = normpath(join(datapath, 'info.json'))
        os.makedirs(dirname(file_pinf), exist_ok=True)
        with open(file_pinf, "w") as f:
            json.dump(parcel, f)
        outlog(f"File saved at: {file_pinf}")

        if pts_bt.value is True:
            outlog(f"Getting time series for parcel: '{pid}',",
                   f"({pts_tstype.value} {pts_band.value}).")
            for pts in pts_tstype.value:
                ts = time_series.by_pid(aois.value, year.value, pid, pts,
                                        ptype.value, pts_band.value)
                band = ''
                if pts_band.value != '':
                    band = f"_{pts_band.value}"
                file_ts = normpath(
                    join(datapath, f'time_series_{pts}{band}.csv'))
                if isinstance(ts, pd.DataFrame):
                    ts.to_csv(file_ts, index=True, header=True)
                elif isinstance(ts, dict):
                    os.makedirs(os.path.dirname(file_ts), exist_ok=True)
                    df = pd.DataFrame.from_dict(ts, orient='columns')
                    df.to_csv(file_ts, index=True, header=True)
            outlog("TS Files are saved.")
        if pci_bt.value is True:
            files_pci = normpath(join(datapath, 'chip_images'))
            outlog(f"Getting '{pci_band.value}' chip images for parcel: {pid}")
            with progress:
                get_requests.rcbl(parcel, pci_start_date.value,
                                  pci_end_date.value, pci_band.value,
                                  pci_chipsize.value, files_pci)
            filet = normpath(
                join(datapath, 'chip_images',
                     f'images_list.{pci_band.value[0]}.csv'))
            if file_len(filet) > 1:
                outlog(
                    f"Completed, all GeoTIFFs for bands '{pci_band.value}' are ",
                    f"downloaded in the folder: '{datapath}/chip_images'")
            else:
                outlog(
                    "No files where downloaded, please check your configurations"
                )

    def get_from_location(lon, lat):
        outlog(f"Finding parcel information for coordinates: {lon}, {lat}")
        parcel = parcel_info.by_location(aois.value, year.value, lon, lat,
                                         ptype.value, True, False, debug)
        pid = str(parcel['pid'][0])
        outlog(f"The parcel '{pid}' was found at this location.")
        try:
            get_data(parcel)
        except Exception as err:
            print(err)

    def get_from_id(pids):
        outlog(f"Getting parcels information for: '{pids}'")
        for pid in pids:
            try:
                parcel = parcel_info.by_pid(aois.value, year.value, pid,
                                            ptype.value, True, False, debug)
                get_data(parcel)
            except Exception as err:
                print(err)

    @bt_get.on_click
    def bt_get_on_click(b):
        progress.clear_output()
        if method.value == 1:
            try:
                with progress:
                    lon, lat = plon.value, plat.value
                    get_from_location(lon, lat)
            except Exception as err:
                outlog("Could not get parcel information for location",
                       f"'{lon}', '{lat}': {err}")

        elif method.value == 2:
            try:
                with progress:
                    pids = pid.value.replace(" ", "").split(",")
                    get_from_id(pids)
            except Exception as err:
                outlog(f"Could not get parcel information: {err}")

        elif method.value == 3:
            try:
                marker = get_maps.base_map.map_marker
                lon = str(round(marker.location[1], 2))
                lat = str(round(marker.location[0], 2))
                get_from_location(lon, lat)
            except Exception as err:
                outlog(f"Could not get parcel information: {err}")
        elif method.value == 4:
            try:
                plimit = int(values['set']['plimit'])
                file = normpath(
                    join(config.get_value(['paths', 'temp']),
                         'pids_from_polygon.txt'))
                with open(file, "r") as text_file:
                    pids = text_file.read().split('\n')
                outlog("Geting data form the parcels:")
                outlog(pids)
                if len(pids) <= plimit:
                    get_from_id(pids)
                else:
                    outlog(
                        "You exceeded the maximum amount of selected parcels ",
                        f"({plimit}) to get data. Please select smaller area.")
            except Exception as err:
                outlog("No pids file found.", err)
        else:
            outlog(f"Please select method to get parcel information.")

    return VBox([
        info, table_options, info_method, method, method_out, info_type,
        data_types, info_get, info_paths, paths_box, bt_get, progress
    ])
示例#22
0
class Graph(VBox):
    """Graph widget class for creating interactive graphs

    Keyword arguments:

    * `name` -- graph name
    * `delayed` -- use a draw button instead of updating on every change
    * `**kwargs` -- default configurations for the graph according to
      GraphConfig attributes and category names
    """
    def __init__(self, name="graph", delayed=False, **kwargs):
        self._display_stack = 1
        self._display_categories = set()
        self._filter_in = None
        self._filter_out = None
        self._svg_name = ""
        self._initial = kwargs
        self.delayed = delayed

        self.graph_name = name
        self.toggle_widgets = OrderedDict()
        self.color_widgets = OrderedDict()
        self.font_color_widgets = OrderedDict()

        self.filter_in_widget = Text(description="Filter In",
                                     value=kwargs.get("filter_in", ""))
        self.filter_out_widget = Text(description="Filter Out",
                                      value=kwargs.get("filter_out", ""))

        self.r_widget = self.slider("R",
                                    "r",
                                    5,
                                    70,
                                    1,
                                    21,
                                    fn=self.update_r_widget)
        self.margin_widget = self.slider("Margin", "margin", 5, 170, 1, 59)
        self.margin_left_widget = self.slider("M. Left", "margin_left", 5, 170,
                                              1, 21)
        self.dist_x_widget = self.slider("Dist. X", "dist_x", 5, 170, 1, 76)
        self.dist_y_widget = self.slider("Dist. Y", "dist_y", 5, 170, 1, 76)
        self.letters_widget = self.slider("Letters", "letters", 1, 40, 1, 7)
        self.by_year_widget = self.slider("By Year", "max_by_year", 0, 50, 1,
                                          5)

        self.places_widget = ToggleButton(description="Places",
                                          value=kwargs.get("places", False))
        self.references_widget = ToggleButton(description="References",
                                              value=kwargs.get(
                                                  "references", True))
        self.delayed_widget = Button(description="Draw")

        self.output_widget = Output()

        self.filter_in_widget.observe(self.update_widget, "value")
        self.filter_out_widget.observe(self.update_widget, "value")
        self.places_widget.observe(self.update_widget, "value")
        self.references_widget.observe(self.update_widget, "value")
        self.delayed_widget.on_click(self.delayed_draw)

        self.create_widgets()

        self.update_r_widget()

        super(Graph, self).__init__([
            HBox([
                VBox([self.filter_in_widget, self.filter_out_widget] +
                     list(self.toggle_widgets.values()) + [
                         HBox([w1, w2])
                         for w1, w2 in zip(self.color_widgets.values(),
                                           self.font_color_widgets.values())
                     ] + [self.places_widget, self.references_widget] +
                     ([self.delayed_widget] if delayed else [])),
                VBox([
                    self.r_widget,
                    self.margin_widget,
                    self.margin_left_widget,
                    self.dist_x_widget,
                    self.dist_y_widget,
                    self.letters_widget,
                    self.by_year_widget,
                ]),
            ]), self.output_widget
        ])
        self.layout.display = "flex"
        self.layout.align_items = "stretch"
        self.delayed_draw()

    def delayed_draw(self, *args):
        """Draw graph"""
        self._display_stack = 0
        self.display()

    def slider(self, description, attribute, min, max, step, default, fn=None):
        """Creates slider"""
        widget = IntSlider(
            description=description,
            min=min,
            max=max,
            step=step,
            value=self._initial.get(attribute, default),
        )
        widget._configattr = attribute
        widget.observe(fn or self.update_widget, "value")
        return widget

    def update_widget(self, *args):
        """Callback for generic widgets"""
        self._display_stack += 1
        self.display()

    def update_r_widget(self, *args):
        """Callback for updating r_widget value"""
        self._display_stack += 1
        r_value = self.r_widget.value
        dist_min = 2 * r_value + 2
        letters_max = int(r_value / 3.6)
        self.margin_left_widget.min = -1
        self.margin_left_widget.value = max(r_value,
                                            self.margin_left_widget.value)
        self.margin_left_widget.min = r_value
        self.dist_x_widget.min = -1
        self.dist_x_widget.value = max(dist_min, self.dist_x_widget.value)
        self.dist_x_widget.min = dist_min
        self.dist_y_widget.min = -1
        self.dist_y_widget.value = max(dist_min, self.dist_y_widget.value)
        self.dist_y_widget.min = dist_min
        self.letters_widget.max = 5000
        self.letters_widget.value = min(letters_max, self.letters_widget.value)
        self.letters_widget.max = letters_max
        self.display()

    def visible_classes(self):
        """Generate classes"""
        for class_ in config.CLASSES:
            if class_[2] in ("display", "hide"):
                yield class_

    def create_category(self, name, attr, value, color, font_color):
        """Create category widget"""
        VIS = ["none", ""]
        widget = self.toggle_widgets[attr] = ToggleButton(value=value,
                                                          description=name)
        wcolor = self.color_widgets[attr] = ColorPicker(value=color,
                                                        description=name,
                                                        width="180px")
        wfont_color = self.font_color_widgets[attr] = ColorPicker(
            value=font_color, width="110px")

        def visibility(*args):
            """" Toggles visibility of category """
            self._display_stack += 1
            wcolor.layout.display = VIS[int(widget.value)]
            wfont_color.layout.display = VIS[int(widget.value)]
            self.display()

        widget.observe(visibility, "value")
        wcolor.observe(self.update_widget, "value")
        wfont_color.observe(self.update_widget, "value")
        visibility()

    def create_widgets(self):
        """Create custom categories"""
        for class_ in self.visible_classes():
            self.create_category(
                class_[0],
                class_[1],
                (class_[2] == "display"),
                class_[3],
                class_[4],
            )

    def graph(self):
        """Create graph"""
        reload()
        work_list = load_work()
        references = load_citations()

        self._svg_name = str(Path("output") / (self.graph_name + ".svg"))
        self._display_categories = {
            key
            for key, widget in self.toggle_widgets.items() if widget.value
        }
        self._filter_in = self.filter_in_widget.value.lower()
        self._filter_out = self.filter_out_widget.value.lower()

        work_list = list(filter(self.filter_work, work_list))
        ref_list = []
        if self.references_widget.value:
            references = ref_list = list(
                filter(
                    lambda x: self.filter_work(x.citation) and self.
                    filter_work(x.work), references))

        graph_config = GraphConfig()
        graph_config.r = self.r_widget.value
        graph_config.margin = self.margin_widget.value
        graph_config.margin_left = self.margin_left_widget.value
        graph_config.dist_x = self.dist_x_widget.value
        graph_config.dist_y = self.dist_y_widget.value
        graph_config.letters = self.letters_widget.value
        graph_config.max_by_year = self.by_year_widget.value
        graph_config.draw_place = self.places_widget.value
        graph_config.fill_color = self.work_colors

        create_graph(self._svg_name, work_list, ref_list, graph_config)
        return work_list, ref_list

    def work_key(self, work):
        """Return work category"""
        return oget(work, "category")

    def work_colors(self, work):
        """Return colors for work"""
        key = self.work_key(work)
        if key not in self.color_widgets:
            return ("white", "black")
        return (self.color_widgets[key].value,
                self.font_color_widgets[key].value)

    def filter_work(self, work):
        """Filter work"""
        key = self.work_key(work)
        if key not in self._display_categories:
            return False
        for attr in dir(work):
            if self._filter_out and self._filter_out in str(getattr(
                    work, attr)).lower():
                return False
        for attr in dir(work):
            if self._filter_in in str(getattr(work, attr)).lower():
                return True
        return False

    def display(self, *args):
        """Display interactive graph"""
        if self._display_stack:
            if not self.delayed:
                self._display_stack -= 1
            if self._display_stack:
                # Skip display if other widgets will invoke display soon
                return False
        self.output_widget.clear_output()
        with self.output_widget:
            work_list, references = self.graph()
            display(self._svg_name)
            svg = SVG(self._svg_name)
            svg._data = svg._data[:4] + ' class="refgraph"' + svg._data[4:]
            display(svg)

            interaction = """
                $(".hoverable polyline, .hoverable line").mouseenter(
                    function(e) {
                        //e.stopPropagation();
                        $(this).css("stroke", "blue");
                        $(this).css("stroke-width", "3px");
                    }).mouseleave(
                    function() {
                        $(this).css("stroke", "black");
                        $(this).css("stroke-width", "inherit");
                    });
            """
            display(Javascript(interaction))
            display(
                HTML("""
                <script type="text/javascript">
                    %s

                    require(["./svg-pan-zoom"], function(svgPanZoom) {
                        svgPanZoom('.refgraph', {'minZoom': 0.1});
                    });
                </script>
            """ % (open(
                    Path(__file__) / ".." / ".." / "resources" /
                    "svg-pan-zoom.min.js").read(), )))

        return True
示例#23
0
class GluePlotly():
    window = None
    plotly_fig = None
    output_cont = None
    options_cont = None
    data = None
    debug = None
    dimensions = None
    parent = None
    tab = None
    modal = True
    only_subsets = False
    options = {}
    margins = {}

    def __init__(self, data, dimensions, **kwargs):
        self.data = data
        self.options = {}
        self.margins = {}
        self.dimensions = dimensions
        self.debug = kwargs.get('debug', None)
        self.modal = kwargs.get('modal', True)
        self.only_subsets = kwargs.get('only_subsets', False)
        self.output_cont = Output()
        self.output_cont.layout.width = '100%'
        self.options_cont = Output()
        self.margins_cont = Output()

        self.option_tab = Tab()
        self.option_tab.children = [self.options_cont, self.margins_cont]
        self.option_tab.set_title(0, "Plot")
        self.option_tab.set_title(1, "Layout")
        self.option_tab.layout.display = 'none'

        self.options_check = ToggleButton(value=False,
                                          description="Options",
                                          icon='cog')
        self.options_check.observe(lambda v: self.showWidget(v["new"]),
                                   names='value')

        self.tab = HBox()
        self.tab.children = [self.option_tab, self.output_cont]
        init_notebook_mode(connected=True)
        if (self.window == None):
            if (self.modal == True):
                title = kwargs.get('title', "")
                mode = kwargs.get('mode', "")
                self.window = Floatview(title=title, mode=mode)
            else:
                self.window = Output()
                display(self.window)
        self.DefaultMargins()
        self.displayWindow()

    def showWidget(self, show):
        if show:
            self.option_tab.layout.display = None
        else:
            self.option_tab.layout.display = "None"

    def UpdateLayout(self, options):
        for key, value in options.items():
            try:
                self.plotly_fig.layout[key] = value
            except:
                pass

    def UpdateTraces(self, options):
        for key, value in options.items():
            for i in range(len(self.plotly_fig.data)):
                try:
                    self.plotly_fig.data[i][key] = value
                except:
                    pass

    def DefaultLayoutTitles(self, title, xaxis, yaxis):
        self.options['title'] = Text(description='Title:', value=title)
        self.options['title'].observe(
            lambda v: self.UpdateLayout({'title': v['new']}), names='value')
        self.options['xaxis'] = Text(description='Xaxis Title:', value=xaxis)
        self.options['xaxis'].observe(
            lambda v: self.UpdateLayout({'xaxis.title': v['new']}),
            names='value')
        self.options['yaxis'] = Text(description='Yaxis Title:', value=yaxis)
        self.options['yaxis'].observe(
            lambda v: self.UpdateLayout({'yaxis.title': v['new']}),
            names='value')

    def DefaultLayoutScales(self, xscale, yscale):
        self.options['xscale'] = Dropdown(description='Xaxis Scale:',
                                          value=xscale,
                                          options=['linear', 'log'])
        self.options['xscale'].observe(
            lambda v: self.UpdateLayout({'xaxis.type': v['new']}),
            names='value')
        self.options['yscale'] = Dropdown(description='Yaxis Scale:',
                                          value=yscale,
                                          options=['linear', 'log'])
        self.options['yscale'].observe(
            lambda v: self.UpdateLayout({'yaxis.type': v['new']}),
            names='value')

    def DefaultMargins(self, l=50, r=0, b=50, t=30):
        self.margins['left'] = IntText(description='Left:', value=l)
        self.margins['left'].observe(
            lambda v: self.UpdateLayout({'margin.l': v['new']}), names='value')
        self.margins['right'] = IntText(description='Right:', value=r)
        self.margins['right'].observe(
            lambda v: self.UpdateLayout({'margin.r': v['new']}), names='value')
        self.margins['bottom'] = IntText(description='Bottom:', value=b)
        self.margins['bottom'].observe(
            lambda v: self.UpdateLayout({'margin.b': v['new']}), names='value')
        self.margins['top'] = IntText(description='Top:', value=t)
        self.margins['top'].observe(
            lambda v: self.UpdateLayout({'margin.t': v['new']}), names='value')

    def display(self):
        self.displayOutput()
        self.displayOptions()

    def displayOutput(self):
        with self.output_cont:
            clear_output()
            display(self.plotly_fig)

    def displayWindow(self):
        with self.window:
            clear_output()
            display(self.options_check)
            display(self.tab)

    def displayOptions(self):
        with self.options_cont:
            clear_output()
            if len(self.options) > 0:
                for key, option in self.options.items():
                    display(option)
            else:
                display("there are no options enabled for this Visualization")
        with self.margins_cont:
            clear_output()
            for key, option in self.margins.items():
                display(option)

    def setParent(self, parent):
        self.parent = parent

    def updateRender(self):
        pass

    def getDeltaFunction(self, size, alpha_min=0.5, alpha_max=0.8):
        if size > 1:
            alpha_delta = (alpha_max - alpha_min) / (size - 1)
        else:
            alpha_delta = (alpha_max - alpha_min)
        return alpha_min, alpha_max, alpha_delta

    def getDeltaColor(self, color, alpha_val, step=0, angle=25):
        rgb = colors.to_rgba(color)
        hsv = colors.rgb_to_hsv((rgb[0], rgb[1], rgb[2]))
        h = (round((hsv[0] * 360 + angle * step)) % 360) / 360
        s = (round((hsv[1] * 360 + (angle / 10) * step)) % 360) / 360
        v = hsv[2]
        rgb = colors.hsv_to_rgb((h, s, v))
        return colors.to_rgba(rgb, alpha=alpha_val)
示例#24
0
class TabularCoOccurrenceGUI(GridBox):  # pylint: disable=too-many-ancestors
    def __init__(self,
                 *,
                 bundle: Bundle,
                 default_token_filter: str = None,
                 **kwargs):
        global CURRENT_BUNDLE
        CURRENT_BUNDLE = bundle
        """Alternative implementation that uses VectorizedCorpus"""
        self.bundle: Bundle = bundle
        self.co_occurrences: pd.DataFrame = None
        self.pivot_column_name: str = 'time_period'

        if not isinstance(bundle.token2id, Token2Id):
            raise ValueError(
                f"Expected Token2Id, found {type(bundle.token2id)}")

        if not isinstance(bundle.compute_options, dict):
            raise ValueError(
                "Expected Compute Options in bundle but found no such thing.")
        """Current processed corpus"""
        self.corpus: VectorizedCorpus = bundle.corpus
        """Properties that changes current corpus"""
        self._pivot: Dropdown = Dropdown(
            options=["year", "lustrum", "decade"],
            value="decade",
            placeholder='Group by',
            layout=Layout(width='auto'),
        )
        """"Keyness source"""
        self._keyness_source: Dropdown = Dropdown(
            options={
                "Full corpus": KeynessMetricSource.Full,
                "Concept corpus": KeynessMetricSource.Concept,
                "Weighed corpus": KeynessMetricSource.Weighed,
            } if bundle.concept_corpus is not None else {
                "Full corpus": KeynessMetricSource.Full,
            },
            value=KeynessMetricSource.Weighed
            if bundle.concept_corpus is not None else KeynessMetricSource.Full,
            layout=Layout(width='auto'),
        )
        """Properties that changes current corpus"""
        self._keyness: Dropdown = Dropdown(
            options={
                "TF": KeynessMetric.TF,
                "TF (norm)": KeynessMetric.TF_normalized,
                "TF-IDF": KeynessMetric.TF_IDF,
                "HAL CWR": KeynessMetric.HAL_cwr,
                "PPMI": KeynessMetric.PPMI,
                "LLR": KeynessMetric.LLR,
                "LLR(Z)": KeynessMetric.LLR_Z,
                "LLR(N)": KeynessMetric.LLR_N,
                "DICE": KeynessMetric.DICE,
            },
            value=KeynessMetric.TF,
            layout=Layout(width='auto'),
        )
        """Properties that don't change current corpus"""
        self._token_filter: Text = Text(value=default_token_filter,
                                        placeholder='token match',
                                        layout=Layout(width='auto'))
        self._global_threshold_filter: Dropdown = Dropdown(
            options={
                f'>= {i}': i
                for i in (1, 2, 3, 4, 5, 10, 25, 50, 100, 250, 500)
            },
            value=5,
            layout=Layout(width='auto'),
        )
        self.concepts: Set[str] = set(self.bundle.context_opts.concept or [])
        self._largest: Dropdown = Dropdown(
            options=[10**i for i in range(0, 7)],
            value=10000,
            layout=Layout(width='auto'),
        )
        self._show_concept = ToggleButton(
            description='Show concept',
            value=False,
            icon='',
            layout=Layout(width='auto'),
        )
        self._message: HTML = HTML()
        self._compute: Button = Button(description="Compute",
                                       button_style='success',
                                       layout=Layout(width='auto'))
        self._save = Button(description='Save', layout=Layout(width='auto'))
        self._download = Button(description='Download',
                                layout=Layout(width='auto'))
        self._download_output: Output = Output()
        self._table_view = TableViewerClass(data=empty_data())

        self._button_bar = HBox(
            children=[
                VBox([HTML("<b>Token match</b>"), self._token_filter]),
                VBox([HTML("<b>Source</b>"), self._keyness_source]),
                VBox([HTML("<b>Keyness</b>"), self._keyness]),
                VBox([HTML("🙂"), self._show_concept]),
                VBox([HTML("<b>Group by</b>"), self._pivot]),
                VBox([HTML("<b>Threshold</b>"),
                      self._global_threshold_filter]),
                VBox([HTML("<b>Group limit</b>"), self._largest]),
                VBox([self._save, self._download]),
                VBox([self._compute, self._message]),
                self._download_output,
            ],
            layout=Layout(width='auto'),
        )
        super().__init__(
            children=[self._button_bar, self._table_view.container],
            layout=Layout(width='auto'),
            **kwargs)

        self._save.on_click(self.save)
        self._download.on_click(self.download)

        self.start_observe()

    def _compute_handler(self, *_):
        try:
            self.set_buzy(True, "Computing...")

            self.update_corpus()
            self.update_co_occurrences()

            self.set_buzy(False, "✔")

        except ValueError as ex:
            self.alert(str(ex))
        except Exception as ex:
            logger.exception(ex)
            self.alert(str(ex))
            raise

        self.set_buzy(False)

    def set_buzy(self, is_buzy: bool = True, message: str = None):

        if message:
            self.alert(message)

        self._keyness.disabled = is_buzy
        self._keyness_source.disabled = is_buzy
        self._show_concept.disabled = is_buzy or self.bundle.concept_corpus is None
        self._pivot.disabled = is_buzy
        self._global_threshold_filter.disabled = is_buzy
        self._token_filter.disabled = is_buzy
        self._save.disabled = is_buzy
        self._download.disabled = is_buzy
        self._largest.disabled = is_buzy

    def start_observe(self):

        self.stop_observe()

        self._compute.on_click(self._compute_handler)

        self._show_concept.observe(self.update_co_occurrences, 'value')
        self._largest.observe(self.update_co_occurrences, 'value')
        self._show_concept.observe(self._update_toggle_icon, 'value')
        self._token_filter.observe(self._filter_co_occurrences, 'value')

        return self

    def stop_observe(self):

        with contextlib.suppress(Exception):

            self._show_concept.unobserve(self.update_co_occurrences, 'value')
            self._largest.unobserve(self.update_co_occurrences, 'value')
            self._token_filter.unobserve(self._filter_co_occurrences, 'value')
            self._show_concept.unobserve(self._update_toggle_icon, 'value')

    def alert(self, message: str) -> None:
        self._message.value = f"<span style='color: red; font-weight: bold;'>{message}</span>"

    def info(self, message: str) -> None:
        self._message.value = f"<span style='color: green; font-weight: bold;'>{message}</span>"

    def update_corpus(self, *_):

        self.set_buzy(True, "⌛ Computing...")
        self.corpus = self.to_corpus()
        self.set_buzy(False, "✔")

    def update_co_occurrences(self, *_) -> pd.DataFrame:

        self.set_buzy(True, "⌛ Preparing data...")
        self.co_occurrences = self.to_co_occurrences()
        self.set_buzy(False, "✔")

        self.set_buzy(True, "⌛ Loading table...")
        self._table_view.update(self.co_occurrences[DISPLAY_COLUMNS])
        self.set_buzy(False, "✔")

        self.info(f"Data size: {len(self.co_occurrences)}")

    def _filter_co_occurrences(self, *_) -> pd.DataFrame:

        co_occurrences: pd.DataFrame = self.to_filtered_co_occurrences()

        self._table_view.update(co_occurrences[DISPLAY_COLUMNS])

        self.info(f"Data size: {len(co_occurrences)}")

    def _update_toggle_icon(self, event: dict) -> None:
        with contextlib.suppress(Exception):
            event['owner'].icon = 'check' if event['new'] else ''

    @property
    def ignores(self) -> List[str]:

        if self.show_concept or not self.concepts:
            return set()

        if isinstance(self.concepts, Iterable):
            return set(self.concepts)

        return {self.concepts}

    @property
    def show_concept(self) -> bool:
        return self._show_concept.value

    @show_concept.setter
    def show_concept(self, value: bool):
        self._show_concept.value = value

    @property
    def keyness(self) -> KeynessMetric:
        return self._keyness.value

    @keyness.setter
    def keyness(self, value: KeynessMetric):
        self._keyness.value = value

    @property
    def keyness_source(self) -> KeynessMetricSource:
        return self._keyness_source.value

    @keyness_source.setter
    def keyness_source(self, value: KeynessMetricSource):
        self._keyness_source.value = value

    @property
    def global_threshold(self) -> int:
        return self._global_threshold_filter.value

    @global_threshold.setter
    def global_threshold(self, value: int):
        self._global_threshold_filter.value = value

    @property
    def largest(self) -> int:
        return self._largest.value

    @largest.setter
    def largest(self, value: int):
        self._largest.value = value

    @property
    def token_filter(self) -> List[str]:
        return self._token_filter.value.strip().split()

    @token_filter.setter
    def token_filter(self, value: List[str]):
        self._token_filter.value = ' '.join(value) if isinstance(
            value, list) else value

    @property
    def pivot(self) -> str:
        return self._pivot.value

    @pivot.setter
    def pivot(self, value: str):
        self._pivot.value = value

    def save(self, *_b):
        store_co_occurrences(
            filename=path_add_timestamp('co_occurrence_data.csv'),
            co_occurrences=self.co_occurrences,
            store_feather=False,
        )

    def download(self, *_):
        self._button_bar.disabled = True

        with contextlib.suppress(Exception):
            js_download = create_js_download(self.co_occurrences, index=True)
            if js_download is not None:
                with self._download_output:
                    IPython_display.display(js_download)

        self._button_bar.disabled = False

    def to_co_occurrences(self) -> pd.DataFrame:

        self.set_buzy(True, "⌛ Preparing co-occurrences...")

        try:

            if self.pivot_column_name not in self.corpus.document_index.columns:
                raise ValueError(
                    f"expected '{self.pivot_column_name}' but not found in {', '.join(self.corpus.document_index.columns)}"
                )

            co_occurrences: pd.DataFrame = (CoOccurrenceHelper(
                corpus=self.corpus,
                source_token2id=self.bundle.token2id,
                pivot_keys=self.pivot_column_name,
            ).exclude(self.ignores).largest(self.largest)).value

            self.set_buzy(False, None)
            self.alert("✔")
        except Exception as ex:
            self.set_buzy(False)
            self.alert(f"😢 {str(ex)}")
            raise

        return co_occurrences

    def to_filtered_co_occurrences(self) -> pd.DataFrame:

        if not self.token_filter:
            return self.co_occurrences

        co_occurrences: pd.DataFrame = self.co_occurrences

        re_filters: List[str] = [
            fnmatch.translate(s) for s in self.token_filter
        ]

        for re_filter in re_filters:
            co_occurrences = co_occurrences[co_occurrences.token.astype(
                str).str.contains(pat=re_filter, case=False, na="")]

        return co_occurrences

    def to_corpus(self) -> VectorizedCorpus:
        """Returns a grouped, optionally TF-IDF, corpus filtered by token & threshold."""
        self.set_buzy(True, "⌛ updating corpus...")

        try:
            corpus: VectorizedCorpus = self.bundle.keyness_transform(
                opts=self.compute_opts())
            self.set_buzy(False, None)
            self.alert("✔")
        except Exception as ex:
            self.set_buzy(False)
            self.alert(f"😢 {str(ex)}")
            raise

        return corpus

    def setup(self) -> "TabularCoOccurrenceGUI":
        self.update_corpus()
        return self

    def compute_opts(self) -> ComputeKeynessOpts:
        return ComputeKeynessOpts(
            period_pivot=self.pivot,
            keyness_source=self.keyness_source,
            keyness=self.keyness,
            tf_threshold=self.global_threshold,
            pivot_column_name=self.pivot_column_name,
            normalize=False,
        )
示例#25
0
class InteractiveWidgets():
    """
    Use this class to bind start/stop interactivity to an existing class.
    Set start_handler, and stop_handler with functions for the button handlers to call, then call
    :func:`InteractiveWidgets.create_interactive_widgets` to get started.
    """
    def __init__(self):
        """
        To be safe, all objects will be left blank in major version 1.x.x on init.
        """
        self.start_streaming_button = None
        self.stop_streaming_button = None
        self.streaming_state_indicator = None
        self.streaming_state = False
        self.start_handler = None
        self.stop_handler = None
        self.output_area = None
        self.display_holder = None

    def create_interactive_widgets(self, start_handler, stop_handler):
        """
        This method will create the necessary ipywidget objects and return the final Box to display.
        :return:
        """
        self.start_streaming_button = ToggleButton(
            description='Start Streaming',
            value=False,
            disabled=False,
            button_style='',
            tooltip='Start Streaming',
            icon='play'  # (FontAwesome names without the `fa-` prefix)
        )
        self.stop_streaming_button = ToggleButton(
            description='Stop Streaming',
            value=True,
            disabled=False,
            button_style='',
            tooltip='Stop Streaming',
            icon='stop'  # (FontAwesome names without the `fa-` prefix)
        )
        self.output_area = Output()
        self.start_handler = start_handler
        self.stop_handler = stop_handler
        self.start_streaming_button.observe(
            self.start_streaming_button_handler)
        self.stop_streaming_button.observe(self.stop_streaming_button_handler)
        self.display_holder = VBox([
            HBox([self.start_streaming_button, self.stop_streaming_button]),
            self.output_area
        ])
        return self.display_holder

    def start_streaming_button_handler(self, change):
        """
        Use this handler to bind the start button.
        Disable the start button on click, and set the stop button to False.
        :return:
        """
        if change['new']:
            self.output_area.clear_output()
            self.start_streaming_button.disabled = True
            self.stop_streaming_button.value = False
            with self.output_area:
                self.start_handler()

    def stop_streaming_button_handler(self, change):
        """
        Use this handler to bind the stop button.
        Re-enable the start button on click, and set the stop button to False.
        :param change:
        :return:
        """
        if change[
                'new'] == True:  # This is required because otherwise this will trigger true on dicts/other objects
            self.start_streaming_button.value = False
            self.start_streaming_button.disabled = False
            with self.output_area:
                self.stop_handler()

    def set_stopped_state(self):
        self.start_streaming_button.value = False
        self.start_streaming_button.disabled = False
        self.stop_streaming_button.value = True