Exemple #1
0
    def lightcurve_widget(self):
        '''Create light curve widget'''
        xax = bq.Axis(label='Time (MJD)',
                      scale=self.sc_x,
                      grid_lines='solid',
                      label_location="middle")
        xax.tick_style = {'stroke': 'black', 'font-size': 12}

        yax = bq.Axis(label='Magnitude',
                      scale=self.sc_y,
                      orientation='vertical',
                      tick_format='0.1f',
                      grid_lines='solid',
                      label_location="middle")
        yax.tick_style = {'stroke': 'black', 'font-size': 12}

        panzoom = bq.PanZoom(scales={'x': [self.sc_x], 'y': [self.sc_y]})
        return bq.Figure(
            axes=[xax, yax],
            marks=[],
            layout=Layout(width='100%', height='auto'),
            fig_margin={
                'top': 0,
                'bottom': 40,
                'left': 50,
                'right': 0
            },
            legend_location='top-right',
        )
Exemple #2
0
            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
Exemple #3
0
 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
Exemple #4
0
def create_plot():
    index = pd.date_range(start='2000-06-01', end='2001-06-01',
                          freq='30min') + timedelta(minutes=15)
    s = pd.Series(np.full(len(index), np.nan), index=index)

    x = index.values
    y = s

    x_sc = bq.DateScale()
    y_sc = bq.LinearScale(min=0)

    line = bq.Lines(
        x=x,
        y=y,
        scales={
            'x': x_sc,
            'y': y_sc
        },
        #display_legend=True, labels=["line 1"],
        #fill='bottom', # opacity does work with this option
        #fill_opacities = [0.5] *len(x)
    )

    panzoom = bq.PanZoom(scales={'x': [x_sc], 'y': [y_sc]})
    #p = bq.Scatter(x=x, y=y, scales= {'x': x_sc, 'y': y_sc})
    ax_x = bq.Axis(scale=x_sc)
    ax_y = bq.Axis(scale=y_sc, orientation='vertical', tick_format='0.2f')

    #fig = bq.Figure(marks=[line, p], axes=[ax_x, ax_y])
    fig = bq.Figure(marks=[line], axes=[ax_x, ax_y], interaction=panzoom)
    fig.layout.width = '95%'

    #p.interactions = {'click': 'select', 'hover': 'tooltip'}
    #p.selected_style = {'opacity': 1.0, 'fill': 'DarkOrange', 'stroke': 'Red'}
    #p.unselected_style = {'opacity': 0.5}
    #p.tooltip = bq.Tooltip(fields=['x', 'y'], formats=['', '.2f'])

    #sel = bq.interacts.IndexSelector(scale=p.scales['x'])
    #
    #def update_range(*args):
    #    if sel.selected:
    #        print(sel.selected[0])
    #
    #sel.observe(update_range, 'selected')
    #fig.interaction = sel

    return fig, line
