def df_items_to_tooltip(df, text_key: str, tool_tip_key: str):
    """
    Turns df into dictionary with rows as lists items and 
    passes specified keys to item text and tooltip respectively.
    Returns:
        list of rows with containers with text and tooltips 
    """

    df_dict = df.to_dict(orient="records")

    row_conts = []

    for row in df_dict:
        container = v.Container(children=[
            v.Tooltip(
                bottom=True,
                v_slots=[{
                    "name":
                    "activator",
                    "variable":
                    "tooltip",
                    "children":
                    v.Html(
                        tag="t2",
                        v_on="tooltip.on",
                        children=[str(row[text_key])],
                    ),
                }],
                children=[str(row[tool_tip_key])],
            )
        ])

        row_conts.append(field)

    return row_conts
Ejemplo n.º 2
0
 def add_tool(self, tool):
     self.tools[tool.tool_id] = tool
     icon = Image.from_file(icon_path(tool.icon, icon_format='svg'), width=ICON_WIDTH)
     button = v.Btn(v_on="tooltip.on", icon=True, children=[icon], value=tool.tool_id)
     annotated = v.Tooltip(
         bottom=True,
         v_slots=[{
             'name': 'activator',
             'variable': 'tooltip',
             'children': button}],
         children=[tool.tool_tip])
     self.children = list(self.children) + [annotated]
Ejemplo n.º 3
0
    def __init__(self, children, compute_all, label="", append_icon=None, prepend_icon=None, tooltip=""):
        # _widget for v_model, widget for display
        if append_icon:  
            self._widget = v.Checkbox(
                v_on='tooltip.on', append_icon=append_icon, v_model=True)
        elif prepend_icon:
            self._widget = v.Checkbox(
                v_on='tooltip.on', prepend_icon=prepend_icon, v_model=True)
        else:
            self._widget = v.Checkbox(
                v_on='tooltip.on', label=label, v_model=True)

        self.widget = v.Tooltip(bottom=True, v_slots=[{'name': 'activator', 'variable': 'tooltip', 'children': self._widget}],
                children=[tooltip])
        self._widget.on_event('change', self.handler)
        self.children = children
        self.compute_all = compute_all
Ejemplo n.º 4
0
    def __init__(self, label, tooltip, enum_color, clr, init_layer_val, layer_options, compute):

        self.check = v.Checkbox(v_on='tooltip.on', label=label, v_model=True , color='primary')
        self.check_widget = v.Tooltip(bottom=True, v_slots=[{'name': 'activator', 'variable': 'tooltip', 'children': self.check}],
                children=[tooltip])
       
        self.compute = compute
        self.enum_color = enum_color
        self.init_layer_val = init_layer_val
        self.layer_options = layer_options
        self.dropdown_widget = Dropdown(options=self.layer_options ,
                                        value=init_layer_val,
                                        disabled=False,
                                        layout={'width': '90px'}
                                        )
        self.dropdown_widget.observe(self.compute, names='value')
        self.dropdown_widget.observing = True
        self.clr = clr
