コード例 #1
0
ファイル: tabular.py プロジェクト: wyhzhbit/holoviews
 def _get_columns(self, element, data):
     columns = []
     for d in element.dimensions():
         col = dimension_sanitizer(d.name)
         kind = data[col].dtype.kind
         if kind == 'i':
             formatter = NumberFormatter()
             editor = IntEditor()
         elif kind == 'f':
             formatter = NumberFormatter(format='0,0.0[00000]')
             editor = NumberEditor()
         elif kind == 'M' or (kind == 'O' and len(data[col])
                              and type(data[col][0]) in datetime_types):
             dimtype = element.get_dimension_type(0)
             dformat = Dimension.type_formatters.get(
                 dimtype, '%Y-%m-%d %H:%M:%S')
             formatter = DateFormatter(format=dformat)
             editor = DateEditor()
         else:
             formatter = StringFormatter()
             editor = StringEditor()
         column = TableColumn(field=dimension_sanitizer(d.name),
                              title=d.pprint_label,
                              editor=editor,
                              formatter=formatter)
         columns.append(column)
     return columns
コード例 #2
0
def make_layout():
    import pandas as pd
    plot, source = make_plot()
    template = """<span href="#" data-toggle="tooltip"  title="<%= value %>"><%= value %></span>"""
    columns = [
        TableColumn(field="dates", title="Date", editor=DateEditor(), formatter=DateFormatter()),
        TableColumn(field="downloads", title="Downloads", editor=IntEditor()),
    ]

    df = pd.DataFrame([
        ['this is a longer text that needs a tooltip, because otherwise we do not see the whole text',
         'this is a short text'],
        ['this is another loooooooooooooooong text that needs a tooltip', 'not much here'],
    ], columns=['a', 'b'])
    columns = [TableColumn(field=c, title=c, width=20, formatter=HTMLTemplateFormatter(template=template))
               for c in ['a', 'b']]
    source = ColumnDataSource(data=df)
    data_table = DataTable(source=source, columns = columns)
    l = layout([[data_table]])
    return l

    data_table = DataTable(source=source, columns=columns, width=400, height=400, editable=True)
    button = Button(label="Randomize data", button_type="success")
    button.on_click(click_handler)
    buttons = WidgetBox(children=[button], width=400)
    column = Column(children=[buttons, plot, data_table])
    return column
コード例 #3
0
ファイル: tabular.py プロジェクト: suesie/holoviews
    def initialize_plot(self, ranges=None, plot=None, plots=None, source=None):
        """
        Initializes a new plot object with the last available frame.
        """
        # Get element key and ranges for frame
        element = self.hmap.last
        key = self.keys[-1]
        self.current_frame = element
        self.current_key = key

        style = self.lookup_options(element, 'style')[self.cyclic_index]
        data, _, style = self.get_data(element, ranges, style)
        if source is None:
            source = self._init_datasource(data)
        self.handles['source'] = source

        columns = []
        dims = element.dimensions()
        for d in dims:
            col = dimension_sanitizer(d.name)
            kind = data[col].dtype.kind
            if kind == 'i':
                formatter = NumberFormatter()
                editor = IntEditor()
            elif kind == 'f':
                formatter = NumberFormatter(format='0,0.0[00000]')
                editor = NumberEditor()
            elif kind == 'M' or (kind == 'O' and len(data[col])
                                 and type(data[col][0]) in datetime_types):
                dimtype = element.get_dimension_type(0)
                dformat = Dimension.type_formatters.get(
                    dimtype, '%Y-%m-%d %H:%M:%S')
                formatter = DateFormatter(format=dformat)
                editor = DateEditor()
            else:
                formatter = StringFormatter()
                editor = StringEditor()
            column = TableColumn(field=d.name,
                                 title=d.pprint_label,
                                 editor=editor,
                                 formatter=formatter)
            columns.append(column)
        style['reorderable'] = False
        table = DataTable(source=source,
                          columns=columns,
                          height=self.height,
                          width=self.width,
                          **style)
        self.handles['plot'] = table
        self.handles['glyph_renderer'] = table
        self._execute_hooks(element)
        self.drawn = True

        for cb in self.callbacks:
            cb.initialize()

        return table
コード例 #4
0
ファイル: widgets_server.py プロジェクト: zlxs23/bokeh
def make_layout():
    plot, source = make_plot()
    columns = [
        TableColumn(field="dates", title="Date", editor=DateEditor(), formatter=DateFormatter()),
        TableColumn(field="downloads", title="Downloads", editor=IntEditor()),
    ]
    data_table = DataTable(source=source, columns=columns, width=400, height=400, editable=True)
    button = Button(label="Randomize data", type="success")
    button.on_click(click_handler)
    buttons = VBox(children=[button])
    vbox = VBox(children=[buttons, plot, data_table])
    return vbox