Exemple #5
0
    def __init__(self, zoom_y=True, **kwargs):
        super().__init__(**kwargs)
        self.x_scale = bqplot.LinearScale(allow_padding=False)
        self.y_scale = bqplot.LinearScale(allow_padding=False)
        widgets.link((self, 'x_min'), (self.x_scale, 'min'))
        widgets.link((self, 'x_max'), (self.x_scale, 'max'))
        widgets.link((self, 'y_min'), (self.y_scale, 'min'))
        widgets.link((self, 'y_max'), (self.y_scale, 'max'))

        self.x_axis = bqplot.Axis(scale=self.x_scale)
        self.y_axis = bqplot.Axis(scale=self.y_scale, orientation='vertical')
        widgets.link((self, 'x_label'), (self.x_axis, 'label'))
        widgets.link((self, 'y_label'), (self.y_axis, 'label'))
        self.x_axis.color = blackish
        self.y_axis.color = blackish
        self.x_axis.label_color = blackish
        self.y_axis.label_color = blackish
        # self.y_axis.tick_style = {'fill': blackish, 'stroke':'none'}
        self.y_axis.grid_color = blackish
        self.x_axis.grid_color = blackish
        self.x_axis.label_offset = "2em"
        self.y_axis.label_offset = "3em"
        self.x_axis.grid_lines = 'none'
        self.y_axis.grid_lines = 'none'

        self.axes = [self.x_axis, self.y_axis]
        self.scales = {'x': self.x_scale, 'y': self.y_scale}

        self.figure = bqplot.Figure(axes=self.axes)
        self.figure.background_style = {'fill': 'none'}
        self.figure.padding_y = 0
        self.figure.fig_margin = {'bottom': 40, 'left': 60, 'right': 10, 'top': 10}

        self.interacts = {}
        self.interacts['pan-zoom'] = bqplot.PanZoom(scales={'x': [self.x_scale], 'y': [self.y_scale] if zoom_y else []})
        self.interacts['select-rect'] = bqplot.interacts.BrushSelector(x_scale=self.x_scale, y_scale=self.y_scale, color="green")
        self.interacts['select-x'] = bqplot.interacts.BrushIntervalSelector(scale=self.x_scale, color="green")
        self._brush = self.interacts['select-rect']
        self._brush_interval = self.interacts['select-x']

        # TODO: put the debounce in the presenter?
        @vaex.jupyter.debounced(DEBOUNCE_SELECT)
        def update_brush(*args):
            with self.output:
                if not self._brush.brushing:  # if we ended _brushing, reset it
                    self.figure.interaction = None
                if self._brush.selected is not None:
                    x1, x2 = self._brush.selected_x
                    y1, y2 = self._brush.selected_y
                    # (x1, y1), (x2, y2) = self._brush.selected
                    # mode = self.modes_names[self.modes_labels.index(self.button_selection_mode.value)]
                    self.presenter.select_rectangle(x1, x2, y1, y2)
                else:
                    self.presenter.select_nothing()
                if not self._brush.brushing:  # but then put it back again so the rectangle is gone,
                    self.figure.interaction = self._brush

        self._brush.observe(update_brush, ["selected", "selected_x"])

        @vaex.jupyter.debounced(DEBOUNCE_SELECT)
        def update_brush(*args):
            with self.output:
                if not self._brush_interval.brushing:  # if we ended _brushing, reset it
                    self.figure.interaction = None
                if self._brush_interval.selected is not None and len(self._brush_interval.selected):
                    x1, x2 = self._brush_interval.selected
                    self.presenter.select_x_range(x1, x2)
                else:
                    self.presenter.select_nothing()
                if not self._brush_interval.brushing:  # but then put it back again so the rectangle is gone,
                    self.figure.interaction = self._brush_interval

        self._brush_interval.observe(update_brush, ["selected"])

        def tool_change(change=None):
            self.figure.interaction = self.interacts.get(self.tool, None)
        self.observe(tool_change, 'tool')
        self.widget = self.figure
