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
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
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
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
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
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))]))
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'
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
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)
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
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'
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'
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')
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)
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()
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
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'
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 ])
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
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)
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, )
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