コード例 #5
0
    def _get_columns(self):
        if self.value is None:
            return []

        index = [self.value.index.name or 'index']
        col_names = index + list(self.value.columns)
        columns = []
        for col in col_names:
            if col in self.value.columns:
                data = self.value[col]
            else:
                data = self.value.index
            kind = data.dtype.kind
            if kind == 'i':
                formatter = NumberFormatter()
                editor = IntEditor()
            elif kind == 'f':
                formatter = NumberFormatter(format='0,0.0[00000]')
                editor = NumberEditor()
            elif isdatetime(data) or kind == 'M':
                formatter = DateFormatter(format='%Y-%m-%d %H:%M:%S')
                editor = DateEditor()
            else:
                formatter = StringFormatter()
                editor = StringEditor()

            if col in self.editors:
                editor = self.editors[col]
            if col in self.formatters:
                formatter = self.formatters[col]
            if str(col) != col:
                self._renamed_cols[str(col)] = col
            width = self.widths.get(str(col))
            column = TableColumn(field=str(col),
                                 title=str(col),
                                 editor=editor,
                                 formatter=formatter,
                                 width=width)
            columns.append(column)
        return columns
コード例 #6
0
from bokeh.util.browser import view
from bokeh.sampledata.autompg2 import autompg2 as mpg

source = ColumnDataSource(mpg)

manufacturers = sorted(mpg["manufacturer"].unique())
models = sorted(mpg["model"].unique())
transmissions = sorted(mpg["trans"].unique())
drives = sorted(mpg["drv"].unique())
classes = sorted(mpg["class"].unique())

columns = [
    TableColumn(field="manufacturer", title="Manufacturer", editor=SelectEditor(options=manufacturers), formatter=StringFormatter(font_style="bold")),
    TableColumn(field="model",        title="Model",        editor=StringEditor(completions=models)),
    TableColumn(field="displ",        title="Displacement", editor=NumberEditor(step=0.1),              formatter=NumberFormatter(format="0.0")),
    TableColumn(field="year",         title="Year",         editor=IntEditor()),
    TableColumn(field="cyl",          title="Cylinders",    editor=IntEditor()),
    TableColumn(field="trans",        title="Transmission", editor=SelectEditor(options=transmissions)),
    TableColumn(field="drv",          title="Drive",        editor=SelectEditor(options=drives)),
    TableColumn(field="class",        title="Class",        editor=SelectEditor(options=classes)),
    TableColumn(field="cty",          title="City MPG",     editor=IntEditor()),
    TableColumn(field="hwy",          title="Highway MPG",  editor=IntEditor()),
]
data_table = DataTable(source=source, columns=columns, editable=True, width=1000,
                       index_position=-1, index_header="row index", index_width=60)

plot = Plot(title=None, plot_width=1000, plot_height=300)

# Set up x & y axis
plot.add_layout(LinearAxis(), 'below')
yaxis = LinearAxis()
コード例 #7
0
)
plot.add_tools(hover)

data_table = DataTable(source=source,
                       width=400,
                       height=327,
                       editable=True,
                       columns=[
                           TableColumn(
                               field="f",
                               title="force (N)",
                               editor=NumberEditor(step=0.001),
                               formatter=NumberFormatter(format="0.000")),
                           TableColumn(field="v",
                                       title="voltage (V/1023)",
                                       editor=IntEditor(step=1)),
                       ])

##############################################################################
# Widgets

_div = Div(text=""" """, height=4)
checkbox = CheckboxGroup(labels=['', '', ''], active=[0])
device_slc = Select(title="Device ID:",
                    value=g.device_id,
                    options=DEVICES['code'])
device_conn_btn = Toggle(label="Connect to device",
                         button_type="success",
                         active=True)