Exemple #6
0
    def create_widget(self, output, plot, dataset, limits):
        self.plot = plot
        self.output = output
        self.dataset = dataset
        self.limits = np.array(limits).tolist()

        def fix(v):
            # bqplot is picky about float and numpy scalars
            if hasattr(v, 'item'):
                return v.item()
            else:
                return v

        self.scale_x = bqplot.LinearScale(min=fix(limits[0][0]),
                                          max=fix(limits[0][1]),
                                          allow_padding=False)
        self.scale_y = bqplot.LinearScale(min=fix(limits[1][0]),
                                          max=fix(limits[1][1]),
                                          allow_padding=False)
        self.scales = {'x': self.scale_x, 'y': self.scale_y}

        self.figure = plt.figure(self.figure_key,
                                 fig=self.figure,
                                 scales=self.scales)
        self.figure.layout.width = 'calc(100% - 400px)'
        self.figure.layout.min_height = '800px'
        plt.figure(fig=self.figure)
        #self.figure.padding_y = 0
        x = np.arange(0, 10)
        y = x**2
        self.core_image = widgets.Image(format='png')
        self.core_image_fix = widgets.Image(format='png')

        self.image = bqplot.Image(scales=self.scales, image=self.core_image)
        # triggered by regular mouse click not a brush selector
        self.image.on_element_click(self.click_to_zoom)

        self.figure.marks = self.figure.marks + [self.image]
        self.scatter = s = plt.scatter(x,
                                       y,
                                       visible=False,
                                       rotation=x,
                                       scales=self.scales,
                                       size=x,
                                       marker="arrow")
        self.panzoom = bqplot.PanZoom(scales={
            'x': [self.scale_x],
            'y': [self.scale_y]
        })
        self.figure.interaction = self.panzoom
        for axes in self.figure.axes:
            axes.grid_lines = 'none'
            axes.color = axes.grid_color = axes.label_color = blackish
        self.figure.axes[0].label = plot.x_label
        self.figure.axes[1].label = plot.y_label
        self.figure.axes[1].scale = bqplot.LinearScale(min=0,
                                                       max=self.scale_y.max -
                                                       self.scale_y.min,
                                                       allow_padding=False)
        self.stuck_ctr = 0

        self.base_address = widgets.Label(
            value=f"Base address: 0x{int(self.limits[1][0]):X}")
        self.zoom_args = widgets.Text(description="Zoom Args",
                                      value=self.zoom_args_string(),
                                      disabled=True,
                                      style={'description_width': 'initial'},
                                      layout=widgets.Layout(width='50%'))

        self.curr_action = Action.other
        self.undo_actions = list()
        self.redo_actions = list()
        self.counter = 2
        self.scale_x.observe(self._update_limits)
        self.scale_y.observe(self._update_limits)
        self.widget = widgets.VBox(
            [self.figure, self.base_address, self.zoom_args])
        self.create_tools()
Exemple #7
0
    def __init__(self, session):
        super(BqplotBaseView, self).__init__(session)
        # session.hub.subscribe(self, SubsetCreateMessage,
        #                       handler=self.receive_message)
        self.state = self._state_cls()

        # if we allow padding, we sometimes get odd behaviour with the interacts
        self.scale_x = bqplot.LinearScale(min=0, max=1, allow_padding=False)
        self.scale_y = bqplot.LinearScale(min=0, max=1)
        self.scales = {'x': self.scale_x, 'y': self.scale_y}
        self.axis_x = bqplot.Axis(
            scale=self.scale_x, grid_lines='solid', label='x')
        self.axis_y = bqplot.Axis(scale=self.scale_y, orientation='vertical', tick_format='0.2f',
                                  grid_lines='solid', label='y')
        def update_axes(*ignore):
            self.axis_x.label = str(self.state.x_att)
            if self.is2d:
                self.axis_y.label = str(self.state.y_att)
        self.state.add_callback('x_att', update_axes)
        if self.is2d:
            self.state.add_callback('y_att', update_axes)
        self.figure = bqplot.Figure(scales=self.scales, animation_duration=0, axes=[
                                    self.axis_x, self.axis_y])
        self.figure.padding_y = 0
        
        actions = ['move']
        self.interact_map = {}
        self.panzoom = bqplot.PanZoom(scales={'x': [self.scale_x], 'y': [self.scale_y]})
        self.interact_map['move'] = self.panzoom

        if self.is2d:
            self.brush = bqplot.interacts.BrushSelector(x_scale=self.scale_x, y_scale=self.scale_y, color="green")
            self.interact_map['brush'] = self.brush
            self.brush.observe(self.update_brush, "brushing")
            actions.append('brush')

        self.brush_x = bqplot.interacts.BrushIntervalSelector(scale=self.scale_x, color="green" )
        self.interact_map['brush x'] = self.brush_x
        self.brush_x.observe(self.update_brush_x, "brushing")
        actions.append('brush x')

        if self.is2d:
            self.brush_y = bqplot.interacts.BrushIntervalSelector(scale=self.scale_y, color="green", orientation='vertical')
            self.interact_map['brush y'] = self.brush_y
            self.brush_y.observe(self.update_brush_y, "brushing")
            actions.append('brush y')


        self.button_action = widgets.ToggleButtons(description='Mode: ', options=[(action, action) for action in actions],
                                                   icons=["arrows", "pencil-square-o"])
        self.button_action.observe(self.change_action, "value")
        self.change_action()  # 'fire' manually for intial value

