class MultiProgressWidget(MultiProgressBar): """ Multiple progress bar Widget suitable for the notebook Displays multiple progress bars for a computation, split on computation type. See Also -------- progress: User-level function <--- use this MultiProgress: Non-visualization component that contains most logic ProgressWidget: Single progress bar widget """ def __init__(self, keys, scheduler=None, minimum=0, interval=0.1, func=key_split, complete=False): super(MultiProgressWidget, self).__init__(keys, scheduler, func, interval, complete) from ipywidgets import VBox self.widget = VBox([]) def make_widget(self, all): from ipywidgets import FloatProgress, HBox, VBox, HTML import cgi self.elapsed_time = HTML('') self.bars = {key: FloatProgress(min=0, max=1, description='', height = '10px') for key in all} self.bar_texts = {key: HTML('', width = "140px") for key in all} self.bar_labels = {key: HTML('<div style=\"padding: 0px 10px 0px 10px; text-align:left; word-wrap: break-word;\">' + cgi.escape(key) + '</div>') for key in all} def key(kv): """ Order keys by most numerous, then by string name """ return kv[::-1] key_order = [k for k, v in sorted(all.items(), key=key, reverse=True)] self.bar_widgets = VBox([ HBox([ self.bar_texts[key], self.bars[key], self.bar_labels[key] ]) for key in key_order ]) self.widget.children = (self.elapsed_time, self.bar_widgets) def _ipython_display_(self, **kwargs): IOLoop.current().add_callback(self.listen) return self.widget._ipython_display_(**kwargs) def _draw_stop(self, remaining, status, exception=None, key=None, **kwargs): for k, v in remaining.items(): if not v: self.bars[k].bar_style = 'success' """ TODO if status == 'error': self.bars[self.func(key)].bar_style = 'danger' self.elapsed_time.value = '<div style="padding: 0px 10px 5px 10px"><b>Warning:</b> the computation terminated due to an error after ' + format_time(self.elapsed) + '</div>' """ def _draw_bar(self, remaining, all, status, **kwargs): if self.keys and not self.widget.children: self.make_widget(all) for k, ntasks in all.items(): ndone = ntasks - remaining[k] self.elapsed_time.value = '<div style="padding: 0px 10px 5px 10px"><b>Elapsed time:</b> ' + format_time(self.elapsed) + '</div>' self.bars[k].value = ndone / ntasks if ntasks else 1.0 self.bar_texts[k].value = '<div style="padding: 0px 10px 0px 10px; text-align: right">%d / %d</div>' % (ndone, ntasks)
class ProgressWidget(ProgressBar): """ProgressBar that uses an IPython ProgressBar widget for the notebook See Also -------- progress: User function TextProgressBar: Text version suitable for the console """ def __init__( self, keys, scheduler=None, interval="100ms", complete=False, loop=None, **kwargs, ): super().__init__(keys, scheduler, interval, complete) from ipywidgets import HTML, FloatProgress, HBox, VBox self.elapsed_time = HTML("") self.bar = FloatProgress(min=0, max=1, description="") self.bar_text = HTML("") self.bar_widget = HBox([self.bar_text, self.bar]) self.widget = VBox([self.elapsed_time, self.bar_widget]) def _ipython_display_(self, **kwargs): IOLoop.current().add_callback(self.listen) return self.widget._ipython_display_(**kwargs) def _draw_stop(self, remaining, status, exception=None, **kwargs): if status == "error": _, exception, _ = clean_exception(exception) self.bar.bar_style = "danger" self.elapsed_time.value = ( '<div style="padding: 0px 10px 5px 10px"><b>Exception</b> ' "<tt>" + repr(exception) + "</tt>:" + format_time(self.elapsed) + " " + "</div>") elif not remaining: self.bar.bar_style = "success" self.elapsed_time.value = ( '<div style="padding: 0px 10px 5px 10px"><b>Finished:</b> ' + format_time(self.elapsed) + "</div>") def _draw_bar(self, remaining, all, **kwargs): ndone = all - remaining self.elapsed_time.value = ( '<div style="padding: 0px 10px 5px 10px"><b>Computing:</b> ' + format_time(self.elapsed) + "</div>") self.bar.value = ndone / all if all else 1.0 self.bar_text.value = ( '<div style="padding: 0px 10px 0px 10px; text-align:right;">%d / %d</div>' % (ndone, all))
class ProgressWidget(ProgressBar): """ ProgressBar that uses an IPython ProgressBar widget for the notebook See Also -------- progress: User function TextProgressBar: Text version suitable for the console """ def __init__(self, keys, scheduler=None, interval='100ms', complete=False, loop=None): super(ProgressWidget, self).__init__(keys, scheduler, interval, complete) from ipywidgets import FloatProgress, HBox, VBox, HTML self.elapsed_time = HTML('') self.bar = FloatProgress(min=0, max=1, description='', height='10px') self.bar_text = HTML('', width="140px") self.bar_widget = HBox([self.bar_text, self.bar]) self.widget = VBox([self.elapsed_time, self.bar_widget]) def _ipython_display_(self, **kwargs): IOLoop.current().add_callback(self.listen) return self.widget._ipython_display_(**kwargs) def _draw_stop(self, remaining, status, exception=None, **kwargs): if status == 'error': self.bar.bar_style = 'danger' self.elapsed_time.value = ( '<div style="padding: 0px 10px 5px 10px"><b>Exception</b> ' '<tt>' + repr(exception) + '</tt>:' + format_time(self.elapsed) + ' ' + '</div>') elif not remaining: self.bar.bar_style = 'success' self.elapsed_time.value = '<div style="padding: 0px 10px 5px 10px"><b>Finished:</b> ' + \ format_time(self.elapsed) + '</div>' def _draw_bar(self, remaining, all, **kwargs): ndone = all - remaining self.elapsed_time.value = '<div style=\"padding: 0px 10px 5px 10px\"><b>Computing:</b> ' + \ format_time(self.elapsed) + '</div>' self.bar.value = ndone / all if all else 1.0 self.bar_text.value = '<div style="padding: 0px 10px 0px 10px; text-align:right;">%d / %d</div>' % ( ndone, all)
class ProgressWidget(ProgressBar): """ ProgressBar that uses an IPython ProgressBar widget for the notebook See Also -------- progress: User function TextProgressBar: Text version suitable for the console """ def __init__(self, keys, scheduler=None, interval='100ms', complete=False, loop=None): super(ProgressWidget, self).__init__(keys, scheduler, interval, complete) from ipywidgets import FloatProgress, HBox, VBox, HTML self.elapsed_time = HTML('') self.bar = FloatProgress(min=0, max=1, description='') self.bar_text = HTML('') self.bar_widget = HBox([self.bar_text, self.bar]) self.widget = VBox([self.elapsed_time, self.bar_widget]) def _ipython_display_(self, **kwargs): IOLoop.current().add_callback(self.listen) return self.widget._ipython_display_(**kwargs) def _draw_stop(self, remaining, status, exception=None, **kwargs): if status == 'error': self.bar.bar_style = 'danger' self.elapsed_time.value = ( '<div style="padding: 0px 10px 5px 10px"><b>Exception</b> ' '<tt>' + repr(exception) + '</tt>:' + format_time(self.elapsed) + ' ' + '</div>' ) elif not remaining: self.bar.bar_style = 'success' self.elapsed_time.value = '<div style="padding: 0px 10px 5px 10px"><b>Finished:</b> ' + \ format_time(self.elapsed) + '</div>' def _draw_bar(self, remaining, all, **kwargs): ndone = all - remaining self.elapsed_time.value = '<div style=\"padding: 0px 10px 5px 10px\"><b>Computing:</b> ' + \ format_time(self.elapsed) + '</div>' self.bar.value = ndone / all if all else 1.0 self.bar_text.value = '<div style="padding: 0px 10px 0px 10px; text-align:right;">%d / %d</div>' % (ndone, all)
class CrossSelect(SelectMultiple): """ CrossSelect provides a two-tab multi-selection widget with regex text filtering. Items can be transferred with buttons between the selected and unselected options. """ def __init__(self, *args, **kwargs): # Compute selected and unselected values options = kwargs.get('options', {}) if isinstance(options, list): options = named_objs([(opt, opt) for opt in options]) self._reverse_lookup = {v: k for k, v in options.items()} selected = [self._reverse_lookup[v] for v in kwargs.get('value', [])] unselected = [k for k in options if k not in selected] # Define whitelist and blacklist self._lists = { False: SelectMultiple(options=unselected), True: SelectMultiple(options=selected) } self._lists[False].observe(self._update_selection, 'value') self._lists[True].observe(self._update_selection, 'value') # Define buttons button_layout = Layout(width='50px') self._buttons = { False: Button(description='<<', layout=button_layout), True: Button(description='>>', layout=button_layout) } self._buttons[False].on_click(self._apply_selection) self._buttons[True].on_click(self._apply_selection) # Define search self._search = { False: Text(placeholder='Filter available options'), True: Text(placeholder='Filter selected options') } self._search[False].observe(self._filter_options, 'value') self._search[True].observe(self._filter_options, 'value') # Define Layout no_margin = Layout(margin='0') row_layout = Layout(margin='0', display='flex', justify_content='space-between') search_row = HBox([self._search[False], self._search[True]]) search_row.layout = row_layout button_box = VBox([self._buttons[True], self._buttons[False]], layout=Layout(margin='auto 0')) tab_row = HBox([self._lists[False], button_box, self._lists[True]]) tab_row.layout = row_layout self._composite = VBox([search_row, tab_row], layout=no_margin) self.observe(self._update_options, 'options') self.observe(self._update_value, 'value') self._selected = {False: [], True: []} self._query = {False: '', True: ''} super(CrossSelect, self).__init__(*args, **dict(kwargs, options=options)) def _update_value(self, event): selected = [self._reverse_lookup.get(v, v) for v in event['new']] self._lists[True].options = selected self._lists[True].value = [] self._lists[False].options = [ o for o in self.options if o not in selected ] def _update_options(self, event): """ Updates the options of each of the sublists after the options for the whole widget are updated. """ self._reverse_lookup = {v: k for k, v in event['new'].items()} options = list(event['new'].keys()) if isinstance( event, dict) else event['new'] self._selected[False] = [] self._selected[True] = [] self._lists[True].options = [''] self._lists[True].value = [] self._lists[False].options = options self._lists[False].value = [] self._apply_filters() def _apply_filters(self): self._filter_options({'owner': self._search[False]}) self._filter_options({'owner': self._search[True]}) def _filter_options(self, event): """ Filters unselected options based on a text query event. """ selected = event['owner'] is self._search[True] query = self._query[selected] if 'new' not in event else event['new'] self._query[selected] = query other = self._lists[not selected].options options = [o for o in self.options if o not in other] if not query: self._lists[selected].options = options self._lists[selected].value = [] else: try: match = re.compile(query) matches = list(filter(match.search, options)) options = matches + [ opt for opt in options if opt not in matches ] except: matches = options self._lists[selected].options = options if options else [''] self._lists[selected].value = matches def _update_selection(self, event): """ Updates the current selection in each list. """ selected = event['owner'] is self._lists[True] self._selected[selected] = [v for v in event['new'] if v != ''] def _apply_selection(self, event): """ Applies the current selection depending on which button was pressed. """ selected = event is self._buttons[True] new = self._selected[not selected] old = self._lists[selected].options other = self._lists[not selected].options merged = sorted([v for v in list(old) + list(new) if v != '']) leftovers = sorted([o for o in other if o not in new and o != '']) new_values = merged if selected else leftovers self._lists[selected].options = merged if merged else [''] self._lists[not selected].options = leftovers if leftovers else [''] self.value = [ self._options_dict[o] for o in self._lists[True].options if o != '' ] self._apply_filters() def _ipython_display_(self, **kwargs): """ Displays the composite widget. """ self._composite._ipython_display_(**kwargs) def get_state(self, key=None, drop_defaults=False): # HACK: Lets this composite widget pretend to be a regular widget # when included into a layout. if key in ['value', '_options_labels']: return super(CrossSelect, self).get_state(key) return self._composite.get_state(key)
class MultiProgressWidget(MultiProgressBar): """ Multiple progress bar Widget suitable for the notebook Displays multiple progress bars for a computation, split on computation type. See Also -------- progress: User-level function <--- use this MultiProgress: Non-visualization component that contains most logic ProgressWidget: Single progress bar widget """ def __init__( self, keys, scheduler=None, minimum=0, interval=0.1, func=key_split, complete=False, ): super(MultiProgressWidget, self).__init__(keys, scheduler, func, interval, complete) from ipywidgets import VBox self.widget = VBox([]) def make_widget(self, all): from ipywidgets import FloatProgress, HBox, VBox, HTML self.elapsed_time = HTML("") self.bars = { key: FloatProgress(min=0, max=1, description="") for key in all } self.bar_texts = {key: HTML("") for key in all} self.bar_labels = { key: HTML('<div style="padding: 0px 10px 0px 10px;' " text-align:left; word-wrap: " 'break-word;">' + html_escape(key.decode() if isinstance(key, bytes) else key) + "</div>") for key in all } def keyfunc(kv): """ Order keys by most numerous, then by string name """ return kv[::-1] key_order = [ k for k, v in sorted(all.items(), key=keyfunc, reverse=True) ] self.bar_widgets = VBox([ HBox([self.bar_texts[key], self.bars[key], self.bar_labels[key]]) for key in key_order ]) self.widget.children = (self.elapsed_time, self.bar_widgets) def _ipython_display_(self, **kwargs): IOLoop.current().add_callback(self.listen) return self.widget._ipython_display_(**kwargs) def _draw_stop(self, remaining, status, exception=None, key=None, **kwargs): for k, v in remaining.items(): if not v: self.bars[k].bar_style = "success" else: self.bars[k].bar_style = "danger" if status == "error": # self.bars[self.func(key)].bar_style = 'danger' # TODO self.elapsed_time.value = ( '<div style="padding: 0px 10px 5px 10px"><b>Exception</b> ' + "<tt>" + repr(exception) + "</tt>:" + format_time(self.elapsed) + " " + "</div>") else: self.elapsed_time.value = ( '<div style="padding: 0px 10px 5px 10px"><b>Finished:</b> ' + format_time(self.elapsed) + "</div>") def _draw_bar(self, remaining, all, status, **kwargs): if self.keys and not self.widget.children: self.make_widget(all) for k, ntasks in all.items(): ndone = ntasks - remaining[k] self.elapsed_time.value = ( '<div style="padding: 0px 10px 5px 10px"><b>Computing:</b> ' + format_time(self.elapsed) + "</div>") self.bars[k].value = ndone / ntasks if ntasks else 1.0 self.bar_texts[k].value = ( '<div style="padding: 0px 10px 0px 10px; text-align: right">%d / %d</div>' % (ndone, ntasks))
class Annotator(BaseAnnotator): """IPython widget to quickly annotate data sets. """ def __init__(self, classes, history_length=10): super().__init__() self.history_length = int(history_length) self.last_repeat = 0 self._build(classes) def build_display_value(self, item): """Build the display of the item being annotated. This class has to be overwritten in subclasses. :returns: an HTML reprensetation of the item to display. """ return html.escape(repr(item)) def clear(self): super().clear() self.last_repeat = 0 def update_display(self): if self.current_item is None: self._html.value = "No data to annotate" self._info.value = " " else: reason, index, item = self.current_item self._html.value = self.build_display_value(item) self._info.value = html.escape("index: {}, reason: {}".format( index, reason)) if len(self.annotations) > self.last_repeat: from ipywidgets import Button, Layout repeats = list(self._history.children) for idx in range(self.last_repeat, len(self.annotations)): annotation = self.annotations[idx] repeat_button = Button( description= f'{annotation["label"]} - {annotation["item"]!r}', layout=Layout(width="50%"), ) repeat_button.on_click(lambda b: self.repeat(idx)) repeats = [repeat_button] + repeats self.last_repeat = len(self.annotations) repeats = repeats[:self.history_length] self._history.children = repeats def _build(self, classes): from ipywidgets import HTML, VBox, Layout, Box self._html = HTML(value="No data to annotate") self._info = HTML(value=" ") self._history = VBox(layout=Layout(margin="1em 0em 0em 0em")) self._widget = VBox([ self._html, self._info, Box( [self._build_label_button(label) for label in classes], layout=Layout(flex_flow="row wrap"), ), self._history, ]) def _build_label_button(self, label): from ipywidgets import Button if not isinstance(label, collections.abc.Mapping): label = {"label": label, "style": ""} else: label = dict(label) label.setdefault("style", "") b = Button(description=label["label"], button_style=label["style"]) b.on_click(lambda b: self.annotate_current(label["label"])) return b def _ipython_display_(self, **kwargs): return self._widget._ipython_display_(**kwargs)