read_point_btn = Button(label="Read point", button_type="primary")
clear_points_btn = Button(label="Clear selected points", button_type="warning")
コード例 #8
0
    def create(self):
        print("running create...")
        manufacturers = sorted(mpg["manufacturer"].unique())
        models = sorted(mpg["model"].unique())
        transmissions = sorted(mpg["trans"].unique())
        drives = sorted(mpg["drv"].unique())
        classes = sorted(mpg["class"].unique())

        manufacturer_select = Select(title="Manufacturer:",
                                     value="All",
                                     options=["All"] + manufacturers)
        manufacturer_select.on_change('value', self.on_manufacturer_change)
        model_select = Select(title="Model:",
                              value="All",
                              options=["All"] + models)
        model_select.on_change('value', self.on_model_change)
        transmission_select = Select(title="Transmission:",
                                     value="All",
                                     options=["All"] + transmissions)
        transmission_select.on_change('value', self.on_transmission_change)
        drive_select = Select(title="Drive:",
                              value="All",
                              options=["All"] + drives)
        drive_select.on_change('value', self.on_drive_change)
        class_select = Select(title="Class:",
                              value="All",
                              options=["All"] + classes)
        class_select.on_change('value', self.on_class_change)

        columns = [
            TableColumn(field="manufacturer",
                        title="Manufacturer",
                        editor=SelectEditor(options=manufacturers),
                        formatter=StringFormatter(font_style="bold")),
            TableColumn(field="model",
                        title="Model",
                        editor=StringEditor(completions=models)),
            TableColumn(field="displ",
                        title="Displacement",
                        editor=NumberEditor(step=0.1),
                        formatter=NumberFormatter(format="0.0")),
            TableColumn(field="year", title="Year", editor=IntEditor()),
            TableColumn(field="cyl", title="Cylinders", editor=IntEditor()),
            TableColumn(field="trans",
                        title="Transmission",
                        editor=SelectEditor(options=transmissions)),
            TableColumn(field="drv",
                        title="Drive",
                        editor=SelectEditor(options=drives)),
            TableColumn(field="class",
                        title="Class",
                        editor=SelectEditor(options=classes)),
            TableColumn(field="cty", title="City MPG", editor=IntEditor()),
            TableColumn(field="hwy", title="Highway MPG", editor=IntEditor()),
        ]
        data_table = DataTable(source=self.source,
                               columns=columns,
                               editable=True,
                               width=1300)

        plot = Plot(title=None,
                    x_range=DataRange1d(),
                    y_range=DataRange1d(),
                    plot_width=1000,
                    plot_height=300)

        # Set up x & y axis
        plot.add_layout(LinearAxis(), 'below')
        yaxis = LinearAxis()
        plot.add_layout(yaxis, 'left')
        plot.add_layout(Grid(dimension=1, ticker=yaxis.ticker))

        # Add Glyphs
        cty_glyph = Circle(x="index",
                           y="cty",
                           fill_color="#396285",
                           size=8,
                           fill_alpha=0.5,
                           line_alpha=0.5)
        hwy_glyph = Circle(x="index",
                           y="hwy",
                           fill_color="#CE603D",
                           size=8,
                           fill_alpha=0.5,
                           line_alpha=0.5)
        cty = plot.add_glyph(self.source, cty_glyph)
        hwy = plot.add_glyph(self.source, hwy_glyph)

        # Add the tools
        tooltips = [
            ("Manufacturer", "@manufacturer"),
            ("Model", "@model"),
            ("Displacement", "@displ"),
            ("Year", "@year"),
            ("Cylinders", "@cyl"),
            ("Transmission", "@trans"),
            ("Drive", "@drv"),
            ("Class", "@class"),
        ]
        cty_hover_tool = HoverTool(renderers=[cty],
                                   tooltips=tooltips + [("City MPG", "@cty")])
        hwy_hover_tool = HoverTool(renderers=[hwy],
                                   tooltips=tooltips +
                                   [("Highway MPG", "@hwy")])
        select_tool = BoxSelectTool(renderers=[cty, hwy], dimensions='width')
        plot.add_tools(cty_hover_tool, hwy_hover_tool, select_tool)

        controls = WidgetBox(manufacturer_select, model_select,
                             transmission_select, drive_select, class_select)
        top_panel = Row(controls, plot)
        layout = Column(top_panel, data_table)

        return layout