#         self.state.add_callback('y_att', self._update_axes)
#         self.state.add_callback('x_log', self._update_axes)
#         self.state.add_callback('y_log', self._update_axes)

        self.state.add_callback('x_min', self.limits_to_scales)
        self.state.add_callback('x_max', self.limits_to_scales)
        self.state.add_callback('y_min', self.limits_to_scales)
        self.state.add_callback('y_max', self.limits_to_scales)

        self.create_tab()
        self.output_widget = widgets.Output()
        self.main_widget = widgets.VBox(
            children=[self.tab, self.figure, self.output_widget])
Exemple #8
0
def plot_signals_low_freq(data, v, w_j, n_days=60):
    signals_dict = signals_low_freq(data, w_j, n_days)
    signals_df = pd.DataFrame(signals_dict, index=["High Freq Signals"]).T

    pos_signals_date, neg_signals_date, exit_signals_date = entry_exit(
        signals_df)

    x_ord = bqplot.DateScale()
    y_sc = bqplot.LinearScale()

    line = bqplot.Lines(x=data.index,
                        y=data.values.squeeze(),
                        scales={
                            'x': x_ord,
                            'y': y_sc
                        },
                        stroke_width=2,
                        display_legend=False,
                        labels=['Underlying TS'])
    scatter1 = bqplot.Scatter(x=pd.DatetimeIndex(pos_signals_date),
                              y=data.loc[pos_signals_date].squeeze(),
                              colors=["green"],
                              scales={
                                  'x': x_ord,
                                  'y': y_sc
                              },
                              marker='triangle-up',
                              default_size=25)
    scatter2 = bqplot.Scatter(x=pd.DatetimeIndex(neg_signals_date),
                              y=data.loc[neg_signals_date].squeeze(),
                              colors=["red"],
                              scales={
                                  'x': x_ord,
                                  'y': y_sc
                              },
                              marker='triangle-down',
                              default_size=25)
    scatter3 = bqplot.Scatter(x=pd.DatetimeIndex(exit_signals_date),
                              y=data.loc[exit_signals_date].squeeze(),
                              colors=["white"],
                              scales={
                                  'x': x_ord,
                                  'y': y_sc
                              },
                              marker='square',
                              default_size=25)
    ax_x = bqplot.Axis(scale=x_ord)
    ax_y = bqplot.Axis(scale=y_sc,
                       orientation='vertical',
                       tick_format='0.2f',
                       grid_lines='solid')

    fig = bqplot.Figure(marks=[line, scatter1, scatter2, scatter3],
                        axes=[ax_x, ax_y])
    pz = bqplot.PanZoom(scales={'x': [x_ord], 'y': [y_sc]})
    pzx = bqplot.PanZoom(scales={'x': [x_ord]})
    pzy = bqplot.PanZoom(scales={
        'y': [y_sc],
    })

    #
    """zoom_interacts = ToggleButtons(
                                            options=OrderedDict([
                                                ('xy ', pz), 
                                                ('x ', pzx), 
                                                ('y ', pzy),   
                                                (' ', None)]),
                                                icons = ["arrows", "arrows-h", "arrows-v", "stop"],
                                                tooltips = ["zoom/pan in x & y", "zoom/pan in x only", "zoom/pan in y only", "cancel zoom/pan"]
                                            )
    zoom_interacts.style.button_width = '50px'

    ResetZoomButton = Button(
        description='',
        disabled=False,
        button_style='', # 'success', 'info', 'warning', 'danger' or ''
        tooltip='Reset zoom',
        icon='arrows-alt'
    )"""
    def resetZoom(new):
        # Reset the x and y axes on the figure
        fig.axes[0].scale.min = None
        fig.axes[1].scale.min = None
        fig.axes[0].scale.max = None
        fig.axes[1].scale.max = None

    ResetZoomButton.on_click(resetZoom)
    ResetZoomButton.layout.width = '95%'

    link((zoom_interacts, 'value'), (fig, 'interaction'))
    display(fig, zoom_interacts)