Ejemplo n.º 5
0
    def init_widgets(self, tag_type):
        self.all_check = v.Checkbox(v_on='tooltip.on',
                                    prepend_icon='fa-globe',
                                    label="All",
                                    v_model=True,
                                    class_='ma-0 mt-1 pa-0')
        self.all_check_tp = v.Tooltip(bottom=True,
                                      v_slots=[{
                                          'name': 'activator',
                                          'variable': 'tooltip',
                                          'children': self.all_check
                                      }],
                                      children=["Select all"])
        self.all_check.on_event('change', self.check_all)
        all_row = [v.Row(children=[self.all_check_tp], class_='ml-7')]

        tag_rows = []
        treenodelabel = v.Html(
            tag='style',
            children=
            [(".vuetify-styles .v-treeview-node__label {"
              "margin-left: 0px;"
              "overflow: visible;"
              "}"
              ".vuetify-styles .v-input--selection-controls:not(.v-input--hide-details) .v-input__slot {"
              "margin-bottom: 0px;"
              "}"
              ".vuetify-styles .v-treeview-node__root .v-icon.v-icon.v-icon--link {"
              "margin-bottom: 10px;"
              "}"
              ".vuetify-styles .v-treeview-node--leaf {"
              "margin-left: 0px;"
              "}"
              ".vuetify-styles .v-treeview--dense .v-treeview-node__root {"
              "min-height: 21px;"
              "}")])

        for tag in self.model.curr_trace.tags:
            if tag.tag_type == tag_type:
                chk = Checkbox(tag)
                self.checkboxes.append(chk)
                chk.widget.on_event('change', self.update_all_checkbox)
                stats = self.get_stats(tag)
                btn, tooltip = self.create_zoom_button(tag, stats=stats)
                statss = self.tag_tooltip(tag, stats).splitlines()

                tag_row = v.Row(children=[btn, chk.widget], class_='ml-0')
                items = [{
                    'id':
                    1,
                    'name':
                    '',
                    'children': [{
                        'id': i + 2,
                        'name': stat
                    } for i, stat in enumerate(statss)],
                }]
                treeview = v.Treeview(items=items, dense=True)
                tag_rows.append(
                    v.Container(row=False,
                                class_="d-flex justify-start ma-0 pa-0",
                                children=[
                                    v.Col(cols=1,
                                          children=[treeview],
                                          class_="ma-0 pa-0"),
                                    v.Col(cols=12,
                                          children=[tag_row],
                                          class_="pt-0 pb-0")
                                ]))
        tag_rows.append(v.Container(row=False, children=[treenodelabel]))
        return VBox([
            v.List(children=(all_row + tag_rows),
                   dense=True,
                   nav=True,
                   max_height="300px",
                   max_width="300px")
        ])