コード例 #9
0
ファイル: data_tables_server.py プロジェクト: tengqu/bokeh
    def create(self):
        manufacturers = sorted(mpg["manufacturer"].unique())
        models = sorted(mpg["model"].unique())
        transmissions = sorted(mpg["trans"].unique())
        drives = sorted(mpg["drv"].unique())
        classes = sorted(mpg["class"].unique())

        manufacturer_select = Select(title="Manufacturer:",
                                     value="All",
                                     options=["All"] + manufacturers)
        manufacturer_select.on_change('value', self.on_manufacturer_change)
        model_select = Select(title="Model:",
                              value="All",
                              options=["All"] + models)
        model_select.on_change('value', self.on_model_change)
        transmission_select = Select(title="Transmission:",
                                     value="All",
                                     options=["All"] + transmissions)
        transmission_select.on_change('value', self.on_transmission_change)
        drive_select = Select(title="Drive:",
                              value="All",
                              options=["All"] + drives)
        drive_select.on_change('value', self.on_drive_change)
        class_select = Select(title="Class:",
                              value="All",
                              options=["All"] + classes)
        class_select.on_change('value', self.on_class_change)

        columns = [
            TableColumn(field="manufacturer",
                        title="Manufacturer",
                        editor=SelectEditor(options=manufacturers),
                        formatter=StringFormatter(font_style="bold")),
            TableColumn(field="model",
                        title="Model",
                        editor=StringEditor(completions=models)),
            TableColumn(field="displ",
                        title="Displacement",
                        editor=NumberEditor(step=0.1),
                        formatter=NumberFormatter(format="0.0")),
            TableColumn(field="year", title="Year", editor=IntEditor()),
            TableColumn(field="cyl", title="Cylinders", editor=IntEditor()),
            TableColumn(field="trans",
                        title="Transmission",
                        editor=SelectEditor(options=transmissions)),
            TableColumn(field="drv",
                        title="Drive",
                        editor=SelectEditor(options=drives)),
            TableColumn(field="class",
                        title="Class",
                        editor=SelectEditor(options=classes)),
            TableColumn(field="cty", title="City MPG", editor=IntEditor()),
            TableColumn(field="hwy", title="Highway MPG", editor=IntEditor()),
        ]
        data_table = DataTable(source=self.source,
                               columns=columns,
                               editable=True)

        xdr = DataRange1d()
        ydr = DataRange1d()
        plot = Plot(title=None,
                    x_range=xdr,
                    y_range=ydr,
                    plot_width=800,
                    plot_height=300)
        xaxis = LinearAxis(plot=plot)
        plot.below.append(xaxis)
        yaxis = LinearAxis(plot=plot)
        ygrid = Grid(plot=plot, dimension=1, ticker=yaxis.ticker)
        plot.left.append(yaxis)
        cty_glyph = Circle(x="index",
                           y="cty",
                           fill_color="#396285",
                           size=8,
                           fill_alpha=0.5,
                           line_alpha=0.5)
        hwy_glyph = Circle(x="index",
                           y="hwy",
                           fill_color="#CE603D",
                           size=8,
                           fill_alpha=0.5,
                           line_alpha=0.5)
        cty = GlyphRenderer(data_source=self.source, glyph=cty_glyph)
        hwy = GlyphRenderer(data_source=self.source, glyph=hwy_glyph)
        tooltips = [
            ("Manufacturer", "@manufacturer"),
            ("Model", "@model"),
            ("Displacement", "@displ"),
            ("Year", "@year"),
            ("Cylinders", "@cyl"),
            ("Transmission", "@trans"),
            ("Drive", "@drv"),
            ("Class", "@class"),
        ]
        cty_hover_tool = HoverTool(plot=plot,
                                   renderers=[cty],
                                   tooltips=tooltips + [("City MPG", "@cty")])
        hwy_hover_tool = HoverTool(plot=plot,
                                   renderers=[hwy],
                                   tooltips=tooltips +
                                   [("Highway MPG", "@hwy")])
        select_tool = BoxSelectTool(plot=plot,
                                    renderers=[cty, hwy],
                                    dimensions=['width'])
        plot.tools.extend([cty_hover_tool, hwy_hover_tool, select_tool])
        plot.renderers.extend([cty, hwy, ygrid])

        controls = VBox(children=[
            manufacturer_select, model_select, transmission_select,
            drive_select, class_select
        ],
                        width=200)
        top_panel = HBox(children=[controls, plot])
        layout = VBox(children=[top_panel, data_table])

        return layout