Exemple #9
0
	def plot_bq(self, grid=None, size=256, limits=None, square=False, center=None, weight=None, figsize=None,
			 aspect="auto", f="identity", fig=None, axes=None, xlabel=None, ylabel=None, title=None,
			 group_by=None, group_limits=None, group_colors='jet', group_labels=None, group_count=None,
			 cmap="afmhot", scales=None, tool_select=False, bq_cleanup=True,
			 **kwargs):
		import vaex.ext.bqplot
		import bqplot.interacts
		import bqplot.pyplot as p
		import ipywidgets as widgets
		import bqplot as bq
		f = _parse_f(f)
		limits = self.limits(limits)
		import vaex.ext.bqplot
		vaex.ext.bqplot.patch()
		if not hasattr(self, "_bqplot"):
			self._bqplot = {}
			self._bqplot["cleanups"] = []
		else:
			if bq_cleanup:
				for cleanup in self._bqplot["cleanups"]:
					cleanup()
			self._bqplot["cleanups"] = []
		if limits is None:
			limits = self.limits_sigma()
		#if fig is None:
		if scales is None:
			x_scale = bq.LinearScale(min=limits[0][0], max=limits[0][1])
			y_scale = bq.LinearScale(min=limits[1][0], max=limits[1][1])
			scales = {'x': x_scale, 'y': y_scale}
		else:
			x_scale = scales["x"]
			y_scale = scales["y"]
		if 1:
			fig = p.figure() # actually, bqplot doesn't return it
			fig = p.current_figure()
			fig.fig_color = "black" # TODO, take the color from the colormap
			fig.padding_y = 0
			# if we don't do this, bqplot may flip some axes... report this bug
			x = np.arange(10)
			y = x**2
			p.plot(x, y, scales=scales)
			#p.xlim(*limits[0])
			#p.ylim(*limits[1])
			#if grid is None:
		if group_limits is None and group_by:
			group_limits = tuple(self.dataset(group_by).minmax()[0]) + (group_count,)
		#fig = p.
		#if xlabel:
		fig.axes[0].label = xlabel or self.expressions[0]
		#if ylabel:
		fig.axes[1].label = ylabel or self.expressions[1]
		if title:
			fig.title = title
		#axes.set_aspect(aspect)
		rgba8 = self.image_rgba(grid=grid, size=size, limits=limits, square=square, center=center, weight=weight,
			 f=f, axes=axes,
			 group_by=group_by, group_limits=group_limits, group_colors=group_colors, group_count=group_count,
			 cmap=cmap)
		#x_scale = p._context["scales"]["x"]
		#y_scale = p._context["scales"]["y"]
		src="http://localhost:8888/kernelspecs/python2/logo-64x64.png"
		import bqplot.marks
		im = vaex.ext.bqplot.Image(src=src, scales=scales, x=0, y=0, width=1, height=1)
		if 0:
			size = 20
			x_data = np.arange(size)
			line = bq.Lines(x=x_data, y=np.random.randn(size), scales={'x': x_scale, 'y': y_scale},
							stroke_width=3, colors=['red'])


			ax_x = bq.Axis(scale=x_scale, tick_format='0.2f', grid_lines='solid')
			ax_y = bq.Axis(scale=y_scale, orientation='vertical', tick_format='0.2f', grid_lines='solid')
			panzoom = bq.PanZoom(scales={'x': [x_scale], 'y': [y_scale]})
			lasso = bqplot.interacts.LassoSelector()
			brush = bqplot.interacts.BrushSelector(x_scale=x_scale, y_scale=y_scale, color="green")
			fig = bq.Figure(marks=[line,im], axes=[ax_x, ax_y], min_width=100, min_height=100, interaction=panzoom)
		else:
			fig.marks = list(fig.marks) + [im]
		def make_image(executor, limits):
			#print "make image" * 100
			self.executor = executor
			if self.dataset.has_selection():
				sub = self.selected()
			else:
				sub = self
			return sub.image_rgba(limits=limits, size=size, f=f)
		progress = widgets.FloatProgress(value=0.0, min=0.0, max=1.0, step=0.01)
		updater = vaex.ext.bqplot.DebouncedThreadedUpdater(self, size, im, make_image, progress_widget=progress)
		def update_image():
			limits = [x_scale.min, x_scale.max], [y_scale.min, y_scale.max]
			#\print limits
			#print "update...", limits
			#vxbq.debounced_threaded_update(self.dataset, im, make_image2, limits=limits)
			updater.update(limits)
		def update(*args):
			update_image()
		y_scale.observe(update, "min")
		y_scale.observe(update, "max")
		x_scale.observe(update, "min")
		x_scale.observe(update, "max")
		update_image()
		#fig = kwargs.pop('figure', p.current_figure())
		tools = []
		tool_actions = []
		panzoom = bq.PanZoom(scales={'x': [x_scale], 'y': [y_scale]})
		tool_actions_map = {u"m":panzoom}
		tool_actions.append(u"m")

		fig.interaction = panzoom
		if tool_select:
			brush = bqplot.interacts.BrushSelector(x_scale=x_scale, y_scale=y_scale, color="green")
			tool_actions_map["b"] = brush
			tool_actions.append("b")
			def update_selection(*args):
				def f():
					if brush.selected:
						(x1, y1), (x2, y2) = brush.selected
						ex1, ex2 = self.expressions
						mode = modes_names[modes_labels.index(button_selection_mode.value)]
						self.dataset.select_rectangle(ex1, ex2, limits=[[x1, x2], [y1, y2]], mode=mode)
					else:
						self.dataset.select_nothing()
				updater.update_select(f)
			brush.observe(update_selection, "selected")
			#fig.interaction = brush
			#callback = self.dataset.signal_selection_changed.connect(lambda dataset: update_image())
			callback = self.dataset.signal_selection_changed.connect(lambda dataset: updater.update_direct_safe())
			def cleanup(callback=callback):
				self.dataset.signal_selection_changed.disconnect(callback=callback)
			self._bqplot["cleanups"].append(cleanup)

			button_select_nothing = widgets.Button(icon="fa-trash-o")
			def select_nothing(button):
				self.dataset.select_nothing()
			button_select_nothing.on_click(select_nothing)
			tools.append(button_select_nothing)
			modes_names = "replace and or xor subtract".split()
			modes_labels = "= & | ^ -".split()
			button_selection_mode = widgets.ToggleButtons(description='',options=modes_labels)
			tools.append(button_selection_mode)
		def change_interact(*args):
			#print "change", args
			fig.interaction = tool_actions_map[button_action.value]
		#tool_actions = ["m", "b"]
		#tool_actions = [("m", "m"), ("b", "b")]
		button_action = widgets.ToggleButtons(description='',options=tool_actions, icons=["fa-arrows", "fa-pencil-square-o"])
		button_action.observe(change_interact, "value")
		tools.insert(0,button_action)
		button_action.value = "m" #tool_actions[-1]
		if len(tools) == 1:
			tools = []
		tools = widgets.HBox(tools)

		box_layout = widgets.Layout(display='flex',
						flex_flow='column',
						#border='solid',
						width='100%', height="100%")
		fig.fig_margin = {'bottom': 40, 'left': 60, 'right': 10, 'top': 40}
		#fig.min_height = 700
		#fig.min_width = 400
		fig.layout = box_layout
		return widgets.VBox([fig, progress, tools])