Ejemplo n.º 6
0
    def create_tools(self):
        self.tools = []
        tool_actions = []
        self.tool_actions_map = tool_actions_map = {u"pan/zoom": self.panzoom}
        tool_actions.append(u"pan/zoom")

        # self.control_widget.set_title(0, "Main")
        self._main_widget = widgets.VBox()
        self._main_widget_1 = widgets.HBox()
        self._main_widget_2 = widgets.HBox()
        if 1:  # tool_select:
            self.brush = bqplot.interacts.BrushSelector(x_scale=self.scale_x,
                                                        y_scale=self.scale_y,
                                                        color="green")
            tool_actions_map["select"] = self.brush
            tool_actions.append("select")

            self.brush.observe(self.update_brush, ["selected", "selected_x"])
            # fig.interaction = brush
            # callback = self.dataset.signal_selection_changed.connect(lambda dataset: update_image())
            # callback = self.dataset.signal_selection_changed.connect(lambda *x: self.update_grid())

            # def cleanup(callback=callback):
            #    self.dataset.signal_selection_changed.disconnect(callback=callback)
            # self._cleanups.append(cleanup)

            self.button_select_nothing = v.Btn(
                icon=True,
                v_on='tooltip.on',
                children=[v.Icon(children=['delete'])])
            self.widget_select_nothing = v.Tooltip(
                bottom=True,
                v_slots=[{
                    'name': 'activator',
                    'variable': 'tooltip',
                    'children': self.button_select_nothing
                }],
                children=["Delete selection"])
            self.button_reset = widgets.Button(description="", icon="refresh")
            import copy
            self.start_limits = copy.deepcopy(self.limits)

            def reset(*args):
                self.limits = copy.deepcopy(self.start_limits)
                with self.scale_y.hold_trait_notifications():
                    self.scale_y.min, self.scale_y.max = self.limits[1]
                with self.scale_x.hold_trait_notifications():
                    self.scale_x.min, self.scale_x.max = self.limits[0]
                self.plot.update_grid()

            self.button_reset.on_click(reset)

            self.button_select_nothing.on_event(
                'click', lambda *ignore: self.plot.select_nothing())
            self.tools.append(self.button_select_nothing)
            self.modes_names = "replace and or xor subtract".split()
            self.modes_labels = "replace and or xor subtract".split()
            self.button_selection_mode = widgets.Dropdown(
                description='select', options=self.modes_labels)
            self.tools.append(self.button_selection_mode)

            def change_interact(*args):
                with self.output:
                    # print "change", args
                    name = tool_actions[self.button_action.v_model]
                    self.figure.interaction = tool_actions_map[name]

            tool_actions = ["pan/zoom", "select"]
            # tool_actions = [("m", "m"), ("b", "b")]
            self.button_action = \
                v.BtnToggle(v_model=0, mandatory=True, multiple=False, children=[
                                v.Tooltip(bottom=True, v_slots=[{
                                    'name': 'activator',
                                    'variable': 'tooltip',
                                    'children': v.Btn(v_on='tooltip.on', children=[
                                        v.Icon(children=['pan_tool'])
                                    ])
                                }], children=[
                                    "Pan & zoom"
                                ]),
                                v.Tooltip(bottom=True, v_slots=[{
                                    'name': 'activator',
                                    'variable': 'tooltip',
                                    'children': v.Btn(v_on='tooltip.on', children=[
                                        v.Icon(children=['crop_free'])
                                    ])
                                }], children=[
                                    "Square selection"
                                ]),
                        ])
            self.widget_tool_basic = v.Layout(children=[
                v.Layout(
                    pa_1=True,
                    column=False,
                    align_center=True,
                    children=[self.button_action, self.widget_select_nothing])
            ])
            self.plot.add_control_widget(self.widget_tool_basic)

            self.button_action.observe(change_interact, "v_model")
            self.tools.insert(0, self.button_action)
            self.button_action.value = "pan/zoom"  # tool_actions[-1]
            if len(self.tools) == 1:
                tools = []
            # self._main_widget_1.children += (self.button_reset,)
            self._main_widget_1.children += (self.button_action, )
            self._main_widget_1.children += (self.button_select_nothing, )
            # self._main_widget_2.children += (self.button_selection_mode,)
        self._main_widget.children = [self._main_widget_1, self._main_widget_2]
        self.control_widget.children += (self._main_widget, )
        self._update_grid_counter = 0  # keep track of t
        self._update_grid_counter_scheduled = 0  # keep track of t