コード例 #10
0
ファイル: widgets.py プロジェクト: sebastianlesser/bokeh
source = ColumnDataSource(data=mpg)
columns = [
    TableColumn(field="manufacturer",
                title="Manufacturer",
                editor=SelectEditor(options=sorted(mpg["manufacturer"].unique())),
                formatter=StringFormatter(font_style="bold")),
    TableColumn(field="model",
                title="Model",
                editor=StringEditor(completions=sorted(mpg["model"].unique()))),
    TableColumn(field="displ",
                title="Displacement",
                editor=NumberEditor(step=0.1),
                formatter=NumberFormatter(format="0.0")),
    TableColumn(field="year",
                title="Year",
                editor=IntEditor()),
    TableColumn(field="cyl",
                title="Cylinders",
                editor=IntEditor()),
    TableColumn(field="trans",
                title="Transmission",
                editor=SelectEditor(options=sorted(mpg["trans"].unique()))),
    TableColumn(field="drv",
                title="Drive",
                editor=SelectEditor(options=sorted(mpg["drv"].unique()))),
    TableColumn(field="class",
                title="Class",
                editor=SelectEditor(options=sorted(mpg["class"].unique()))),
    TableColumn(field="cty",
                title="City MPG",
                editor=IntEditor()),
コード例 #11
0
ファイル: main.py プロジェクト: j-brady/peakipy
#    "CLUSTID",
#    "X_PPM",
#    "Y_PPM",
#    "X_RADIUS_PPM",
#    "Y_RADIUS_PPM",
#    "XW_HZ",
#    "YW_HZ",
#    "VOL",
#    "include",
#    "MEMCNT",
# ]
#
# columns = [TableColumn(field=field, title=field) for field in selected_columns]
columns = [
    TableColumn(field="ASS", title="Assignment"),
    TableColumn(field="CLUSTID", title="Cluster", editor=IntEditor()),
    TableColumn(
        field="X_PPM",
        title=f"{f2_label}",
        editor=NumberEditor(step=0.0001),
        formatter=NumberFormatter(format="0.0000"),
    ),
    TableColumn(
        field="Y_PPM",
        title=f"{f1_label}",
        editor=NumberEditor(step=0.0001),
        formatter=NumberFormatter(format="0.0000"),
    ),
    TableColumn(
        field="X_RADIUS_PPM",
        title=f"{f2_label} radius (ppm)",
コード例 #12
0
ファイル: main.py プロジェクト: vnbisn/LeM_widget
y2_axis = Select(title="Y2 Axis", options=sorted(axis_keys), value=" ANet")
for key in slider_keys:
    s = Slider(title=key, **bounds_heuristic(pd[key][0]))
    sliders.append(s)

source = ColumnDataSource(data=get_data(sliders))

p = figure(plot_height=600, plot_width=700, title='', toolbar_location=None)
p.extra_y_ranges = {'second': Range1d(start=0, end=50)}
p.add_layout(LinearAxis(y_range_name='second'), 'right')
p.line(x='x', y='y1', source=source)
p.line(x='x', y='y2', source=source, color='green', y_range_name='second')

pd_source = ColumnDataSource(pd)
columns = [
    TableColumn(field=key, title=key, editor=IntEditor()) for key in pd.keys()
]
#columns = [TableColumn(field=key, title=key) for key in ['LeafID', 'Temperature']]
data_table = DataTable(source=pd_source,
                       columns=columns,
                       width=1200,
                       height=300,
                       editable=True)

sizing_mode = 'fixed'  # 'scale_width' also looks nice with this example
controls = sliders + [x_axis, y1_axis, y2_axis]
for item in controls:
    item.on_change('value', lambda attr, old, new: update())

inputs1 = widgetbox(*controls[:10], sizing_mode=sizing_mode)
inputs2 = widgetbox(*controls[10:], sizing_mode=sizing_mode)
コード例 #13
0
    def make_example_datatable():
        source = ColumnDataSource(mpg)
        print(source.column_names)
        manufacturers = sorted(mpg["manufacturer"].unique())
        models = sorted(mpg["model"].unique())
        transmissions = sorted(mpg["trans"].unique())
        drives = sorted(mpg["drv"].unique())
        classes = sorted(mpg["class"].unique())

        columns = [
            TableColumn(field="manufacturer",
                        title="Manufacturer",
                        editor=SelectEditor(options=manufacturers),
                        formatter=StringFormatter(font_style="bold")),
            TableColumn(field="model",
                        title="Model",
                        editor=StringEditor(completions=models)),
            TableColumn(field="displ",
                        title="Displacement",
                        editor=NumberEditor(step=0.1),
                        formatter=NumberFormatter(format="0.0")),
            TableColumn(field="year", title="Year", editor=IntEditor()),
            TableColumn(field="cyl", title="Cylinders", editor=IntEditor()),
            TableColumn(field="trans",
                        title="Transmission",
                        editor=SelectEditor(options=transmissions)),
            TableColumn(field="drv",
                        title="Drive",
                        editor=SelectEditor(options=drives)),
            TableColumn(field="class",
                        title="Class",
                        editor=SelectEditor(options=classes)),
            TableColumn(field="cty", title="City MPG", editor=IntEditor()),
            TableColumn(field="hwy", title="Highway MPG", editor=IntEditor()),
        ]
        data_table = DataTable(source=source,
                               columns=columns,
                               editable=True,
                               width=1000)
        plot = Plot(title=None,
                    x_range=DataRange1d(),
                    y_range=DataRange1d(),
                    plot_width=1000,
                    plot_height=300)
        # Set up x & y axis
        plot.add_layout(LinearAxis(), 'below')
        yaxis = LinearAxis()
        plot.add_layout(yaxis, 'left')
        plot.add_layout(Grid(dimension=1, ticker=yaxis.ticker))

        # Add Glyphs
        cty_glyph = Circle(x="index",
                           y="cty",
                           fill_color="#396285",
                           size=8,
                           fill_alpha=0.5,
                           line_alpha=0.5)
        hwy_glyph = Circle(x="index",
                           y="hwy",
                           fill_color="#CE603D",
                           size=8,
                           fill_alpha=0.5,
                           line_alpha=0.5)
        cty = plot.add_glyph(source, cty_glyph)
        hwy = plot.add_glyph(source, hwy_glyph)

        # Add the tools
        tooltips = [
            ("Manufacturer", "@manufacturer"),
            ("Model", "@model"),
            ("Displacement", "@displ"),
            ("Year", "@year"),
            ("Cylinders", "@cyl"),
            ("Transmission", "@trans"),
            ("Drive", "@drv"),
            ("Class", "@class"),
        ]
        cty_hover_tool = HoverTool(renderers=[cty],
                                   tooltips=tooltips + [("City MPG", "@cty")])
        hwy_hover_tool = HoverTool(renderers=[hwy],
                                   tooltips=tooltips +
                                   [("Highway MPG", "@hwy")])
        select_tool = BoxSelectTool(renderers=[cty, hwy], dimensions='width')
        plot.add_tools(cty_hover_tool, hwy_hover_tool, select_tool)
        layout = Column(plot, data_table)
        doc = Document()
        doc.add_root(layout)
        return doc
コード例 #14
0
ファイル: edit.py プロジェクト: j-brady/peakipy
    def setup_plot(self):
        """" code to setup the bokeh plots """
        #  make bokeh figure
        tools = [
            "tap",
            "box_zoom",
            "lasso_select",
            "box_select",
            "wheel_zoom",
            "pan",
            "reset",
        ]
        self.p = figure(
            x_range=(self.peakipy_data.f2_ppm_0, self.peakipy_data.f2_ppm_1),
            y_range=(self.peakipy_data.f1_ppm_0, self.peakipy_data.f1_ppm_1),
            x_axis_label=f"{self.peakipy_data.f2_label} - ppm",
            y_axis_label=f"{self.peakipy_data.f1_label} - ppm",
            tools=tools,
            active_drag="pan",
            active_scroll="wheel_zoom",
            active_tap=None,
        )
        if not self.thres:
            self.thres = threshold_otsu(self.peakipy_data.data[0])
        self.contour_start = self.thres  # contour level start value
        self.contour_num = 20  # number of contour levels
        self.contour_factor = 1.20  # scaling factor between contour levels
        cl = self.contour_start * self.contour_factor ** np.arange(self.contour_num)
        if len(cl) > 1 and np.min(np.diff(cl)) <= 0.0:
            print(f"Setting contour levels to np.abs({cl})")
            cl = np.abs(cl)
        self.extent = (
            self.peakipy_data.f2_ppm_0,
            self.peakipy_data.f2_ppm_1,
            self.peakipy_data.f1_ppm_0,
            self.peakipy_data.f1_ppm_1,
        )
        self.spec_source = get_contour_data(
            self.peakipy_data.data[0], cl, extent=self.extent, cmap=viridis
        )
        #  negative contours
        self.spec_source_neg = get_contour_data(
            self.peakipy_data.data[0] * -1.0, cl, extent=self.extent, cmap=autumn
        )
        self.p.multi_line(
            xs="xs", ys="ys", line_color="line_color", source=self.spec_source
        )
        self.p.multi_line(
            xs="xs", ys="ys", line_color="line_color", source=self.spec_source_neg
        )
        # contour_num = Slider(title="contour number", value=20, start=1, end=50,step=1)
        # contour_start = Slider(title="contour start", value=100000, start=1000, end=10000000,step=1000)
        self.contour_start = TextInput(
            value="%.2e" % self.thres, title="Contour level:", width=100
        )
        # contour_factor = Slider(title="contour factor", value=1.20, start=1., end=2.,step=0.05)
        self.contour_start.on_change("value", self.update_contour)
        # for w in [contour_num,contour_start,contour_factor]:
        #    w.on_change("value",update_contour)

        #  plot mask outlines
        el = self.p.ellipse(
            x="X_PPM",
            y="Y_PPM",
            width="X_DIAMETER_PPM",
            height="Y_DIAMETER_PPM",
            source=self.source,
            fill_color="color",
            fill_alpha=0.1,
            line_dash="dotted",
            line_color="red",
        )

        self.p.add_tools(
            HoverTool(
                tooltips=[
                    ("Index", "$index"),
                    ("Assignment", "@ASS"),
                    ("CLUSTID", "@CLUSTID"),
                    ("RADII", "@X_RADIUS_PPM{0.000}, @Y_RADIUS_PPM{0.000}"),
                    (
                        f"{self.peakipy_data.f2_label},{self.peakipy_data.f1_label}",
                        "$x{0.000} ppm, $y{0.000} ppm",
                    ),
                ],
                mode="mouse",
                # add renderers
                renderers=[el],
            )
        )
        # p.toolbar.active_scroll = "auto"
        # draw border around spectrum area
        spec_border_x = [
            self.peakipy_data.f2_ppm_min,
            self.peakipy_data.f2_ppm_min,
            self.peakipy_data.f2_ppm_max,
            self.peakipy_data.f2_ppm_max,
            self.peakipy_data.f2_ppm_min,
        ]

        spec_border_y = [
            self.peakipy_data.f1_ppm_min,
            self.peakipy_data.f1_ppm_max,
            self.peakipy_data.f1_ppm_max,
            self.peakipy_data.f1_ppm_min,
            self.peakipy_data.f1_ppm_min,
        ]

        self.p.line(
            spec_border_x,
            spec_border_y,
            line_width=1,
            line_color="black",
            line_dash="dotted",
            line_alpha=0.5,
        )
        self.p.circle(x="X_PPM", y="Y_PPM", source=self.source, color="color")
        # plot cluster numbers
        self.p.text(
            x="X_PPM",
            y="Y_PPM",
            text="CLUSTID",
            text_color="color",
            source=self.source,
            text_font_size="8pt",
            text_font_style="bold",
        )

        self.p.on_event(DoubleTap, self.peak_pick_callback)

        self.pos_neg_contour_dic = {0: "pos/neg", 1: "pos", 2: "neg"}
        self.pos_neg_contour_radiobutton = RadioButtonGroup(
            labels=[
                self.pos_neg_contour_dic[i] for i in self.pos_neg_contour_dic.keys()
            ],
            active=0,
        )
        self.pos_neg_contour_radiobutton.on_change("active", self.update_contour)
        # call fit_peaks
        self.fit_button = Button(label="Fit selected cluster", button_type="primary")
        # lineshape selection
        self.lineshapes = {
            0: "PV",
            1: "V",
            2: "G",
            3: "L",
            4: "PV_PV",
            # 5: "PV_L",
            # 6: "PV_G",
            # 7: "G_L",
        }
        self.radio_button_group = RadioButtonGroup(
            labels=[self.lineshapes[i] for i in self.lineshapes.keys()], active=0
        )
        self.ls_div = Div(
            text="""Choose lineshape you wish to fit. This can be Voigt (V), pseudo-Voigt (PV), Gaussian (G), Lorentzian (L).
            PV_PV fits a PV lineshape with independent "fraction" parameters for the direct and indirect dimensions"""
        )
        self.clust_div = Div(
            text="""If you want to adjust how the peaks are automatically clustered then try changing the
                width/diameter/height (integer values) of the structuring element used during the binary dilation step
                (you can also remove it by selecting 'None'). Increasing the size of the structuring element will cause
                peaks to be more readily incorporated into clusters. Be sure to save your peak list before doing this as
                any manual edits will be lost."""
        )
        self.intro_div = Div(
            text="""<h2>peakipy - interactive fit adjustment </h2> 
            """
        )

        self.doc_link = Div(
            text="<h3><a href='https://j-brady.github.io/peakipy/build/usage/instructions.html', target='_blank'> ℹ️ click here for documentation</a></h3>"
        )
        self.fit_reports = ""
        self.fit_reports_div = Div(text="", height=400, style={"overflow": "scroll"})
        # Plane selection
        self.select_planes_list = [
            f"{i}"
            for i in range(self.peakipy_data.data.shape[self.peakipy_data.planes])
        ]
        self.select_plane = Select(
            title="Select plane:",
            value=self.select_planes_list[0],
            options=self.select_planes_list,
        )
        self.select_planes_dic = {
            f"{i}": i
            for i in range(self.peakipy_data.data.shape[self.peakipy_data.planes])
        }
        self.select_plane.on_change("value", self.update_contour)

        self.checkbox_group = CheckboxGroup(
            labels=["fit current plane only"], active=[]
        )

        #  not sure this is needed
        selected_df = self.peakipy_data.df.copy()

        self.fit_button.on_event(ButtonClick, self.fit_selected)

        columns = [
            TableColumn(field="ASS", title="Assignment"),
            TableColumn(field="CLUSTID", title="Cluster", editor=IntEditor()),
            TableColumn(
                field="X_PPM",
                title=f"{self.peakipy_data.f2_label}",
                editor=NumberEditor(step=0.0001),
                formatter=NumberFormatter(format="0.0000"),
            ),
            TableColumn(
                field="Y_PPM",
                title=f"{self.peakipy_data.f1_label}",
                editor=NumberEditor(step=0.0001),
                formatter=NumberFormatter(format="0.0000"),
            ),
            TableColumn(
                field="X_RADIUS_PPM",
                title=f"{self.peakipy_data.f2_label} radius (ppm)",
                editor=NumberEditor(step=0.0001),
                formatter=NumberFormatter(format="0.0000"),
            ),
            TableColumn(
                field="Y_RADIUS_PPM",
                title=f"{self.peakipy_data.f1_label} radius (ppm)",
                editor=NumberEditor(step=0.0001),
                formatter=NumberFormatter(format="0.0000"),
            ),
            TableColumn(
                field="XW_HZ",
                title=f"{self.peakipy_data.f2_label} LW (Hz)",
                editor=NumberEditor(step=0.01),
                formatter=NumberFormatter(format="0.00"),
            ),
            TableColumn(
                field="YW_HZ",
                title=f"{self.peakipy_data.f1_label} LW (Hz)",
                editor=NumberEditor(step=0.01),
                formatter=NumberFormatter(format="0.00"),
            ),
            TableColumn(
                field="VOL", title="Volume", formatter=NumberFormatter(format="0.0")
            ),
            TableColumn(
                field="include",
                title="Include",
                editor=SelectEditor(options=["yes", "no"]),
            ),
            TableColumn(field="MEMCNT", title="MEMCNT", editor=IntEditor()),
        ]

        self.data_table = DataTable(
            source=self.source, columns=columns, editable=True, fit_columns=True
        )

        # callback for adding
        # source.selected.on_change('indices', callback)
        self.source.selected.on_change("indices", self.select_callback)

        # Document layout
        fitting_controls = column(
            row(
                column(self.slider_X_RADIUS, self.slider_Y_RADIUS),
                column(
                    row(
                        widgetbox(self.contour_start, self.pos_neg_contour_radiobutton)
                    ),
                    widgetbox(self.fit_button),
                ),
            ),
            row(
                column(widgetbox(self.ls_div), widgetbox(self.radio_button_group)),
                column(widgetbox(self.select_plane), widgetbox(self.checkbox_group)),
            ),
        )

        # reclustering tab
        self.struct_el = Select(
            title="Structuring element:",
            value="disk",
            options=["square", "disk", "rectangle", "None", "mask_method"],
            width=100,
        )
        self.struct_el_size = TextInput(
            value="3",
            title="Size(width/radius or width,height for rectangle):",
            width=100,
        )

        self.recluster = Button(label="Re-cluster", button_type="warning")
        self.recluster.on_event(ButtonClick, self.recluster_peaks)

        # edit_fits tabs
        fitting_layout = fitting_controls
        log_layout = self.fit_reports_div
        recluster_layout = row(
            self.clust_div,
            column(
                self.contour_start, self.struct_el, self.struct_el_size, self.recluster
            ),
        )
        save_layout = column(self.savefilename, self.button, self.exit_button)

        fitting_tab = Panel(child=fitting_layout, title="Peak fitting")
        log_tab = Panel(child=log_layout, title="Log")
        recluster_tab = Panel(child=recluster_layout, title="Re-cluster peaks")
        save_tab = Panel(child=save_layout, title="Save edited peaklist")
        self.tabs = Tabs(
            tabs=[fitting_tab, log_tab, recluster_tab, save_tab],
            sizing_mode="scale_both",
        )