Ejemplo n.º 7
0
    def create_tools(self):
        self.tools = []
        self.tool_actions = []
        tool_actions_map = dict()

        if 1:  # tool_select:
            #### initiaite the 4 types of zoom brushes, which should only highlight axis that are not locked ###
            self.zoom_brush_full = bqplot.interacts.BrushSelector(
                x_scale=self.scale_x, y_scale=self.scale_y, color="blue")
            self.zoom_brush_full.observe(self.update_zoom_brush_full,
                                         ["brushing"])

            self.zoom_brush_vertical = bqplot.interacts.BrushIntervalSelector(
                scale=self.scale_y, orientation='vertical', color="blue")
            self.zoom_brush_vertical.observe(self.update_zoom_brush_vertical,
                                             ["brushing"])

            self.zoom_brush_horizontal = bqplot.interacts.BrushIntervalSelector(
                scale=self.scale_x, orientation='horizontal', color="blue")
            self.zoom_brush_horizontal.observe(
                self.update_zoom_brush_horizontal, ["brushing"])

            self.zoom_brush_none = bqplot.interacts.BrushSelector(
                x_scale=self.scale_x, y_scale=self.scale_y, color="gray")
            self.zoom_brush_none.observe(self.update_zoom_brush_none,
                                         ["brushing"])

            # initiaite measurement tool
            self.ruler = bqplot.interacts.BrushSelector(x_scale=self.scale_x,
                                                        y_scale=self.scale_y,
                                                        color="blue")
            self.ruler.observe(self.measure_selected_area, ["brushing"])
            #### Set the default initial tools ####
            self.zoom_brush = self.zoom_brush_full
            self.click_brush = None  # use regular mouse
            self.click_brush_in = None
            self.click_brush_out = None

            tool_actions_map[ZOOM_SELECT] = self.zoom_brush
            tool_actions_map[PAN_ZOOM] = self.panzoom
            tool_actions_map[CLICK_ZOOM_IN] = self.click_brush_in
            tool_actions_map[CLICK_ZOOM_OUT] = self.click_brush_out
            tool_actions_map[RULER] = self.ruler
            self.tool_actions = [
                PAN_ZOOM, ZOOM_SELECT, CLICK_ZOOM_IN, CLICK_ZOOM_OUT, RULER
            ]

            self.start_limits = copy.deepcopy(self.limits)

            def change_interact(*args):
                with self.output:
                    name = self.tool_actions[self.interaction_tooltips.v_model]
                    self.figure.interaction = tool_actions_map[name]
                    if name == RULER:
                        self.plot.model.legend.openMeasurementPanel()

            self.interaction_tooltips = \
                v.BtnToggle(v_model=0, mandatory=True, multiple=False, children=[
                                v.Tooltip(bottom=True, v_slots=[{
                                    'name': 'activator',
                                    'variable': 'tooltip',
                                    'children': v.Btn(v_on='tooltip.on', children=[
                                        v.Icon(children=['pan_tool'])
                                    ])
                                }], children=[PAN_ZOOM]),
                                v.Tooltip(bottom=True, v_slots=[{
                                    'name': 'activator',
                                    'variable': 'tooltip',
                                    'children': v.Btn(v_on='tooltip.on', children=[
                                        v.Icon(children=['crop'])
                                    ])
                                }], children=[ZOOM_SELECT]),
                                v.Tooltip(bottom=True, v_slots=[{
                                    'name': 'activator',
                                    'variable': 'tooltip',
                                    'children': v.Btn(v_on='tooltip.on', children=[
                                        v.Icon(
                                            children=['mdi-magnify-plus-cursor'])
                                    ])
                                }], children=[CLICK_ZOOM_IN]),
                                v.Tooltip(bottom=True, v_slots=[{
                                    'name': 'activator',
                                    'variable': 'tooltip',
                                                'children': v.Btn(v_on='tooltip.on', children=[
                                                    v.Icon(
                                                        children=['mdi-magnify-minus-cursor'])
                                                ])
                                }], children=[CLICK_ZOOM_OUT]),
                                v.Tooltip(bottom=True, v_slots=[{
                                    'name': 'activator',
                                    'variable': 'tooltip',
                                    'children': v.Btn(v_on='tooltip.on', children=[
                                        v.Icon(children=['mdi-ruler'])
                                    ])
                                }], children=[RULER])      # ruler
                            ])
            self.interaction_tooltips.observe(change_interact, "v_model")

            def reset(*args):
                (x1, x2), (y1, y2) = self.start_limits
                self.zoom_sel(x1, x2, y1, y2, smart_zoom=True)
                with self.zoom_brush.hold_trait_notifications():
                    self.zoom_brush.selected_x = None
                    self.zoom_brush.selected_y = None
                    self.zoom_brush.selected = None

            self.screenshot_btn = v.Btn(
                v_on='tooltip.on',
                icon=True,
                children=[v.Icon(children=['mdi-camera'])])
            self.screenshot_tooltip = v.Tooltip(bottom=True,
                                                v_slots=[{
                                                    'name':
                                                    'activator',
                                                    'variable':
                                                    'tooltip',
                                                    'children':
                                                    self.screenshot_btn
                                                }],
                                                children=[SCREENSHOT])

            @debounced(0.5)
            def screenshot():
                def peer(a):
                    print(type(a).__name__)
                    print(type(a).__module__)
                    print(dir(a))

                #display(self.pil_image_test)
                # print(self.core_image.value)
                #peer(self.figure)
                #self.figure.save_png("test.png")
                #display(IPyImage("test.png"))
                #display(self.core.image)
                clear_output(wait=True)
                self.plot.model.plot.show()
                display(IPyImage(self.core_image.value))

            self.screenshot_btn.on_event('click', lambda *ignore: screenshot())
            self.reset_btn = v.Btn(v_on='tooltip.on',
                                   icon=True,
                                   children=[v.Icon(children=['refresh'])])
            self.reset_btn.on_event('click', lambda *ignore: reset())
            self.reset_tooltip = v.Tooltip(bottom=True,
                                           v_slots=[{
                                               'name': 'activator',
                                               'variable': 'tooltip',
                                               'children': self.reset_btn
                                           }],
                                           children=[RESET_ZOOM])

            self.undo_btn = v.Btn(v_on='tooltip.on',
                                  icon=True,
                                  disabled=True,
                                  children=[v.Icon(children=['undo'])])
            self.undo_tooltip = v.Tooltip(bottom=True,
                                          v_slots=[{
                                              'name': 'activator',
                                              'variable': 'tooltip',
                                              'children': self.undo_btn
                                          }],
                                          children=[UNDO])

            self.redo_btn = v.Btn(v_on='tooltip.on',
                                  icon=True,
                                  disabled=True,
                                  children=[v.Icon(children=['redo'])])
            self.redo_tooltip = v.Tooltip(bottom=True,
                                          v_slots=[{
                                              'name': 'activator',
                                              'variable': 'tooltip',
                                              'children': self.redo_btn
                                          }],
                                          children=[REDO])

            @debounced(0.5)
            def undo_redo(*args):
                self.curr_action = args[0]
                (x1, x2), (y1, y2) = args[1][-1]
                with self.scale_x.hold_trait_notifications():
                    with self.scale_y.hold_trait_notifications():
                        self.scale_x.min, self.scale_x.max = x1, x2
                        self.scale_y.min, self.scale_y.max = y1, y2

            self.undo_btn.on_event(
                'click',
                lambda *ignore: undo_redo(Action.undo, self.undo_actions))
            self.redo_btn.on_event(
                'click',
                lambda *ignore: undo_redo(Action.redo, self.redo_actions))

            control_lyt = widgets.Layout(width='100px')
            self.control_x = widgets.Checkbox(value=False,
                                              description='Lock X Axis',
                                              indent=False,
                                              layout=control_lyt)
            self.control_y = widgets.Checkbox(value=False,
                                              description='Lock Y Axis',
                                              indent=False,
                                              layout=control_lyt)

            def axis_lock_update(checkbox):
                ####### Only allows one checkbox to be locked at a time ######
                if checkbox['owner'].description == self.control_x.description:
                    if self.control_y.value:
                        self.control_y.value = False

                if checkbox['owner'].description == self.control_y.description:
                    if self.control_x.value:
                        self.control_x.value = False
                ##############################################################
                # When a axis checkbox is locked.
                # Updates the panzoom tool to lock eithier the x or y axis.
                # Also updates the zoombrush tool to use relevant zoom brush
                if self.control_x.value:
                    if self.control_y.value:
                        self.panzoom = bqplot.PanZoom()
                        self.zoom_brush = self.zoom_brush_none
                    else:
                        self.panzoom = bqplot.PanZoom(
                            scales={'y': [self.scale_y]})
                        self.zoom_brush = self.zoom_brush_vertical
                else:
                    if self.control_y.value:
                        self.panzoom = bqplot.PanZoom(
                            scales={'x': [self.scale_x]})
                        self.zoom_brush = self.zoom_brush_horizontal
                    else:
                        self.panzoom = bqplot.PanZoom(scales={
                            'x': [self.scale_x],
                            'y': [self.scale_y]
                        })
                        self.zoom_brush = self.zoom_brush_full

                tool_actions_map[PAN_ZOOM] = self.panzoom
                tool_actions_map[ZOOM_SELECT] = self.zoom_brush

                # Update immediately if in PAN_ZOOM mode
                name = self.tool_actions[self.interaction_tooltips.v_model]
                if name == PAN_ZOOM:
                    self.figure.interaction = self.panzoom
                elif name == ZOOM_SELECT:
                    self.figure.interaction = self.zoom_brush

            self.control_x.observe(axis_lock_update)
            self.control_y.observe(axis_lock_update)
            self.axis_controls = widgets.VBox([self.control_x, self.control_y])

            self.tooltips = v.Row(children=[
                self.axis_controls, self.interaction_tooltips,
                self.reset_tooltip, self.undo_tooltip, self.redo_tooltip,
                self.screenshot_tooltip
            ],
                                  align='center',
                                  justify='center')
            self.plot.add_to_toolbar(self.tooltips)
Ejemplo n.º 8
0
    def init_widgets(self):
        # Primary checkboxes
        read_hit = ChildCheckbox(self.compute_all, READ_HIT, 1)
        write_hit = ChildCheckbox(self.compute_all, WRITE_HIT, 2)
        read_capmiss = ChildCheckbox(self.compute_all, READ_MISS, 4)
        write_capmiss = ChildCheckbox(self.compute_all, WRITE_MISS, 5)
        read_compmiss = ChildCheckbox(self.compute_all, COMP_R_MISS, 6)
        write_compmiss = ChildCheckbox(self.compute_all, COMP_W_MISS, 8)
        chks = [read_hit, write_hit, read_capmiss,
                write_capmiss, read_compmiss, write_compmiss]
        self.checkboxes = chks


        # Parent checkboxes
        self.all_check = ParentCheckbox(chks, self.compute_all, label = 'All', tooltip="Show All")
        self.read_check = ParentCheckbox([read_hit, read_capmiss, read_compmiss], self.compute_all, 
                                         label='Reads', tooltip="Reads")
        self.write_check = ParentCheckbox([write_hit, write_capmiss, write_compmiss], self.compute_all, 
                                          label='Writes', tooltip="Writes")
        self.hit_check = ParentCheckbox([read_hit, write_hit], self.compute_all, 
                                          label='Hits', tooltip="Hits")
        self.capmiss_check = ParentCheckbox([read_capmiss, write_capmiss], self.compute_all, 
                                             label='Capacity Misses', tooltip="Capacity Misses")
        self.compmiss_check = ParentCheckbox([read_compmiss, write_compmiss], self.compute_all, 
                                              label='Compuls Misses', tooltip="Compulsory Misses")
        self.parentcheckboxes = [self.all_check, self.read_check, self.write_check, 
                self.hit_check, self.capmiss_check, self.compmiss_check]

        def parentbox(check):
            return HBox([check.widget], layout=Layout(align_items="center", overflow="hidden", justify_content="center"))

        def clr_picker(clr, cache=False):
            if cache:
                clr_picker = ColorPicker(concise=True, value=to_hex(self.colormap[clr][0:3]), 
                        disabled=False, layout=Layout(width="30px"))
            else:
                clr_picker = ColorPicker(concise=True, value=to_hex(self.colormap[clr][0:3]), 
                        disabled=False, layout=Layout(width="25px", margin="0 0 0 8px"))
            clr_picker.observing = True
            def handle_color_picker(change):
                self.colormap[clr] = to_rgba(change.new, 1)
                self.model.plot.colormap = ListedColormap(self.colormap)
                self.model.plot.backend.plot._update_image()
            clr_picker.observe(handle_color_picker, names='value')
            self.colorpickers[clr] = clr_picker
            return clr_picker

        def primbox(check):
            return HBox([check.widget, clr_picker(check.clr)],
                layout=Layout(justify_content="center",align_items="center",overflow="hidden"))

        # Wrap parent boxes in ipywidget
        alls = parentbox(self.all_check)

        read = parentbox(self.read_check)
        write = parentbox(self.write_check)

        hits = parentbox(self.hit_check)
        capmisses = parentbox(self.capmiss_check)
        compmisses = parentbox(self.compmiss_check)

        # Add pseudo grid and wrap primary boxes in ipywidget
        gridbox = HBox([GridBox([alls, vdiv, read, vdiv, write,
                                 hdiv, hdiv, hdiv, hdiv, hdiv,
                                 hits, vdiv, primbox(read_hit), lvdiv, primbox(write_hit),
                                 hdiv, hdiv, lhdiv, lhdiv, lhdiv,
                                 capmisses, vdiv, primbox(read_capmiss), lvdiv, primbox(write_capmiss),
                                 hdiv, hdiv, lhdiv, lhdiv, lhdiv,
                                 compmisses, vdiv, primbox(read_compmiss), lvdiv, primbox(write_compmiss)],
                                layout=Layout(grid_template_rows="50px 2px 50px 2px 50px 2px 50px", grid_template_columns="100px 5px 100px 5px 100px"))], layout=Layout(padding="0 0 0 14px"))

        cache_icon = v.Icon(children=['fa-database'], v_on='tooltip.on')
        cache_icon_tp = v.Tooltip(bottom=True, v_slots=[{'name': 'activator', 'variable': 'tooltip', 'children': cache_icon}], children=["Cache"])

        cache_clrpkr = clr_picker(3, cache=True)

        reset_clrs = v.Btn(v_on='tooltip.on', icon=True, children=[v.Icon(children=['refresh'])])
        reset_clrs.on_event('click', self.reset_colormap)
        reset_clrs_tp = v.Tooltip(bottom=True, v_slots=[{'name': 'activator', 'variable': 'tooltip', 'children': reset_clrs}], children=["Reset all colors"])
        cache_row = HBox([cache_icon_tp, cache_clrpkr, reset_clrs_tp],
                        layout=Layout(padding="0 20px 20px 20px", align_items="center", justify_content="space-between"))
        cache_row
        return VBox([gridbox, cache_row])
Ejemplo n.º 9
0
    def create_tools(self):
        self.tools = []
        tool_actions = []
        tool_actions_map = dict()

        if 1:  # tool_select:
            self.zoom_brush = bqplot.interacts.BrushSelector(
                x_scale=self.scale_x, y_scale=self.scale_y, color="blue")
            self.zoom_brush.observe(self.update_zoom_brush, ["brushing"])
            self.click_brush = None  # use regular mouse
            tool_actions_map[ZOOM_SELECT] = self.zoom_brush
            tool_actions_map[PAN_ZOOM] = self.panzoom
            tool_actions_map[CLICK_ZOOM] = self.click_brush
            tool_actions = [PAN_ZOOM, ZOOM_SELECT, CLICK_ZOOM]

            self.start_limits = copy.deepcopy(self.limits)

            def change_interact(*args):
                with self.output:
                    name = tool_actions[self.interaction_tooltips.v_model]
                    self.figure.interaction = tool_actions_map[name]

            self.interaction_tooltips = \
                v.BtnToggle(v_model=0, mandatory=True, multiple=False, children=[
                                v.Tooltip(bottom=True, v_slots=[{
                                    'name': 'activator',
                                    'variable': 'tooltip',
                                    'children': v.Btn(v_on='tooltip.on', children=[
                                        v.Icon(children=['pan_tool'])
                                    ])
                                }], children=[PAN_ZOOM]),
                                v.Tooltip(bottom=True, v_slots=[{
                                    'name': 'activator',
                                    'variable': 'tooltip',
                                    'children': v.Btn(v_on='tooltip.on', children=[
                                        v.Icon(children=['crop'])
                                    ])
                                }], children=[ZOOM_SELECT]),
                                v.Tooltip(bottom=True, v_slots=[{
                                    'name': 'activator',
                                    'variable': 'tooltip',
                                    'children': v.Btn(v_on='tooltip.on', children=[
                                        v.Icon(children=['mdi-mouse'])
                                    ])
                                }], children=[CLICK_ZOOM])
                            ])
            self.interaction_tooltips.observe(change_interact, "v_model")

            def reset(*args):
                (x1, x2), (y1, y2) = self.start_limits
                self.zoom_sel(x1, x2, y1, y2, smart_zoom=True)
                with self.zoom_brush.hold_trait_notifications():
                    self.zoom_brush.selected_x = None
                    self.zoom_brush.selected_y = None

            self.reset_btn = v.Btn(v_on='tooltip.on',
                                   icon=True,
                                   children=[v.Icon(children=['refresh'])])
            self.reset_btn.on_event('click', lambda *ignore: reset())
            self.reset_tooltip = v.Tooltip(bottom=True,
                                           v_slots=[{
                                               'name': 'activator',
                                               'variable': 'tooltip',
                                               'children': self.reset_btn
                                           }],
                                           children=[RESET_ZOOM])

            self.undo_btn = v.Btn(v_on='tooltip.on',
                                  icon=True,
                                  disabled=True,
                                  children=[v.Icon(children=['undo'])])
            self.undo_tooltip = v.Tooltip(bottom=True,
                                          v_slots=[{
                                              'name': 'activator',
                                              'variable': 'tooltip',
                                              'children': self.undo_btn
                                          }],
                                          children=[UNDO])
            self.redo_btn = v.Btn(v_on='tooltip.on',
                                  icon=True,
                                  disabled=True,
                                  children=[v.Icon(children=['redo'])])
            self.redo_tooltip = v.Tooltip(bottom=True,
                                          v_slots=[{
                                              'name': 'activator',
                                              'variable': 'tooltip',
                                              'children': self.redo_btn
                                          }],
                                          children=[REDO])

            @debounced(0.5)
            def undo_redo(*args):
                self.curr_action = args[0]
                (x1, x2), (y1, y2) = args[1][-1]
                with self.scale_x.hold_trait_notifications():
                    with self.scale_y.hold_trait_notifications():
                        self.scale_x.min, self.scale_x.max = x1, x2
                        self.scale_y.min, self.scale_y.max = y1, y2

            self.undo_btn.on_event(
                'click',
                lambda *ignore: undo_redo(Action.undo, self.undo_actions))
            self.redo_btn.on_event(
                'click',
                lambda *ignore: undo_redo(Action.redo, self.redo_actions))

            control_lyt = widgets.Layout(width='40px')
            self.panzoom_x = control_x = widgets.Checkbox(value=True,
                                                          description='X',
                                                          indent=False,
                                                          layout=control_lyt)
            self.panzoom_y = control_y = widgets.Checkbox(value=True,
                                                          description='Y',
                                                          indent=False,
                                                          layout=control_lyt)

            def update_panzoom(checkbox):
                if control_x.value:
                    if control_y.value:
                        self.panzoom = bqplot.PanZoom(scales={
                            'x': [self.scale_x],
                            'y': [self.scale_y]
                        })
                    else:
                        self.panzoom = bqplot.PanZoom(
                            scales={'x': [self.scale_x]})
                else:
                    if control_y.value:
                        self.panzoom = bqplot.PanZoom(
                            scales={'y': [self.scale_y]})
                    else:
                        self.panzoom = bqplot.PanZoom()
                tool_actions_map[PAN_ZOOM] = self.panzoom
                # Update immediately if in PAN_ZOOM mode
                name = tool_actions[self.interaction_tooltips.v_model]
                if name == PAN_ZOOM:
                    self.figure.interaction = self.panzoom

            self.panzoom_x.observe(update_panzoom)
            self.panzoom_y.observe(update_panzoom)
            self.panzoom_controls = widgets.VBox(
                [self.panzoom_x, self.panzoom_y])

            self.tooltips = v.Row(children=[
                self.panzoom_controls, self.interaction_tooltips,
                self.reset_tooltip, self.undo_tooltip, self.redo_tooltip
            ],
                                  align='center',
                                  justify='center')
            self.plot.add_to_toolbar(self.tooltips)