def read_file_tab(self): """Lets the user choose a data file to read""" # Drop down list self.file_select = Select(name='Data files', value='', options=[], title='Data files') # Status text self.file_status = Div(text='', width=self.page_width) # Update the file_select and file_status controls with scan data self.scan_folder() # This line is here deliberately. The scan_folder would trigger # the on-change function and we don't want that first time around. self.file_select.on_change('value', self.file_changed) # Re-scan button file_rescan = Button(label="Rescan folder", button_type="success") file_rescan.on_click(self.scan_folder) # Layout c = column(self.file_select, self.file_status, file_rescan) return Panel(child=c, title="Read from file")
def __init__(self, ut330): self.ut330 = ut330 self.device_name = TextInput(title="Device name") self.device_time = TextInput(title="Device time") self.computer_time = TextInput(title="Computer time") self.t_high = TextInput(title="High temperature alarm (C)") self.t_low = TextInput(title="Low temperature alarm (C)") self.h_high = TextInput(title="High humidity alarm (%RH)") self.h_low = TextInput(title="Low humidity alarm (%RH)") self.p_high = TextInput(title="High pressure alarm") self.p_low = TextInput(title="Low pressure alarm") self.sampling = TextInput(title="Sampling interval (s)") self.overwrite_records = Select(title="Overwrite records", options=['False', 'True']) self.delay_start = Select(title="Delay start", options=['No delay', 'Delay']) self.delay = TextInput(title="Delay (s)") self.power = TextInput(title="Battery power (%)") self.readings = TextInput(title="Readings") self.read_config = Button(label='Read config') self.write_config = Button(label='Write config')
def run(self): """ Start the CLI logic creating the input source, data conversions, chart instances to show and all other niceties provided by CLI """ try: self.limit_source(self.source) children = [] if self.smart_filters: copy_selection = Button(label="copy current selection") copy_selection.on_click(self.on_copy) children.append(copy_selection) self.chart = create_chart( self.series, self.source, self.index, self.factories, self.map_options, children=children, **self.chart_args ) self.chart.show() self.has_ranged_x_axis = 'ranged_x_axis' in self.source.columns self.columns = [c for c in self.source.columns if c != 'ranged_x_axis'] if self.smart_filters: for chart in self.chart.charts: chart.source.on_change('selected', self, 'on_selection_changed') self.chart.session.poll_document(self.chart.doc) except TypeError: if not self.series: series_list = ', '.join(self.chart.values.keys()) print(hm.ERR_MSG_TEMPL % series_list) raise if self.sync_with_source: keep_source_input_sync(self.input, self.update_source, self.last_byte)
def mass_plotting(self, filename): data_dict = self.data_generation(filename) self.data_test(data_dict) name_check = data_dict["gen_info"]["DATA FILES"] attr_id = name_check[1][4][:-3] + "_" + name_check[2][2] TOOLS="pan,wheel_zoom,box_zoom,reset, hover, previewsave" figure_obj = figure(plot_width = 1000, plot_height = 800, y_axis_type = "log", title = attr_id, tools = TOOLS) figure_obj.yaxis.axis_label = data_dict["data"][0]["y_unit"] figure_obj.xaxis.axis_label = data_dict["data"][0]["x_unit"] hover = figure_obj.select(dict(type = HoverTool)) hover.tooltips=[("Value:", "$top")] hist, edges = np.histogram(data_dict["data"][0]["y"], bins = data_dict["data"][0]["x"]) source = ColumnDataSource(data = dict(top = hist, left = edges[:-1], right = edges[1:], x_unit = data_dict["data"][0]["x_unit"], y_unit = data_dict["data"][0]["y_unit"], edges = edges)) #hist = figure_obj.Histogram(source ) figure_obj.quad(top = "top", bottom = 0, left = "left" , right = "right", source = source) matplot_button = Button(label = "create matplotlib plot") matplot_button.on_click(lambda source_list = source: self.matplotlib_export_ms(source_list)) return Panel(child = hplot(figure_obj, matplot_button), title = attr_id)
def __init__(self, ut330): self.ut330 = ut330 self.source = ColumnDataSource(data=dict(ts=[], t=[], h=[])) self.plot = figure(x_axis_type="datetime") self.plot.title = "Temperature and humidity vs. time" self.plot.line(x="ts", y="t", source=self.source, color="blue", legend="Temperature", line_width=2) self.plot.xaxis.axis_label = "Timestamp" self.plot.yaxis.axis_label = "Temperature (C)" self.plot.extra_y_ranges = {"humidity": Range1d(0, 100)} self.plot.line(x="ts", y="h", source=self.source, y_range_name="humidity", color="green", legend="Humidity", line_width=2) self.plot.add_layout(LinearAxis(y_range_name="humidity", axis_label="Relative humidity (%)"), 'right') self.read = Button(label='Read data') self.delete = Button(label='Delete data')
def button_print_page(): """Button to print currently displayed webpage to paper or pdf. Notes ----- * Available styles: 'default', 'primary', 'success', 'warning', 'danger' """ button = Button(label="Print this page", button_type="success") button.callback = CustomJS(code="""print()""") return widgetbox(button)
class Offsets_Panel(object): def __init__(self, ut330): self.ut330 = ut330 self.t_current = TextInput(title="Temperature current") self.h_current = TextInput(title="Humidity current") self.p_current = TextInput(title="Pressure current") self.t_offset = TextInput(title="Temperature offset") self.h_offset = TextInput(title="Humidity offset") self.p_offset = TextInput(title="Pressure offset") self.read_offsets = Button(label='Read offsets') self.write_offsets = Button(label='Write offsets') def _layout_(self): return VBox(HBox(self.t_current, self.t_offset, width=500), HBox(self.h_current, self.h_offset, width=500), HBox(self.p_current, self.p_offset, width=500), HBox(self.read_offsets, self.write_offsets, width=500)) def panel(self): return Panel(child=self._layout_(), title="Offsets") def _read_(self): offsets = self.ut330.read_offsets() self.t_current.value = str(offsets['temperature']) self.h_current.value = str(offsets['humidity']) self.p_current.value = str(offsets['pressure']) self.t_offset.value = str(offsets['temperature offset']) self.h_offset.value = str(offsets['humidity offset']) self.p_offset.value = str(offsets['pressure offset']) def _write_(self): offsets = {'temperature offset': float(self.t_offset.value), 'humidity offset': float(self.h_offset.value), 'pressure offset': float(self.p_offset.value)} self.ut330.write_offsets(offsets) def callbacks(self): self.read_offsets.on_click(self._read_) self.write_offsets.on_click(self._write_) def device_read(self): self._read_()
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", button_type="success") button.on_click(click_handler) buttons = WidgetBox(children=[button],width=800) column = Column(children=[buttons, plot, data_table]) return column
def make_layout(): plot, source = make_plot() columns = [ TableColumn(field="dates", title="Date"), TableColumn(field="downloads", title="Downloads"), ] data_table = DataTable(source=source, columns=columns, width=400, height=400) 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
def button_save_table(table): """Button to save selected data table as csv. Notes ----- * Does not work for column values containing tuples (like 'neighbors') * Currently columns being saved are hard coded in the javascript callback * Available styles: 'default', 'primary', 'success', 'warning', 'danger' """ button = Button(label="Download selected data", button_type="success") button.callback = CustomJS(args=dict(source=table.source), code=open(join(dirname(__file__), "js/download_data.js")).read()) return widgetbox(button)
def __init__(self, ut330): self.ut330 = ut330 self.t_current = TextInput(title="Temperature current") self.h_current = TextInput(title="Humidity current") self.p_current = TextInput(title="Pressure current") self.t_offset = TextInput(title="Temperature offset") self.h_offset = TextInput(title="Humidity offset") self.p_offset = TextInput(title="Pressure offset") self.read_offsets = Button(label='Read offsets') self.write_offsets = Button(label='Write offsets')
def offset_tab(self): """Reading/writing device offsets""" # True if the offset device data has been read, false otherwise self.offset_device_read = False offset_status_h = Div(text="<strong>Status</strong>") self.offset_status = Div(text="", width=self.page_width) # Connect to device button # ======================== offset_controls_h = Div(text="<strong>Device controls</strong>") offset_connect = Button(label='Connect to UT330', button_type="success") offset_read = Button(label='Read offset', button_type="success") offset_write = Button(label='Write offset', button_type="success") offset_disconnect = Button(label='Disconnect from UT330', button_type="success") offset_connect.on_click(self.offset_connect) offset_read.on_click(self.offset_read) offset_write.on_click(self.offset_write) offset_disconnect.on_click(self.offset_disconnect) # Offsets # ======= offset_offsets_h = Div(text="<strong>Offsets</strong>") self.offset_t_current = TextInput(title="Temperature current") self.offset_h_current = TextInput(title="Humidity current") self.offset_p_current = TextInput(title="Pressure current") self.offset_t = TextInput(title="Temperature offset") self.offset_h = TextInput(title="Humidity offset") self.offset_p = TextInput(title="Pressure offset") # Values to widgets # ================= if self.device_connected: self.offset_connected() else: self.offset_not_connected() if self.device_connected: self.offset_status.text = ('UT330 device connected. The Read, ' 'Write, and Disconnect buttons ' 'will work.') else: self.offset_status.text = ('UT330 device is <strong>NOT</strong> ' 'connected. The ' 'Read, Write, and Disconnect buttons ' 'will <strong>not work</strong>. ' 'Click the ' 'Connect button if the UT330 is ' 'connected on a USB port.') # Layout # ====== l = layout([[offset_status_h], [self.offset_status], [offset_controls_h], [offset_connect, offset_read, offset_write, offset_disconnect], [offset_offsets_h], [self.offset_t_current, self.offset_h_current, self.offset_p_current], [self.offset_t, self.offset_h, self.offset_p]], width=self.page_width) return Panel(child=l, title="Read/write offset")
x_axis_type="log", x_axis_label='Time since end of outburst (days)', y_axis_label='Teff (eV)') plot.line('x', 'y', source=source, line_width=2, line_alpha=0.6) source2 = ColumnDataSource(data=dict(x=tobs, y=Teffobs)) plot.scatter('x', 'y', source=source2, size=8, marker='circle', fill_color='red', line_color='black') # Set up the controls go_button = Button(label="Go", button_type="success") go_button.on_click(button_handler) def_button = Button(label="Defaults", button_type="default") def_button.on_click(def_handler) Q_slider = Slider(title="Qimp", value=params['Qimp'], start=0.0, end=30.0, step=0.1) Q_slider.on_change('value', Q_slider_handler) Tb_slider = Slider(title="Top temperature (1e8 K)", value=params['Tb'] / 1e8, start=0.3,
from __future__ import print_function from bokeh.util.browser import view from bokeh.document import Document from bokeh.embed import file_html from bokeh.resources import INLINE from bokeh.models import CustomJS, WidgetBox from bokeh.models.widgets import ( Button, Toggle, Dropdown, CheckboxGroup, RadioGroup, CheckboxButtonGroup, RadioButtonGroup, ) button = Button(label="Button (enabled) - has click event", button_type="primary") button.js_on_click(CustomJS(code="console.log('button: click', this.toString())")) button_disabled = Button(label="Button (disabled) - no click event", button_type="primary", disabled=True) button_disabled.js_on_click(CustomJS(code="console.log('button_disabled: click', this.toString())")) toggle_inactive = Toggle(label="Toggle button (initially inactive)", button_type="success") toggle_inactive.js_on_click(CustomJS(code="console.log('toggle_inactive: ' + this.active, this.toString())")) toggle_active = Toggle(label="Toggle button (initially active)", button_type="success", active=True) toggle_active.js_on_click(CustomJS(code="console.log('toggle_active: ' + this.active, this.toString())")) menu = [("Item 1", "item_1_value"), ("Item 2", "item_2_value"), None, ("Item 3", "item_3_value")] dropdown = Dropdown(label="Dropdown button", button_type="warning", menu=menu) dropdown.js_on_click(CustomJS(code="console.log('dropdown: ' + this.value, this.toString())")) dropdown_disabled = Dropdown(label="Dropdown button (disabled)", button_type="warning", disabled=True, menu=menu) dropdown_disabled.js_on_click(CustomJS(code="console.log('dropdown_disabled: ' + this.value, this.toString())"))
def bokeh_ajax(request): startDt = dfDict['time'][0].to_pydatetime() endDt = dfStatic['time'].iloc[-1].to_pydatetime() # note: need the below in order to display the bokeh plot jsResources = INLINE.render_js() # need the below in order to be able to properly interact with the plot and have the default bokeh plot # interaction tool to display cssResources = INLINE.render_css() source2 = ColumnDataSource(data={"time": [], "temperature": [], "id": []}) livePlot2 = figure(x_axis_type="datetime", x_range=[startDt, endDt], y_range=(0, 25), y_axis_label='Temperature (Celsius)', title="Sea Surface Temperature at 43.18, -70.43", plot_width=800) livePlot2.line("time", "temperature", source=source2) updateStartJS = CustomJS(args=dict(plotRange=livePlot2.x_range), code=""" var newStart = Date.parse(cb_obj.value) plotRange.start = newStart plotRange.change.emit() """) updateEndJS = CustomJS(args=dict(plotRange=livePlot2.x_range), code=""" var newEnd = Date.parse(cb_obj.value) plotRange.end = newEnd plotRange.change.emit() """) startInput = TextInput(value=startDt.strftime(dateFmt), title="Enter Date in format: YYYY-mm-dd") startInput.js_on_change('value', updateStartJS) endInput = TextInput(value=endDt.strftime(dateFmt), title="Enter Date in format: YYYY-mm-dd") endInput.js_on_change('value', updateEndJS) textWidgets = row(startInput, endInput) # https://stackoverflow.com/questions/37083998/flask-bokeh-ajaxdatasource # above stackoverflow helped a lot and is what the below CustomJS is based on callback = CustomJS(args=dict(source=source2), code=""" var time_values = "time"; var temperatures = "temperature"; var plot_data = source.data; jQuery.ajax({ type: 'POST', url: '/AJAXdata2', data: {}, dataType: 'json', success: function (json_from_server) { plot_data['temperature'] = plot_data['temperature'].concat(json_from_server['temperature']); plot_data['time'] = plot_data['time'].concat(json_from_server['time']); plot_data['id'] = plot_data['id'].concat(json_from_server['id']); source.change.emit(); }, error: function() { alert("Oh no, something went wrong. Search for an error " + "message in Flask log and browser developer tools."); } }); """) manualUpdate = Button(label="update graph", callback=callback) widgets = widgetbox([manualUpdate]) # IMPORTANT: key is that the widget you want to control plot X has to be in the same layout object as # said plot X . Therefore, when you call the components() method on it both widget and plot live within the # object, if they are not then the JS callbacks don't work because I think they do not know how to communicate # with one another layout2 = column(widgets, textWidgets, livePlot2) script2, div2 = components(layout2) return { 'someword': "hello", 'jsResources': jsResources, 'cssResources': cssResources, 'script2': script2, 'div2': div2 }
start_button.label = 'Start recording data' curdoc().remove_periodic_callback(callback_id) filename = "readings " + str(datetime.datetime.now()) + ".csv" f = open(filename, 'w+') f.write( "Index,Date Stamp,Time Stamp,Channel 0,Channel 1,Channel 2,Channel 3,Channel 4,Channel 5,Channel 6,Channel 7\n" ) f.close() my_supply = rg() file_control = TextInput(title='Name of save file', value=filename) comment_box = TextInput( title='Annotation (Will be added when box is unselected)') start_button = Button(label='Start recording data') directory_control = TextInput( title='Absolute path to desired directory (Ex: /home/pi/Documents/)') plot1 = figure(x_range=(0, 100), y_range=(0, 5), x_axis_label='Time (100 ms)', y_axis_label='Volts', title='Channel 0', plot_width=500, plot_height=200) plot2 = figure(x_range=(0, 100), y_range=(0, 5), x_axis_label="Time (100 ms)", y_axis_label="Volts", title="Channel 1", plot_width=500,
def colorbar_slider(fig): ''' Adds interactive sliders and text input boxes for the colorbar. Returns a layout object to be put into a gridplot ''' cb = get_colorbar_renderer(fig) data = get_image_data(fig) data = reject_outliers_quick(data) datamin = nanmin(data) datamax = nanmax(data) im = get_glyph_renderer(fig) # Get image renderer from bokeh.models import CustomJS, Slider, TextInput from bokeh.models.widgets import Button from bokeh.layouts import widgetbox model = Slider() # trick it into letting datamin and datamax into CustomJS model.tags.append(datamin) # Hide these in here model.tags.append(datamax) callback_u = CustomJS(args=dict(cb=cb, im=im, model=model), code=""" var cm = cb.color_mapper; var upp = upper_slider.get('value'); upper_input.value = upp.toString() lower_slider.end = upp cm.high = upp; im.glyph.color_mapper.high = upp; if (cm.low >= cm.high){ cm.low = upp/1.1 // to prevent limits being the same im.glyph.color_mapper.low = low/1.1; } if (upp > model.tags[1]){ upper_slider.end = upp } """) callback_l = CustomJS(args=dict(cb=cb, im=im, model=model), code=""" var cm = cb.color_mapper; var low = lower_slider.get('value'); lower_input.value = low.toString() upper_slider.start = low cm.low = low; im.glyph.color_mapper.low = low; if (cm.high <= cm.low){ cm.high = low*1.1 // to prevent limits being the same im.glyph.color_mapper.high = low*1.1; } if (low < model.tags[0]){ lower_slider.start = low }""") callback_ut = CustomJS(args=dict(cb=cb, im=im, model=model), code=""" var cm = cb.color_mapper; var upp = parseFloat(upper_input.get('value')); upper_slider.value = upp cm.high = upp; im.glyph.color_mapper.high = upp; if (cm.low >= cm.high){ cm.low = upp/1.1 // to prevent limits being the same im.glyph.color_mapper.low = upp/1.1; } if (upp > model.tags[1]){ upper_slider.end = upp } """) callback_lt = CustomJS(args=dict(cb=cb, im=im, model=model), code=""" var cm = cb.color_mapper; var low = parseFloat(lower_input.get('value')); lower_slider.value = low cm.low = low; im.glyph.color_mapper.low = low; if (cm.high <= cm.low){ cm.high = low*1.1 // to prevent limits being the same im.glyph.color_mapper.high = low*1.1; } if (low < model.tags[0]){ lower_slider.start = low } """) callback_reset_js = CustomJS(args=dict(cb=cb, im=im, model=model), code=""" var cm = cb.color_mapper; var low = model.tags[0]; var high = model.tags[1]; low = parseFloat(low.toPrecision(3)) // 3 sig figs high = parseFloat(high.toPrecision(3)) // 3 sig figs lower_slider.value = low; lower_slider.set('step', (high-low)/50); cm.low = low; upper_slider.value = high; upper_slider.set('step', (high-low)/50); cm.high = high; im.glyph.color_mapper.low = low; im.glyph.color_mapper.high = high; lower_input.value = low.toString(); upper_input.value = high.toString(); lower_slider.start = low; lower_slider.end = high; upper_slider.start = low; upper_slider.end = high; model.trigger('change') cb_obj.trigger('change)') """) reset_button = Button(label='Reset', callback = callback_reset_js) def callback_reset(*args, **kwargs): from IPython.display import Javascript, display # display(callback_reset_js) # callback_reset_js.name = None # callback_reset_js.name = 'test' # display('Plot updated, press reset to rescale!') # cb.color_mapper.low = datamin # cb.color_mapper.high = datamax # im.glyph.color_mapper.low = datamin # im.glyph.color_mapper.high = datamax # lower_slider.start = datamin # lower_slider.end = datamax # lower_slider.value = datamin # upper_slider.start = datamin # upper_slider.end = datamax # lower_slider.value = datamax # lower_input.value = str(datamin) # upper_input.value = str(datamax) # update() # fig.text(x=0,y=0,text='Plot updated, press reset to rescale!') # reset_button.label='Reset: Data changed! Press me!' # reset_button.trigger('clicks',0,1) reset_button.on_click(callback_reset) # def callback_die(attr, old, new): # from IPython.display import display # display('yoooo') # display(old) # display(new) # raise Exception() # exception_button = Button(label='KILL ME') # exception_button.on_click(callback_die) lower_slider = Slider(start=datamin, end=datamax, value=datamin, step=(datamax-datamin)/50, # smallest step is 1e-5 title="Lower lim", callback=callback_l) lower_slider.width=100 upper_slider = Slider(start=datamin, end=datamax, value=datamax, step=(datamax-datamin)/50, title="Upper lim", callback=callback_u) upper_slider.width=100 lower_input = TextInput(callback=callback_lt, value = str(datamin), width=50) upper_input = TextInput(callback=callback_ut, value = str(datamax), width=50) # add all of these widgets as arguments to the callback functions for callback in ['l', 'u', 'lt', 'ut', 'reset_js']: for widget in ['lower_slider', 'upper_slider','lower_input','upper_input', 'reset_button']: exec('callback_%s.args["%s"] = %s' %(callback, widget, widget)) wb = widgetbox([upper_slider, upper_input, lower_slider, lower_input, reset_button], width=100, sizing_mode = 'stretch_both') return wb
# open a session to keep our local document in sync with server session = push_session(curdoc()) def start_handler(): global playing if not playing: curdoc().add_periodic_callback(update, 50) playing = True def stop_handler(): global playing if playing: curdoc().remove_periodic_callback(update) playing = False button_start = Button(label="Start", button_type="success") button_start.on_click(start_handler) button_stop = Button(label="Stop", button_type="danger") button_stop.on_click(stop_handler) controls = hplot(button_start, button_stop) layout = vplot(controls, p) @cosine(w=0.03) def update(step): if playing: r2.data_source.data["y"] = y * step r2.glyph.line_alpha = 1 - 0.8 * abs(step) playing = True
def create_interact_ui(doc): # The data source includes metadata for hover-over tooltips lc_source = prepare_lightcurve_datasource(lc) tpf_source = prepare_tpf_datasource(tpf, aperture_mask) # Create the lightcurve figure and its vertical marker fig_lc, vertical_line = make_lightcurve_figure_elements( lc, lc_source, ylim_func=ylim_func) # Create the TPF figure and its stretch slider pedestal = -np.nanmin(tpf.flux.value) + 1 if scale == 'linear': pedestal = 0 fig_tpf, stretch_slider = make_tpf_figure_elements(tpf, tpf_source, pedestal=pedestal, fiducial_frame=0, vmin=vmin, vmax=vmax, scale=scale, cmap=cmap, tools=tools) # Helper lookup table which maps cadence number onto flux array index. tpf_index_lookup = {cad: idx for idx, cad in enumerate(tpf.cadenceno)} # Interactive slider widgets and buttons to select the cadence number cadence_slider = Slider(start=np.min(tpf.cadenceno), end=np.max(tpf.cadenceno), value=np.min(tpf.cadenceno), step=1, title="Cadence Number", width=490) r_button = Button(label=">", button_type="default", width=30) l_button = Button(label="<", button_type="default", width=30) export_button = Button(label="Save Lightcurve", button_type="success", width=120) message_on_save = Div(text=' ', width=600, height=15) # Callbacks def _create_lightcurve_from_pixels(tpf, selected_pixel_indices, transform_func=transform_func): """Create the lightcurve from the selected pixel index list""" selected_indices = np.array(selected_pixel_indices) selected_mask = np.isin(pixel_index_array, selected_indices) lc_new = tpf.to_lightcurve(aperture_mask=selected_mask) lc_new.meta['aperture_mask'] = selected_mask if transform_func is not None: lc_transformed = transform_func(lc_new) if (len(lc_transformed) != len(lc_new)): warnings.warn( 'Dropping cadences in `transform_func` is not ' 'yet supported due to fixed time coordinates.' 'Skipping the transformation...', LightkurveWarning) else: lc_new = lc_transformed lc_new.meta['aperture_mask'] = selected_mask return lc_new def update_upon_pixel_selection(attr, old, new): """Callback to take action when pixels are selected.""" # Check if a selection was "re-clicked", then de-select if ((sorted(old) == sorted(new)) & (new != [])): # Trigger recursion tpf_source.selected.indices = new[1:] if new != []: lc_new = _create_lightcurve_from_pixels( tpf, new, transform_func=transform_func) lc_source.data['flux'] = lc_new.flux.value if ylim_func is None: ylims = get_lightcurve_y_limits(lc_source) else: ylims = ylim_func(lc_new) fig_lc.y_range.start = ylims[0] fig_lc.y_range.end = ylims[1] else: lc_source.data['flux'] = lc.flux.value * 0.0 fig_lc.y_range.start = -1 fig_lc.y_range.end = 1 message_on_save.text = " " export_button.button_type = "success" def update_upon_cadence_change(attr, old, new): """Callback to take action when cadence slider changes""" if new in tpf.cadenceno: frameno = tpf_index_lookup[new] fig_tpf.select('tpfimg')[0].data_source.data['image'] = \ [tpf.flux.value[frameno, :, :] + pedestal] vertical_line.update(location=tpf.time.value[frameno]) else: fig_tpf.select('tpfimg')[0].data_source.data['image'] = \ [tpf.flux.value[0, :, :] * np.NaN] lc_source.selected.indices = [] def go_right_by_one(): """Step forward in time by a single cadence""" existing_value = cadence_slider.value if existing_value < np.max(tpf.cadenceno): cadence_slider.value = existing_value + 1 def go_left_by_one(): """Step back in time by a single cadence""" existing_value = cadence_slider.value if existing_value > np.min(tpf.cadenceno): cadence_slider.value = existing_value - 1 def save_lightcurve(): """Save the lightcurve as a fits file with mask as HDU extension""" if tpf_source.selected.indices != []: lc_new = _create_lightcurve_from_pixels( tpf, tpf_source.selected.indices, transform_func=transform_func) lc_new.to_fits( exported_filename, overwrite=True, flux_column_name='SAP_FLUX', aperture_mask=lc_new.meta['aperture_mask'].astype(np.int), SOURCE='lightkurve interact', NOTE='custom mask', MASKNPIX=np.nansum(lc_new.meta['aperture_mask'])) if message_on_save.text == " ": text = '<font color="black"><i>Saved file {} </i></font>' message_on_save.text = text.format(exported_filename) export_button.button_type = "success" else: text = '<font color="gray"><i>Saved file {} </i></font>' message_on_save.text = text.format(exported_filename) else: text = '<font color="gray"><i>No pixels selected, no mask saved</i></font>' export_button.button_type = "warning" message_on_save.text = text def jump_to_lightcurve_position(attr, old, new): if new != []: cadence_slider.value = lc.cadenceno[new[0]] # Map changes to callbacks r_button.on_click(go_right_by_one) l_button.on_click(go_left_by_one) tpf_source.selected.on_change('indices', update_upon_pixel_selection) lc_source.selected.on_change('indices', jump_to_lightcurve_position) export_button.on_click(save_lightcurve) cadence_slider.on_change('value', update_upon_cadence_change) # Layout all of the plots sp1, sp2, sp3, sp4 = (Spacer(width=15), Spacer(width=30), Spacer(width=80), Spacer(width=60)) widgets_and_figures = layout([fig_lc, fig_tpf], [ l_button, sp1, r_button, sp2, cadence_slider, sp3, stretch_slider ], [export_button, sp4, message_on_save]) doc.add_root(widgets_and_figures)
def animate_update(): year = slider.value + 1 if year > 2017: year = 1973 slider.value = year callback_id='0'#declare a variable like this def animate(): global callback_id if button.label == 'Play': button.label = 'Pause' callback_id = curdoc().add_periodic_callback(animate_update, 500) else: button.label = 'Play' curdoc().remove_periodic_callback(callback_id) button = Button(label='Play', width=60) button.on_click(animate) def plotAvgTrend(): source1 = ColumnDataSource(data=filterDB(place=commune1,houseType=propertyType)) source2 = ColumnDataSource(data=filterDB(place=commune2,houseType=propertyType)) fig=figure(width=700,title='Belgian real estate transactions 1973-2017: average trend in euros by commune and type') fig.line(x="CD_YEAR", y=Yaxis,color='blue',source=source1,legend=commune1) fig.line(x="CD_YEAR", y=Yaxis,color='red',source=source2,legend=commune2) fig.xaxis.axis_label = 'Year' fig.x_range = Range1d(1973,2017) fig.yaxis.formatter = NumeralTickFormatter(format="{}0") if Yaxis=='Mean Price':
y=[], x1=[], y1=[], cx=[], cy=[], ) pre.text = '<h4 style="border-top: 2px solid #778899;width: 1600px"><br><b style="color:slategray">Error! Try expanding date slider</b><br></h4>' pdict['active'] = radio_button_group.active def update_click(): pre.text = '<h4 style="border-top: 2px solid #778899;width: 1600px"><br><b style="color:slategray">Update in Progress....</b><br></h4>' curdoc().add_next_tick_callback(my_slider_handler) bt = Button(label='Update Plot', button_type="success") bt.on_click(update_click) """ WIDGETS """ sdate_input = TextInput(value="2020-01-03 00:00:00", title="Start Date: (YYYY-MM-DD HH:MM:SS)") #sdate_input.on_change("value", my_slider_handler) edate_input = TextInput(value="2020-01-03 01:00:00", title="End Date: (YYYY-MM-DD HH:MM:SS)") #edate_input.on_change("value", my_slider_handler) count_threshold = TextInput(value="1", title="Count Threshold Value")
from bokeh.plotting import figure from bokeh.layouts import layout from bokeh.models import ColumnDataSource, Range1d from bokeh.models.widgets import Button from bokeh.io import curdoc import numpy as np source = ColumnDataSource(data=dict(x=[], y=[])) p = figure() unit_range = Range1d(0, 1) p.x_range, p.y_range = unit_range, unit_range p.circle(x='x', y='y', source=source) def generate(): values = [[v] for v in np.random.random(size=2)] source.data = dict(x=values[0], y=values[1]) generate_button = Button(label='Generate') generate_button.on_click(generate) l = layout([[p], [generate_button]]) generate() curdoc().add_root(l) curdoc().title = 'Random point in unit square'
from bokeh.plotting import curdoc from bokeh.models.widgets import Button def button_clicked(): print('Button Clicked') my_button = Button(label="Click Here!") my_button.on_click(button_clicked) curdoc().add_root(my_button)
from bokeh.plotting import figure from bokeh.models.widgets import Select, Button, Slider, Paragraph, Panel, Tabs from bokeh.layouts import layout, widgetbox from Plot.ann_data_instance import ANNData import ann from bokeh.io import curdoc from bokeh.models import ColumnDataSource learning_rate_select = Select(title="Öğrenme Hızını Seçiniz:", options=['1e-5', '1e-3', '0.01', '0.1', '1'], value="0.01") activation_func_select = Select(title="Aktivasyon Fonksiyonunu Seçiniz:", options=['ReLu', 'Tanh', 'Sigmoid'], value='ReLu') add_layer_button = Button(label="Katman Ekle", button_type="success") remove_layer_select = Select(title="Katman Çıkar:", options=["Seçiniz", "1"]) layer_select = Select(title="Düğüm Eklemek/Çıkarmak İçin Katman Seç:", options=["1"]) add_node_button = Button(label="+", button_type="warning") remove_node_button = Button(label="-", button_type="warning") epoch_slider = Slider(start=500, end=50000, value=500, step=500, title="Adım Sayısı Belirle") play_button = Button(label="Oynat", button_type="success") play_button_info = Paragraph(text="") widgets = widgetbox(learning_rate_select, activation_func_select, add_layer_button, remove_layer_select,
def make_document(self, doc): # source = ColumnDataSource({'x': [], 'y': [], 'color': []}) # x = [] # y = [] colors = [ "#75968f", "#a5bab7", "#c9d9d3", "#e2e2e2", "#dfccce", "#ddb7b1", "#cc7878", "#933b41", "#550b1d" ] mapper = LinearColorMapper(palette=colors, low=0, high=1) button = Button(label="Start", button_type="success") # create three plots plot = { 'time': [self.env.now], 'running': [len(self.simulation.cluster.running_tasks)], 'finished': [len(self.simulation.cluster.finished_tasks)] } plotdata = ColumnDataSource(plot) def update_start(): if not self.start: self.start = True p = figure(plot_width=400, plot_height=400) p.line(x='time', y='running', legend_label='Running tasks', alpha=0.2, line_width=3, color='navy', source=plotdata) p.line(x='time', y='finished', legend_label='Finished tasks', alpha=0.8, line_width=2, color='orange', source=plotdata) p.xaxis.axis_label = 'Time' p.yaxis.axis_label = 'Tasks' def update_plot(): if self.env: updata = { 'time': [self.env.now], 'running': [len(self.simulation.cluster.running_tasks)], 'finished': [len(self.simulation.cluster.finished_tasks)] } plotdata.stream(updata) """ SETUP TABLE """ columns = [ TableColumn(field="name", title="Name"), TableColumn(field="start", title="Start Time"), TableColumn(field="demand", title="No. Antennas"), TableColumn(field="duration", title="Observation Length"), TableColumn(field="running", title="Running Status") ] sourcedata = dict(name=[], start=[], duration=[], demand=[], running=[]) tablesource = ColumnDataSource(data=sourcedata) for observation in self.simulation.telescope.observations: sourcedata['name'].append(observation.name) sourcedata['start'].append(observation.start) sourcedata['duration'].append(observation.duration) sourcedata['demand'].append(observation.demand) sourcedata['running'].append(observation.status) data_table = DataTable(source=tablesource, columns=columns, width=600, height=280) def update_table(): if self.env: for i, observation in enumerate( self.simulation.telescope.observations): dictionary = {"running": [(i, observation.status)]} tablesource.patch(dictionary) doc.add_periodic_callback(update_plot, 500) doc.add_periodic_callback(update_table, 500) button.on_click(update_start) # fig.xgrid.grid_line_color = None # fig.x_range.start = 0 # fig.x_range.end = 350 # fig.legend.orientation = "horizontal" # fig.legend.location = "top_center" doc.title = "TopSim Dashboard" doc.add_root(layout([button], [p, data_table])) return doc
def time_tab(self): """The date and time setting and getting tab""" self.time_status = Div(text="", width=self.page_width) time_connect = Button(label='Connect to UT330', button_type="success") time_disconnect = Button(label='Disconnect from UT330', button_type="success") time_get = Button(label='Get UT330 date and time', button_type="success") self.time_compare = Div(text="", width=self.page_width) time_set = Button(label='Set the UT330 date and time', button_type="success") time_connect.on_click(self.time_connect) time_disconnect.on_click(self.time_disconnect) time_get.on_click(self.time_get) time_set.on_click(self.time_set) l = layout([self.time_status], [time_connect, time_disconnect], [time_get, self.time_compare], [time_set]) return Panel(child=l, title="Date and time setting")
def getBokehComponent(self): self.bk = Button(label=self._settings['label']) self.bk.on_event(ButtonClick, self.handle_click) return self.bk
windowsize = Slider(title="Window Size", value=30, start=0, end=60, step=2) # Set up callbacks def update_title(attrname, old, new): p1.title.text = text.value def update_window(attrname, old, new): # Get the current slider values window_size = windowsize.value # re calculate average and re-draw line window = np.ones(window_size)/float(window_size) avg = np.convolve(source.data[col2], window, 'same') p1.line(source.data[col1], avg, color='navy', legend='avg') checkbox_group = CheckboxGroup( labels=["Option 1", "Option 2", "Option 3"], active=[0, 1]) button = Button(label="Foo", button_type="success") text.on_change('value', update_title) windowsize.on_change('value', update_window) tabs = Tabs(tabs=create_panels(files, names), width=800) inputs = widgetbox(text, windowsize, checkbox_group, button)#, amplitude, phase, freq) curdoc().add_root(row(inputs, tabs)) curdoc().title = "Dashboard"
curdoc().remove_periodic_callback(update) toggle = Toggle(label="Start", type="success") toggle.on_click(toggle_handler) toggle.active = False # Set up reset button def reset_handler(): global ii, current_time ii = 0 current_time = 0 l_forward.data_source.data["y"] = forward_wave() l_reverse.data_source.data["y"] = reverse_wave() l_sum.data_source.data["y"] = l_forward.data_source.data["y"] + \ l_reverse.data_source.data["y"] #t2.data_source.data["text"] = ['t = {:.3f} s'.format(current_time)] button_reset = Button(label="Reset", type="success") button_reset.on_click(reset_handler) # Set up checkboxes to show/hide forward & reverse propagating waves def checkbox_group_handler(active): global alpha, alpha_slider if 0 in active: #l_forward.glyph.visible = True l_forward.glyph.line_alpha = alpha_forward_reverse_waves else: #l_forward.glyph.visible = False l_forward.glyph.line_alpha = 0.0 if 1 in active: #l_reverse.glyph.visible = True l_reverse.glyph.line_alpha = alpha_forward_reverse_waves else:
ndvis = TextInput(title='NDVIs', value=str(raster_info[band_list[0]]['ndvis'])) tir_max = TextInput(title='Tmax', value=str(raster_info[band_list[0]]['tir_max'])) tir_min = TextInput(title='Tmin', value=str(raster_info[band_list[0]]['tir_min'])) warm_t1 = TextInput(title='Warm T1', value=str(raster_info[band_list[0]]['we_points'][0, 0])) warm_t2 = TextInput(title='Warm T2', value=str(raster_info[band_list[0]]['we_points'][0, 1])) warm_n1 = TextInput(title='Warm N1', value=str(raster_info[band_list[0]]['we_points'][1, 0])) warm_n2 = TextInput(title='Warm N2', value=str(raster_info[band_list[0]]['we_points'][1, 1])) save_button = Button(label='Save All', button_type='default') src = ColumnDataSource(data=dict(tir=[], ndvi=[], tstar=[], fr=[], ef=[])) we_src = ColumnDataSource(data=dict(we=[], tirs=[])) #Based on https://ideone.com/ItifKv #Converts string output from TextInput to float, returns 0 if it can't def convert_to_float(frac_str): try: return float(frac_str) except ValueError: try: num, denom = frac_str.split('/') except: return np.nan
def launch_order(symbol, qty, OrderType, clientOrderId = 13): global newOrderSide global newOrderSymbol newOrderSymbol = symbol newOrderSide = OrderType NewOrder = {'type': 'NewOrder', 'clientOrderId': str(clientOrderId), 'symbol': symbol , 'buySell': OrderType, 'qty': qty} with SocketIO(server) as socketIO: socketIO.emit('submitOrder', NewOrder) socketIO.on('onOrderMessage', order_response) socketIO.wait() buyButton = Button(label="BUY", button_type="success") buyButton.on_click(buyThreadFunc) sellButton = Button(label="SELL", button_type="warning") sellButton.on_click(sellThreadFunc) select = Select(title="Ticker:", value=stocks_list[0], options=stocks_list) select.on_change("value", ticker_handler) quantity_input = TextInput(value="100", title="quantity:") quantity_input.on_change("value", quantity_handler) if currentPNL == 0 : PNLbutton = Button(label="PNL : " + str(currentPNL), button_type="warning") elif currentPNL >0 :
class DatabaseEditor: def __init__(self, roi_manager): column_width = 600 self.roi_manager = roi_manager # allows ROI Name manager updates after importing data self.source = ColumnDataSource(data=dict()) self.source_csv = ColumnDataSource(data=dict(text=[])) self.import_inbox_button = Button(label='Import all from inbox', button_type='success', width=200) self.import_inbox_button.on_click(self.import_inbox) self.import_inbox_force = CheckboxGroup( labels=['Force Update', 'Import Latest Only', 'Move Files'], active=[1, 2]) self.rebuild_db_button = Button(label='Rebuild database', button_type='warning', width=200) self.rebuild_db_button.on_click(self.rebuild_db_button_click) self.query_table = Select( value='Plans', options=['DVHs', 'Plans', 'Rxs', 'Beams', 'DICOM_Files'], width=200, title='Table:') self.query_columns = MultiSelect( title="Columns (Ctrl or Shift Click enabled):", width=250, options=[tuple(['', ''])], size=10) self.query_condition = TextInput(value='', title="Condition:", width=450) self.query_button = Button(label='Query', button_type='primary', width=100) self.query_table.on_change('value', self.update_query_columns_ticker) self.query_button.on_click(self.update_query_source) self.update_db_title = Div(text="<b>Update Database</b>", width=column_width) self.update_db_table = Select( value='DVHs', options=['DVHs', 'Plans', 'Rxs', 'Beams'], width=80, title='Table:') self.update_db_column = Select(value='', options=[''], width=175, title='Column') self.update_db_value = TextInput(value='', title="Value:", width=200) self.update_db_condition = TextInput(value='', title="Condition:", width=350) self.update_db_button = Button(label='Update DB', button_type='warning', width=100) self.update_db_table.on_change('value', self.update_update_db_columns_ticker) self.update_db_button.on_click(self.update_db) self.update_query_columns() self.update_update_db_column() self.reimport_title = Div(text="<b>Reimport from DICOM</b>", width=column_width) self.reimport_mrn_text = TextInput(value='', width=200, title='MRN:') self.reimport_study_date_select = Select(value='', options=[''], width=200, title='Sim Study Date:') self.reimport_uid_select = Select(value='', options=[''], width=425, title='Study Instance UID:') self.reimport_old_data_select = Select( value='Delete from DB', options=['Delete from DB', 'Keep in DB'], width=150, title='Current Data:') self.reimport_button = Button(label='Reimport', button_type='warning', width=100) self.reimport_mrn_text.on_change('value', self.reimport_mrn_ticker) self.reimport_study_date_select.on_change( 'value', self.reimport_study_date_ticker) self.reimport_button.on_click(self.reimport_button_click) self.query_data_table = DataTable(source=self.source, columns=[], width=column_width, editable=True, height=600) self.delete_from_db_title = Div( text="<b>Delete all data with mrn or study_instance_uid</b>", width=column_width) self.delete_from_db_column = Select( value='mrn', options=['mrn', 'study_instance_uid'], width=200, title='Patient Identifier:') self.delete_from_db_value = TextInput(value='', title="Value (required):", width=300) self.delete_from_db_button = Button(label='Delete', button_type='warning', width=100) self.delete_auth_text = TextInput( value='', title="Type 'delete' here to authorize:", width=300) self.delete_auth_text.on_change('value', self.delete_auth_text_ticker) self.delete_from_db_button.on_click(self.delete_from_db) self.change_mrn_uid_title = Div( text="<b>Change mrn or study_instance_uid in all tables</b>", width=column_width) self.change_mrn_uid_column = Select( value='mrn', options=['mrn', 'study_instance_uid'], width=200, title='Patient Identifier:') self.change_mrn_uid_old_value = TextInput(value='', title="Old:", width=300) self.change_mrn_uid_new_value = TextInput(value='', title="New:", width=300) self.change_mrn_uid_button = Button(label='Rename', button_type='warning', width=100) self.change_mrn_uid_button.on_click(self.change_mrn_uid) self.calculations_title = Div(text="<b>Post Import Calculations</b>", width=column_width) self.calculate_condition = TextInput(value='', title="Condition:", width=350) self.calculate_options = [ 'Default Post-Import', 'PTV Distances', 'PTV Overlap', 'ROI Centroid', 'ROI Spread', 'ROI Cross-Section', 'OAR-PTV Centroid Dist', 'Beam Complexities', 'Plan Complexities', 'All (except age)', 'Patient Ages' ] self.calculate_select = Select(value=self.calculate_options[0], options=self.calculate_options, title='Calculate:', width=150) self.calculate_missing_only = CheckboxGroup( labels=['Only Calculate Missing Values'], active=[0], width=280) self.calculate_exec_button = Button(label='Perform Calc', button_type='primary', width=150) self.calculate_exec_button.on_click(self.calculate_exec) self.download = Button(label="Download Table", button_type="default", width=150) self.download.callback = CustomJS(args=dict(source=self.source_csv), code=open( join(dirname(dirname(__file__)), 'download_new.js')).read()) self.layout = row( column( row(self.import_inbox_button, Spacer(width=20), self.rebuild_db_button, Spacer(width=50), self.import_inbox_force), self.calculations_title, row(self.calculate_select, Spacer(width=20), self.calculate_missing_only, self.calculate_exec_button), self.calculate_condition, Div(text="<hr>", width=column_width), self.update_db_title, row(self.update_db_table, self.update_db_column, self.update_db_value, Spacer(width=45), self.update_db_button), self.update_db_condition, Div(text="<hr>", width=column_width), self.reimport_title, row(self.reimport_mrn_text, Spacer(width=10), self.reimport_old_data_select, Spacer(width=140), self.reimport_button), row(self.reimport_study_date_select, self.reimport_uid_select), Div(text="<hr>", width=column_width), row(self.delete_from_db_title), row(self.delete_from_db_column, Spacer(width=300), self.delete_from_db_button), row(self.delete_from_db_value, self.delete_auth_text), Div(text="<hr>", width=column_width), row(self.change_mrn_uid_title), row(self.change_mrn_uid_column, Spacer(width=300), self.change_mrn_uid_button), row(self.change_mrn_uid_old_value, self.change_mrn_uid_new_value)), column(Div(text="<b>Query Database</b>", width=column_width), row(self.query_table, self.query_columns), self.query_condition, row(self.query_button, Spacer(width=25), self.download), self.query_data_table)) def update_query_columns_ticker(self, attr, old, new): self.update_query_columns() def update_query_columns(self): new_options = DVH_SQL().get_column_names( self.query_table.value.lower()) if self.query_table.value.lower() == 'dvhs': new_options.pop(new_options.index('dvh_string')) new_options.pop(new_options.index('roi_coord_string')) new_options.pop(new_options.index('dth_string')) options_tuples = [tuple([option, option]) for option in new_options] self.query_columns.options = options_tuples self.query_columns.value = [''] def update_update_db_columns_ticker(self, attr, old, new): self.update_update_db_column() def update_update_db_column(self): new_options = DVH_SQL().get_column_names( self.update_db_table.value.lower()) new_options.pop(new_options.index('import_time_stamp')) if self.update_db_table.value.lower() == 'dvhs': new_options.pop(new_options.index('dvh_string')) new_options.pop(new_options.index('roi_coord_string')) self.update_db_column.options = new_options self.update_db_column.value = new_options[0] def update_query_source(self): columns = [v for v in self.query_columns.value if v] for i, key in enumerate([ 'mrn', 'study_instance_uid' ]): # move/add mrn and study_instance_uid to the front if key in columns: columns.pop(columns.index(key)) columns.insert(i, key) table_columns = [TableColumn(field=c, title=c) for c in columns] query_cursor = DVH_SQL().query(self.query_table.value, ','.join(columns).strip(), self.query_condition.value, order_by='mrn') new_data = { c: [str(line[i]) for line in query_cursor] for i, c in enumerate(columns) } if new_data: self.source.data = new_data self.query_data_table.columns = table_columns self.query_data_table.width = [700, 150 * len(table_columns) ][len(table_columns) > 5] self.update_csv() def update_db(self): if self.update_db_condition.value and self.update_db_value.value: self.update_db_button.label = 'Updating...' self.update_db_button.button_type = 'danger' update_value = self.update_db_value.value if self.update_db_column.value in {'birth_date', 'sim_study_date'}: update_value = update_value + "::date" DVH_SQL().update(self.update_db_table.value, self.update_db_column.value, update_value, self.update_db_condition.value) self.update_query_source() self.update_db_button.label = 'Update' self.update_db_button.button_type = 'warning' self.roi_manager.update_uncategorized_variation_select() self.roi_manager.update_ignored_variations_select() def delete_from_db(self): if self.delete_from_db_value.value and self.delete_auth_text.value == 'delete': condition = self.delete_from_db_column.value + " = '" + self.delete_from_db_value.value + "'" DVH_SQL().delete_rows(condition) self.update_query_source() self.delete_from_db_value.value = '' self.delete_auth_text.value = '' self.roi_manager.update_uncategorized_variation_select() self.roi_manager.update_ignored_variations_select() def change_mrn_uid(self): self.change_mrn_uid_button.label = 'Updating...' self.change_mrn_uid_button.button_type = 'danger' old = self.change_mrn_uid_old_value.value new = self.change_mrn_uid_new_value.value if old and new and old != new: if self.change_mrn_uid_column.value == 'mrn': DVH_SQL().change_mrn(old, new) elif self.change_mrn_uid_column.value == 'study_instance_uid': DVH_SQL().change_uid(old, new) self.change_mrn_uid_old_value.value = '' self.change_mrn_uid_new_value.value = '' self.change_mrn_uid_button.label = 'Rename' self.change_mrn_uid_button.button_type = 'warning' self.update_query_source() def delete_auth_text_ticker(self, attr, old, new): self.delete_from_db_button.button_type = ['warning', 'danger'][new == 'delete'] def import_inbox(self): if self.import_inbox_button.label in {'Cancel'}: self.rebuild_db_button.label = 'Rebuild database' self.rebuild_db_button.button_type = 'warning' else: self.import_inbox_button.button_type = 'warning' self.import_inbox_button.label = 'Importing...' force_update = 0 in self.import_inbox_force.active move_files = 2 in self.import_inbox_force.active import_latest_only = 1 in self.import_inbox_force.active dicom_to_sql(force_update=force_update, import_latest_only=import_latest_only, move_files=move_files) self.roi_manager.update_uncategorized_variation_select() self.import_inbox_button.button_type = 'success' self.import_inbox_button.label = 'Import all from inbox' def rebuild_db_button_click(self): if self.rebuild_db_button.button_type in {'warning'}: self.rebuild_db_button.label = 'Are you sure?' self.rebuild_db_button.button_type = 'danger' self.import_inbox_button.button_type = 'success' self.import_inbox_button.label = 'Cancel' else: directories = load_directories() self.rebuild_db_button.label = 'Rebuilding...' self.rebuild_db_button.button_type = 'danger' self.import_inbox_button.button_type = 'success' self.import_inbox_button.label = 'Import all from inbox' rebuild_database(directories['imported']) self.rebuild_db_button.label = 'Rebuild database' self.rebuild_db_button.button_type = 'warning' def update_all_min_distances_in_db(self, *condition): if condition and condition[0]: condition = " AND (" + condition[0] + ")" else: condition = '' condition = "(LOWER(roi_type) IN ('organ', 'ctv', 'gtv') AND (" \ "LOWER(roi_name) NOT IN ('external', 'skin') OR " \ "LOWER(physician_roi) NOT IN ('uncategorized', 'ignored', 'external', 'skin')))" + condition if 0 in self.calculate_missing_only.active: if condition: condition = "(%s) AND dist_to_ptv_min is NULL" % condition else: condition = "dist_to_ptv_min is NULL" rois = DVH_SQL().query('dvhs', 'study_instance_uid, roi_name, physician_roi', condition) total_rois = float(len(rois)) for i, roi in enumerate(rois): self.calculate_exec_button.label = str( int((float(i) / total_rois) * 100)) + '%' if roi[1].lower() not in {'external', 'skin'} and \ roi[2].lower() not in {'uncategorized', 'ignored', 'external', 'skin'}: print('updating dist to ptv:', roi[1], sep=' ') db_update.min_distances(roi[0], roi[1]) else: print('skipping dist to ptv:', roi[1], sep=' ') def update_all(self, variable, *condition): variable_function_map = { 'ptv_overlap': db_update.treatment_volume_overlap, 'centroid': db_update.centroid, 'spread': db_update.spread, 'cross_section': db_update.cross_section, 'ptv_centroids': db_update.dist_to_ptv_centroids } null_variable = variable if variable == 'ptv_centroids': null_variable = 'dist_to_ptv_centroids' elif variable == 'spread': null_variable = 'spread_x' elif variable == 'cross_section': null_variable = 'cross_section_max' elif variable == 'plan_complexity': null_variable = 'complexity' final_condition = { True: ["(%s is NULL)" % null_variable], False: [] }[0 in self.calculate_missing_only.active] if condition and condition[0]: final_condition.append('(%s)' % condition[0]) final_condition = ' AND '.join(final_condition) rois = DVH_SQL().query('dvhs', 'study_instance_uid, roi_name, physician_roi', final_condition) total_rois = float(len(rois)) for i, roi in enumerate(rois): self.calculate_exec_button.label = str( int((float(i) / total_rois) * 100)) + '%' print('updating %s:' % variable, roi[1], sep=' ') variable_function_map[variable](roi[0], roi[1]) def update_all_tv_overlaps_in_db(self, condition): self.update_all('ptv_overlap', condition) def update_all_centroids_in_db(self, condition): self.update_all('centroid', condition) def update_all_spreads_in_db(self, condition): self.update_all('spread', condition) def update_all_cross_sections_in_db(self, condition): self.update_all('cross_section', condition) def update_all_dist_to_ptv_centoids_in_db(self, condition): self.update_all('ptv_centroids', condition) def update_all_plan_complexities_in_db(self, condition): final_condition = { True: ["(complexity is NULL)"], False: [] }[0 in self.calculate_missing_only.active] if condition and condition[0]: final_condition.append('(%s)' % condition[0]) final_condition = ' AND '.join(final_condition) db_update.plan_complexities(final_condition) def update_all_beam_complexities_in_db(self, condition): final_condition = { True: ["(complexity_min is NULL)"], False: [] }[0 in self.calculate_missing_only.active] if condition and condition[0]: final_condition.append('(%s)' % condition[0]) final_condition = ' AND '.join(final_condition) db_update.beam_complexities(final_condition) def update_all_except_age_in_db(self, *condition): for f in self.calculate_select.options: if f not in {'Patient Ages', 'Default Post-Import'}: self.calculate_select.value = f self.calculate_exec() def update_default_post_import(self, *condition): for f in [ 'PTV Distances', 'PTV Overlap', 'OAR-PTV Centroid Dist', 'Plan Complexities' ]: self.calculate_select.value = f self.calculate_exec() self.calculate_select.value = 'Default Post-Import' # Calculates volumes using Shapely, not dicompyler # This function is not in the GUI @staticmethod def recalculate_roi_volumes(*condition): rois = DVH_SQL().query('dvhs', 'study_instance_uid, roi_name, physician_roi', condition[0]) counter = 0. total_rois = float(len(rois)) for roi in rois: counter += 1. print('updating volume:', roi[1], int(100. * counter / total_rois), sep=' ') db_update.volumes(roi[0], roi[1]) # Calculates surface area using Shapely # This function is not in the GUI @staticmethod def recalculate_surface_areas(*condition): rois = DVH_SQL().query('dvhs', 'study_instance_uid, roi_name, physician_roi', condition[0]) roi_count = float(len(rois)) for i, roi in enumerate(rois): print('updating surface area:', roi[1], int(100. * float(i) / roi_count), sep=' ') db_update.surface_area(roi[0], roi[1]) def reimport_mrn_ticker(self, attr, old, new): new_options = DVH_SQL().get_unique_values('Plans', 'sim_study_date', "mrn = '%s'" % new) if not new_options: new_options = ['MRN not found'] self.reimport_study_date_select.options = new_options self.reimport_study_date_select.value = new_options[0] def reimport_study_date_ticker(self, attr, old, new): if new != 'MRN not found': if new == 'None': new_options = DVH_SQL().get_unique_values( 'Plans', 'study_instance_uid', "mrn = '%s'" % self.reimport_mrn_text.value) else: new_options = DVH_SQL().get_unique_values( 'Plans', 'study_instance_uid', "mrn = '%s' and sim_study_date = '%s'" % (self.reimport_mrn_text.value, new)) else: new_options = ['Study Date not found'] self.reimport_uid_select.options = new_options self.reimport_uid_select.value = new_options[0] def reimport_button_click(self): dicom_directory = DVH_SQL().query( 'DICOM_Files', "folder_path", "study_instance_uid = '%s'" % self.reimport_uid_select.value)[0][0] if os.path.isdir(dicom_directory): if not os.listdir(dicom_directory): print("WARNING: %s is empty." % dicom_directory) print("Aborting DICOM reimport.") else: self.reimport_button.label = "Updating..." self.reimport_button.button_type = 'danger' if self.reimport_old_data_select.value == "Delete from DB": DVH_SQL().delete_rows("study_instance_uid = '%s'" % self.reimport_uid_select.value, ignore_table=['DICOM_Files']) dicom_to_sql(start_path=dicom_directory, force_update=True, move_files=False, update_dicom_catalogue_table=False) self.reimport_button.label = "Reimport" self.reimport_button.button_type = 'warning' self.roi_manager.update_uncategorized_variation_select() self.roi_manager.update_ignored_variations_select() else: print("WARNING: %s does not exist" % dicom_directory) print("Aborting DICOM reimport.") def calculate_exec(self): calc_map = { 'PTV Distances': self.update_all_min_distances_in_db, 'PTV Overlap': self.update_all_tv_overlaps_in_db, 'Patient Ages': recalculate_ages, 'ROI Centroid': self.update_all_centroids_in_db, 'ROI Spread': self.update_all_spreads_in_db, 'ROI Cross-Section': self.update_all_cross_sections_in_db, 'OAR-PTV Centroid Dist': self.update_all_dist_to_ptv_centoids_in_db, 'Beam Complexities': self.update_all_beam_complexities_in_db, 'Plan Complexities': self.update_all_plan_complexities_in_db, 'All (except age)': self.update_all_except_age_in_db, 'Default Post-Import': self.update_default_post_import } start_time = datetime.now() print(str(start_time), 'Beginning %s calculations' % self.calculate_select.value, sep=' ') self.calculate_exec_button.label = 'Calculating...' self.calculate_exec_button.button_type = 'warning' calc_map[self.calculate_select.value](self.calculate_condition.value) self.update_query_source() self.calculate_exec_button.label = 'Perform Calc' self.calculate_exec_button.button_type = 'primary' end_time = datetime.now() print(str(end_time), 'Calculations complete', sep=' ') print_run_time(start_time, end_time, "Calculations for %s" % self.calculate_select.value) def update_csv(self): src_data = [self.source.data] src_names = ['Queried Data'] columns = list(src_data[0]) columns.sort() for i, key in enumerate([ 'mrn', 'study_instance_uid' ]): # move/add mrn and study_instance_uid to the front if key in columns: columns.pop(columns.index(key)) columns.insert(i, key) csv_text = get_csv(src_data, src_names, columns) self.source_csv.data = {'text': [csv_text]}
sliders['{0} exponent'.format(par_name)] = Slider( start=-30, end=0, value=exponents[par_name], step=1, title='{0}: Exponent'.format(par_name)) elif par_name == 'Shunt Resistance' or par_name == 'Series Resistance': sliders['{0} exponent'.format(par_name)] = Slider( start=-2, end=20, value=exponents[par_name], step=1, title='{0}: Exponent'.format(par_name)) #Buttons for saving and fitting Fit_button = Button(label="Perform Fit") Save_button = Button(label="Save Fit") #Button for saving IV data without outliers Save_data_wo_outlier_button = Button(label="Save data without outliers") #Define Drop-down menu for fitting method methods_select = Select(title='Fitting to:', value='Log', options=['Log', 'Linear']) fit_methods_select = Select(title='Fitting method:', value='by eye', options=[ 'By Eye', 'Gradient Descent', 'Brute Force - I_0', 'Brute Force - R_S' ])
def __init__(self, roi_manager): column_width = 600 self.roi_manager = roi_manager # allows ROI Name manager updates after importing data self.source = ColumnDataSource(data=dict()) self.source_csv = ColumnDataSource(data=dict(text=[])) self.import_inbox_button = Button(label='Import all from inbox', button_type='success', width=200) self.import_inbox_button.on_click(self.import_inbox) self.import_inbox_force = CheckboxGroup( labels=['Force Update', 'Import Latest Only', 'Move Files'], active=[1, 2]) self.rebuild_db_button = Button(label='Rebuild database', button_type='warning', width=200) self.rebuild_db_button.on_click(self.rebuild_db_button_click) self.query_table = Select( value='Plans', options=['DVHs', 'Plans', 'Rxs', 'Beams', 'DICOM_Files'], width=200, title='Table:') self.query_columns = MultiSelect( title="Columns (Ctrl or Shift Click enabled):", width=250, options=[tuple(['', ''])], size=10) self.query_condition = TextInput(value='', title="Condition:", width=450) self.query_button = Button(label='Query', button_type='primary', width=100) self.query_table.on_change('value', self.update_query_columns_ticker) self.query_button.on_click(self.update_query_source) self.update_db_title = Div(text="<b>Update Database</b>", width=column_width) self.update_db_table = Select( value='DVHs', options=['DVHs', 'Plans', 'Rxs', 'Beams'], width=80, title='Table:') self.update_db_column = Select(value='', options=[''], width=175, title='Column') self.update_db_value = TextInput(value='', title="Value:", width=200) self.update_db_condition = TextInput(value='', title="Condition:", width=350) self.update_db_button = Button(label='Update DB', button_type='warning', width=100) self.update_db_table.on_change('value', self.update_update_db_columns_ticker) self.update_db_button.on_click(self.update_db) self.update_query_columns() self.update_update_db_column() self.reimport_title = Div(text="<b>Reimport from DICOM</b>", width=column_width) self.reimport_mrn_text = TextInput(value='', width=200, title='MRN:') self.reimport_study_date_select = Select(value='', options=[''], width=200, title='Sim Study Date:') self.reimport_uid_select = Select(value='', options=[''], width=425, title='Study Instance UID:') self.reimport_old_data_select = Select( value='Delete from DB', options=['Delete from DB', 'Keep in DB'], width=150, title='Current Data:') self.reimport_button = Button(label='Reimport', button_type='warning', width=100) self.reimport_mrn_text.on_change('value', self.reimport_mrn_ticker) self.reimport_study_date_select.on_change( 'value', self.reimport_study_date_ticker) self.reimport_button.on_click(self.reimport_button_click) self.query_data_table = DataTable(source=self.source, columns=[], width=column_width, editable=True, height=600) self.delete_from_db_title = Div( text="<b>Delete all data with mrn or study_instance_uid</b>", width=column_width) self.delete_from_db_column = Select( value='mrn', options=['mrn', 'study_instance_uid'], width=200, title='Patient Identifier:') self.delete_from_db_value = TextInput(value='', title="Value (required):", width=300) self.delete_from_db_button = Button(label='Delete', button_type='warning', width=100) self.delete_auth_text = TextInput( value='', title="Type 'delete' here to authorize:", width=300) self.delete_auth_text.on_change('value', self.delete_auth_text_ticker) self.delete_from_db_button.on_click(self.delete_from_db) self.change_mrn_uid_title = Div( text="<b>Change mrn or study_instance_uid in all tables</b>", width=column_width) self.change_mrn_uid_column = Select( value='mrn', options=['mrn', 'study_instance_uid'], width=200, title='Patient Identifier:') self.change_mrn_uid_old_value = TextInput(value='', title="Old:", width=300) self.change_mrn_uid_new_value = TextInput(value='', title="New:", width=300) self.change_mrn_uid_button = Button(label='Rename', button_type='warning', width=100) self.change_mrn_uid_button.on_click(self.change_mrn_uid) self.calculations_title = Div(text="<b>Post Import Calculations</b>", width=column_width) self.calculate_condition = TextInput(value='', title="Condition:", width=350) self.calculate_options = [ 'Default Post-Import', 'PTV Distances', 'PTV Overlap', 'ROI Centroid', 'ROI Spread', 'ROI Cross-Section', 'OAR-PTV Centroid Dist', 'Beam Complexities', 'Plan Complexities', 'All (except age)', 'Patient Ages' ] self.calculate_select = Select(value=self.calculate_options[0], options=self.calculate_options, title='Calculate:', width=150) self.calculate_missing_only = CheckboxGroup( labels=['Only Calculate Missing Values'], active=[0], width=280) self.calculate_exec_button = Button(label='Perform Calc', button_type='primary', width=150) self.calculate_exec_button.on_click(self.calculate_exec) self.download = Button(label="Download Table", button_type="default", width=150) self.download.callback = CustomJS(args=dict(source=self.source_csv), code=open( join(dirname(dirname(__file__)), 'download_new.js')).read()) self.layout = row( column( row(self.import_inbox_button, Spacer(width=20), self.rebuild_db_button, Spacer(width=50), self.import_inbox_force), self.calculations_title, row(self.calculate_select, Spacer(width=20), self.calculate_missing_only, self.calculate_exec_button), self.calculate_condition, Div(text="<hr>", width=column_width), self.update_db_title, row(self.update_db_table, self.update_db_column, self.update_db_value, Spacer(width=45), self.update_db_button), self.update_db_condition, Div(text="<hr>", width=column_width), self.reimport_title, row(self.reimport_mrn_text, Spacer(width=10), self.reimport_old_data_select, Spacer(width=140), self.reimport_button), row(self.reimport_study_date_select, self.reimport_uid_select), Div(text="<hr>", width=column_width), row(self.delete_from_db_title), row(self.delete_from_db_column, Spacer(width=300), self.delete_from_db_button), row(self.delete_from_db_value, self.delete_auth_text), Div(text="<hr>", width=column_width), row(self.change_mrn_uid_title), row(self.change_mrn_uid_column, Spacer(width=300), self.change_mrn_uid_button), row(self.change_mrn_uid_old_value, self.change_mrn_uid_new_value)), column(Div(text="<b>Query Database</b>", width=column_width), row(self.query_table, self.query_columns), self.query_condition, row(self.query_button, Spacer(width=25), self.download), self.query_data_table))
def selection_plot(response): # Let's move these into a settings file somewhere? # height/width could potentially be driven by the request? # Include color data in the ColumnDataSource to allow for changing the color on # the client side. urls = [x[0] for x in response["pages"]] xdata = [x[1] for x in response["pages"]] ydata = [x[2] for x in response["pages"]] tags = [x[3] for x in response["pages"]] color = [colormap(x[0]) if x else colormap(None) for x in tags] source = ColumnDataSource( data=dict( x=xdata, y=ydata, urls=urls, tags=tags, color=color, ) ) # Callback code for CDS. source.callback = CustomJS(code=""" var inds = cb_obj.get('selected')["1d"].indices; var data = cb_obj.get('data'); BokehPlots.showPages(inds); """) # Create the figure with FIGURE_WIDTH and FIGURE_HEIGHT p = figure(tools="hover", width=FIGURE_WIDTH, toolbar_location=None, responsive=True, tags=["clusterPlot"]) # Ensure that the lasso only selects with mouseup, not mousemove. p.add_tools(LassoSelectTool(select_every_mousemove=False)) # These turn off the x/y axis ticks p.axis.visible = None # These turn the major grid off p.xgrid.grid_line_color = None p.ygrid.grid_line_color = None # Plot non-selected circles with a particular style using CIRCLE_SIZE and # 'color' list p.circle("x", "y", size=13, line_width=2, line_alpha=1, line_color=None, fill_alpha=1, color='color', source=source, name="urls") nonselected_circle = Circle(fill_alpha=0.1, line_alpha=0.1, fill_color='color', line_color='color') renderer = p.select(name="urls") renderer.nonselection_glyph = nonselected_circle # Create buttons and their callbacks, use button_code string for callbacks. button_code = """ event.preventDefault(); var inds = source.get('selected')["1d"].indices; var data = source.get('data'); var selected = []; tag = "%s"; for(var i = 0; i < inds.length; i++){ selected.push({ x: data.x[inds[i]], y: data.y[inds[i]], url: data.urls[inds[i]], tags: data.tags[inds[i]], selected: true, possible: false, }); data["color"][inds[i]] = "%s"; } BokehPlots.updateTags(selected, tag, inds); source.trigger("change"); """ # Supply color with print formatting. button1 = Button(label="Relevant", type="success") button1.callback = CustomJS(args=dict(source=source), code=button_code % ("Relevant", POSITIVE_COLOR)) button2 = Button(label="Irrelevant", type="success") button2.callback = CustomJS(args=dict(source=source), code=button_code % ("Irrelevant", NEGATIVE_COLOR)) button3 = Button(label="Neutral", type="success") button3.callback = CustomJS(args=dict(source=source), code=button_code % ("Neutral", NEUTRAL_COLOR)) # Adjust what attributes are displayed by the HoverTool hover = p.select(dict(type=HoverTool)) hover.tooltips = [ ("urls", "@urls"), ] layout = vform(p, button1, button2, button3) # Combine script and div into a single string. plot_code = components(layout) return plot_code[0] + plot_code[1]
width=140, min_date=datetime.date(2020, 1, 1), max_date=today, value=today) end_date.on_change('value', refresh_plot) end_hour = select = Select(title='hour', value="23", options=hours, width=70) end_minute = select = Select(title='min', value="59", options=minutes, width=70) end_hour.on_change('value', refresh_plot) end_minute.on_change('value', refresh_plot) ## live button live_button = Button(width=130, margin=[15, 10, 15, 10], label="live", button_type="default") live_button.js_on_click(CustomJS(code=""" window.location.href='./live'; """)) ## force update_data() history_button = Button(width=130, margin=[15, 10, 15, 10], label="history", button_type="primary") history_button.on_click(plot_data) tz_text = Paragraph(text=f"timezone: {timezone}", width=340) controls = column(row(live_button, history_button), instrum_select, row(start_date, start_hour, start_minute), row(end_date, end_hour, end_minute), tz_text)
### NOTE: The csv export will not work on Safari import bokeh import pandas as pd from bokeh.plotting import ColumnDataSource from bokeh.models import CustomJS, HBox, VBox, VBoxForm from bokeh.models.widgets import Slider, Button, DataTable, TableColumn from bokeh.io import curdoc, vform # note this is fake data df = pd.read_csv('salary_data.csv') salary_range = Slider(title="Max Salary", start=10000, end=250000, value=150000, step=1000) button = Button(label="Download") button.button_type = "success" source = ColumnDataSource(data=dict()) columns = [TableColumn(field="name", title="Employee Name"), TableColumn(field="salary", title="Income"), TableColumn(field="years_experience", title="Experience (years)")] data_table = DataTable(source=source, columns=columns) def update(attr, old, new): curr_df = df[df['salary'] <= salary_range.value].dropna() source.data = dict(name=curr_df['name'].tolist(), salary=curr_df['salary'].tolist(), years_experience=curr_df['years_experience'].tolist())
def start_handler(): global playing if not playing: curdoc().add_periodic_callback(update, 50) playing = True def stop_handler(): global playing if playing: curdoc().remove_periodic_callback(update) playing = False button_start = Button(label="Start", button_type="success") button_start.on_click(start_handler) button_stop = Button(label="Stop", button_type="danger") button_stop.on_click(stop_handler) controls = hplot(button_start, button_stop) layout = vplot(controls, p) @cosine(w=0.03) def update(step): if playing: r2.data_source.data["y"] = y * step r2.glyph.line_alpha = 1 - 0.8 * abs(step)
def config_tab(self): """Reading/writing device configuration""" # True if the config device data has been read, false otherwise self.config_device_read = False # Device connectivity # =================== config_conn_head = Div(text="<strong>Connectivity</strong>") self.config_status = Div(text="", width=self.page_width) config_connect = Button(label='Connect to UT330', button_type="success") config_read = Button(label='Read config', button_type="success") config_write = Button(label='Write config', button_type="success") config_disconnect = Button(label='Disconnect from UT330', button_type="success") config_connect.on_click(self.config_connect) config_read.on_click(self.config_read) config_write.on_click(self.config_write) config_disconnect.on_click(self.config_disconnect) # Show the configuration data # =========================== # Set up the widgets config_device_head = Div(text="<strong>Configuration</strong>") self.config_device_name = TextInput(title="Device name") self.config_device_time = TextInput(title="Device time") self.config_computer_time = TextInput(title="Computer time") self.config_t_high = TextInput(title="High temperature alarm (C)") self.config_t_low = TextInput(title="Low temperature alarm (C)") self.config_h_high = TextInput(title="High humidity alarm (%RH)") self.config_h_low = TextInput(title="Low humidity alarm (%RH)") self.config_p_high = TextInput(title="High pressure alarm") self.config_p_low = TextInput(title="Low pressure alarm") self.config_sampling = TextInput(title="Sampling interval (s)") self.config_overwrite_records = Select(title="Overwrite records", options=['False', 'True']) self.config_delay_start = Select(title="Delay start", options=['No delay', 'Delay']) self.config_delay = TextInput(title="Delay (s)") # Status data # =========== config_status_head = Div(text="<strong>Status</strong>") self.config_power = TextInput(title="Battery power (%)") self.config_readings = TextInput(title="Readings") # Disable user input for these widgets self.config_power.disabled = True self.config_readings.disabled = True # Values to widgets # ================= if self.device_connected: self.config_connected() else: self.config_not_connected() # Set up the display layout = column(row(config_conn_head), row(self.config_status), row(config_connect, config_read, config_write, config_disconnect), row(config_device_head), row(self.config_device_name, self.config_device_time, self.config_computer_time), row(self.config_t_low, self.config_h_low, self.config_p_low), row(self.config_t_high, self.config_h_high, self.config_p_high), row(self.config_sampling), row(self.config_overwrite_records, self.config_delay_start, self.config_delay), row(config_status_head), row(self.config_power, self.config_readings)) return Panel(child=layout, title="Read/write configuration")
def make_document(doc): doc.title = "Hello, world!" df = pd.read_csv(fileName) # return dataframe if False: df = df.set_index('date') ''' make a copy of df. therefor changing the source will not affect df. using df in update() will ~reset the source to original values ''' source = ColumnDataSource(data=df) # dict()) columns = [ TableColumn(field="name", title="Employee Name"), TableColumn(field="salary", title="Income", formatter=NumberFormatter(format="$0,0.00")), TableColumn(field="years_experience", title="Experience (years)") ] data_table = DataTable(source=source, columns=columns, width=800) # ,row_headers=None) table = widgetbox(data_table, width=880) def slider_table_update(attr, old, new): print ("slider update") print(attr) print(old) print(new) current = df[df['salary'] <= slider.value].dropna() # df ## source.data = { 'name' : current.name, 'salary' : current.salary, 'years_experience' : current.years_experience } return None slider = Slider(title="values range", start=0, end=100000, value=21000, step=1, width=800) slider.on_change('value', lambda attr, old, new: slider_table_update(attr, old, new)) # fig1 = figure(title='Line plot!') #, sizing_mode='scale_width') # fig1.line(x=[1, 2, 3], y=[1, 4, 9]) #, sizing_mode='scale_width') ) # , y_range=(00000, 100000), # fig2.scatter(x=source.data['years_experience'], y=source.data['salary']) # title="scatter example") #, xlabel="xlable", ylabel="ylabel") # plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6) selected_tools = 'pan,wheel_zoom,xbox_select,reset' fig2 = figure(title='salary - vs years scatter plot', width=500, height=400, tools='pan, wheel_zoom') fig2.scatter(x='years_experience', y='salary', source=source) # https://stackoverflow.com/questions/34646270/how-do-i-work-with-images-in-bokeh-python # img_path = 'https://bokeh.pydata.org/en/latest/_static/images/logo.png' img_path = join(DATA_DIR,'logoScrnSht.png') # img_path = r'C:\Users\Ran_the_User\Documents\GitHub\TAILOR\bokeh\bokeh_pages\static\logoScrnSht.png' x_range = (-20,10) # could be anything - e.g.(0,1) y_range = (20,30) factor = 1.2 figImg = figure(x_range=x_range, y_range=y_range) # figImg = figure(x_range=x_range, y_range=y_range, width=500, height=400) print (img_path) figImg.image_url(url=[img_path], x=x_range[0], y=y_range[1], w=x_range[1]-x_range[0], h=y_range[1]-y_range[0]) # figImg.image_url(url=[img_path], x=x_range[0]/factor, y=(y_range[0]+y_range[1])/2, w=(x_range[1]-x_range[0])/factor, h=(y_range[1]-y_range[0])/factor, anchor="bottom_left") toggle_callback = CustomJS(args=dict(source=source), code=""" var data = source.data; var A = a.value; var k = b.value; var phi = c.value; var B = d.value; var x = data['years_experience'] var y = data['salary'] for (var i = 0; i < x.length; i++) { y[i] =i*2.; } source.change.emit(); """) def isToggleActive(status): print("toggle case") print(status) def on_chkbx_clicked(list_of_checked_options): print("chkbx case") print(list_of_checked_options) def on_radio_clicked(checked_option_ndx): print("cradio case") print(checked_option_ndx) # toggle = Toggle(label='Some on/off', button_type='success') toggle = Button(label='change table by source', button_type='success', callback=toggle_callback) # toggleLayout = layout([toggle]) checkbox = CheckboxGroup(labels=['foo', 'bar', 'baz']) radio = RadioGroup(labels=['2000', '2010', '2020']) # toggle.on_click(isToggleActive) checkbox.on_click(on_chkbx_clicked) radio.on_click(on_chkbx_clicked) checkbox_button_group = CheckboxButtonGroup( labels=["Option 1", "Option 2", "Option 3"], active=[0, 1]) def set_vbar(): fruits = ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries'] fig3 = figure(x_range=fruits, plot_height=250, title="Fruit Counts", toolbar_location=None, tools="") fig3.vbar(x=fruits, top=[5, 3, 4, 2, 4, 6], width=0.9) fig3.xgrid.grid_line_color = None fig3.y_range.start = 0 return fig3 def event_chart(): factors = ["a","b","c,","d"] x = [24.3, -22.3, -25, 6] LineColor=["green" if a>=0 else "red" for a in x] Tooltips = [ ("index", "$index"), ("(x,y)", "($x, $y)") # ("radius", "@radius"), # ("fill color", "$color[hex, swatch]:fill_color"), # ("x", "@x"), # ("bar", "@bar"), ] dots_fig = figure(title="exapmple", y_range = factors, x_range = [-30,30], toolbar_location="below", toolbar_sticky=False, \ tools='lasso_select, poly_select, undo, redo, reset') # , \ # tooltips=Tooltips) dots_fig.segment(0, factors, x, factors, line_width=2, line_color=LineColor) c1 = dots_fig.circle(x, factors, size=15, fill_color="orange", line_width=3, line_color=LineColor) # tool = BoxEditTool(renderers=[c1]) tool2 = BoxSelectTool(dimensions="width") # To make a multiple selection, press the SHIFT key. To clear the selection, press the ESC key # dots_fig.add_tools(tool) # disappears the points.. dots_fig.add_tools(tool2) dots_fig.add_tools(CrosshairTool(dimensions='height')) return dots_fig # fig2.axis.visible = False # fig2.image phase1 = column(table, slider) phase2 = row(phase1, fig2) phase3 = row(event_chart(), set_vbar()) phase4 = column(phase2, phase3 , checkbox, radio) # phase5 = bk_example.bk_example() # doc.add_root(phase5) # doc.add_root(phase4) tab1 = Panel(child=phase4, title="phase4 part") # doc.add_root(toggle) # doc.add_root(figImg) secPanelLy = column(toggle, figImg, checkbox_button_group) tab2 = Panel(child=secPanelLy, title="other parts", closable=False) tabs = Tabs(tabs=[ tab1, tab2 ]) if __name__!='__main__': print("doc : ", doc) print("name : ",__name__) doc().add_root(tabs) else: doc.add_root(tabs) # doc.add_root(event_chart_example()) toggle_callback.args['a']=slider toggle_callback.args['b']=toggle toggle_callback.args['c']=checkbox toggle_callback.args['d']=radio
def device_data_tab(self): """Reading device data""" self.data_status = Div(text="", width=self.page_width) data_connect = Button(label='Connect to UT330', button_type="success") data_read = Button(label='Read data', button_type="success") data_write = Button(label='Write data to disk', button_type="success") data_erase = Button(label='Erase data', button_type="success") data_disconnect = Button(label='Disconnect from UT330', button_type="success") data_connect.on_click(self.data_connect) data_read.on_click(self.data_read) data_write.on_click(self.data_write) data_erase.on_click(self.data_erase) data_disconnect.on_click(self.data_disconnect) if self.device_connected: self.data_status.text = ('UT330 device connected. The Read, ' 'Write, Erase, and Disconnect buttons ' 'will work.') else: self.data_status.text = ('UT330 device is <strong>NOT</strong> ' 'connected. The ' 'Read, Write, Erase, and Disconnect ' 'buttons will <strong>not work</strong>. ' 'Press the ' 'Connect button if the UT330 is ' 'connected on a USB port.') # Layout l = layout([[self.data_status], [data_connect, data_disconnect], [data_read, data_write, data_erase]], width=self.page_width) return Panel(child=l, title="Read from device")
f_photo.title.text_color = (0.7, 0.7, 0.7) f_photo.title.text_font = 'helvetica' f_photo.title.text_font_size = '20pt' f_photo.title.align = 'left' #Style the grid f_photo.grid.grid_line_color = (1, 1, 1) f_photo.grid.grid_line_alpha = 0.3 f_photo.grid.grid_line_dash = [5, 3] f_aux.grid.grid_line_color = (1, 1, 1) f_aux.grid.grid_line_alpha = 0.3 f_aux.grid.grid_line_dash = [5, 3] #add widgets (dropdown button) to save data as csv. CustomJS required to download data in browser button = Button(label='Export data', button_type='danger') js_download = """ var csv = source.get('data'); var filetext = 'time;photo_current;laser_current;temperature;date\\n'; for (i=0; i < csv['date'].length; i++) { var currRow = [csv['time'][i].toString(), csv['photo_current'][i].toString(), csv['laser_current'][i].toString(), csv['date'][i].toString().concat('\\n')]; var joined = currRow.join(';'); filetext = filetext.concat(joined); } var filename = 'sensor_data.csv'; var blob = new Blob([filetext], { type: 'text/csv;charset=utf-8;' });
print 'After: ' + str(undefinedSource.data) + '\n' ########################################################################### # Setup figure, glyphs, and a datasource glyphDict = create_glyphs() undefinedSource = bkM.ColumnDataSource(data=dict(x=[0,4,8], y=[0,0,0], width=[0.25,0.25,0.25], height=[2,2,2])) fig = create_fig() ########################################################################### # Add widgets and their callbacks from bokeh.models.widgets import Button, TextInput changeA_button = Button(label='UpdateFig A') changeA_button.on_click(update_figure_A) changeB_button = Button(label='UpdateFig B') changeB_button.on_click(update_figure_B) widgets = [changeA_button, changeB_button] from bokeh.layouts import widgetbox widgetBox = widgetbox(*widgets, sizing_mode='fixed') # Add figure and widgets to a layout ########################################################################### from bokeh.layouts import layout layout = layout( [[fig], [widgetBox]], sizing_mode='fixed')
df = pd.read_csv(join(dirname(__file__), 'salary_data.csv')) source = ColumnDataSource(data=dict()) def update(): current = df[(df['salary'] >= slider.value[0]) & (df['salary'] <= slider.value[1])].dropna() source.data = { 'name' : current.name, 'salary' : current.salary, 'years_experience' : current.years_experience, } slider = RangeSlider(title="Max Salary", start=10000, end=110000, value=(10000, 50000), step=1000, format="0,0") slider.on_change('value', lambda attr, old, new: update()) button = Button(label="Download", button_type="success") button.callback = CustomJS(args=dict(source=source), code=open(join(dirname(__file__), "download.js")).read()) columns = [ TableColumn(field="name", title="Employee Name"), TableColumn(field="salary", title="Income", formatter=NumberFormatter(format="$0,0.00")), TableColumn(field="years_experience", title="Experience (years)") ] data_table = DataTable(source=source, columns=columns, width=800) controls = widgetbox(slider, button) table = widgetbox(data_table) curdoc().add_root(row(controls, table))
def plotting(self): if self.debug: self.debug_file = open("debug_output.txt", "w") self.debug_file.write("Initialized plotting subroutine \n") TOOLS="pan,wheel_zoom,box_zoom,reset,hover,previewsave" tab_plots = [] self.all_elements = [] self.elements_comparison = [] for filename in self.filenames: if "ITO" in filename: tab_plots.append(self.mass_plotting(filename)) continue data_dict = self.data_generation(filename) self.data_test(data_dict) name_check = data_dict["gen_info"]["DATA FILES"] attr_id = name_check[1][4][:-3] + "_" + name_check[2][2] self.attribute_ids.append(attr_id) attr_extra_y_ranges = False attr_extra_x_ranges = False local_source_line = [] """ create plots for each datafile and put them in a tab. """ y_axis_units = [x["y_unit"] for x in data_dict["data"]] x_axis_units = [x["x_unit"] for x in data_dict["data"]] figure_obj = figure(plot_width = 1000, plot_height = 800, y_axis_type = "log", title = attr_id, tools = TOOLS) #figure_obj.axes.major_label_text_font_size("12pt") #figure_obj.major_label_text_font_size("12pt") hover = figure_obj.select(dict(type = HoverTool)) hover.tooltips = [ ("Element:", "@element"), ("(x, y):", "($x, $y)")] self.figure_data.append((figure_obj, data_dict)) figure_obj.yaxis.axis_label = y_axis_units[0] figure_obj.xaxis.axis_label = x_axis_units[0] if not all(x == y_axis_units[0] for x in y_axis_units): for unit, dataset in zip(y_axis_units, data_dict["data"]): if not unit == y_axis_units[0]: extra_y_ranges_exists = attr_extra_y_ranges extra_y_ranges_exists = True if self.debug: self.debug_file.write("Added extra y-axis for file_id: %s, element: %s | New length %g \n" %(attr_id, dataset["sample_element"], len(figure_obj.yaxis))) figure_obj.extra_y_ranges = {"foo": Range1d(start = np.amin(dataset["y"]), end = np.amax(dataset["y"]))} figure_obj.add_layout(LogAxis(y_range_name = "foo", axis_label = unit), "right") break if not all(x == x_axis_units[0] for x in x_axis_units): for unit, dataset in zip(x_axis_units, data_dict["data"]): if not unit == x_axis_units[0]: extra_x_ranges_exists = attr_extra_x_ranges extra_x_ranges_exists = True if self.debug: self.debug_file.write("Added extra x-axis for file_id: %s, element: %s. | New length %g \n" %(attr_id, dataset["sample_element"], len(figure_obj.yaxis))) figure_obj.extra_x_ranges = {"bar": Range1d(start = np.amin(dataset["x"]), end = np.amax(dataset["x"]))} figure_obj.add_layout(LinearAxis(x_range_name = "bar", axis_label = unit), "above") break figure_obj.xaxis.axis_label = x_axis_units[0] colour_list = Spectral11 + RdPu9 + Oranges9 colour_indices = [0, 2, 8, 10, 12, 14, 20, 22, 1, 3, 9, 11, 13, 15] list_of_elements = [] source_list = [] line_list = [] for dataset, color_index in zip(data_dict["data"], colour_indices): self.all_elements.append(dataset["sample_element"]) #strip isotope number color = colour_list[color_index] source = ColumnDataSource(data = dataset) #Datastructure for source of plotting self.source_test(source) list_of_elements.append(dataset["sample_element"]) line_glyph = figure_obj.line("x", "y", source = source, line_width = 2, line_color = color, legend = dataset["sample_element"]) if self.debug: self.debug_file.write("Create line object on figure %s at %s \n" %(id(figure_obj), id(line_glyph))) line_list.append(line_glyph) source_list.append(source) local_source_line.append([[source, line] for source, line in zip(source_list, line_list)]) self.source_line.append(local_source_line) #Calculations on the dataset text_input_rsf = TextInput(value = "default", title = "RSF or SF (at/cm^3): ") do_integral_button = Button(label = "Calibration integral") smoothing_button = Button(label = "smth selct elem") matplot_button = Button(label = "Create matplotlib fig") text_input_sputter = TextInput(value = "default", title = "Sputter speed: number unit") text_input_crater_depth = TextInput(value = "default", title = "Depth of crater in: number unit") radio_group = RadioGroup(labels = list_of_elements, active=0) text_input_xval_integral = TextInput(value = "0", title = "x-delimiter ") text_input_dose = TextInput(value = "0", title = "Dose[cm^-2] ") #Save files for later use save_flexDPE_button = Button(label = "Save element for FlexPDE") save_all_flexDPE_button = Button(label = "Save all elements for FlexPDE") save_textfile_button = Button(label = "Sava Data in textfile") #Pointers to methods on click / change handlers radio_group.on_change("active", lambda attr, old, new: None) matplot_button.on_click(lambda source_list = source_list: self.matplotlib_export(source_list)) do_integral_button.on_click(lambda source_list = source_list, line_list = line_list, source_line = self.source_line, figure_data = self.figure_data, data_dict = data_dict, radio = radio_group, x_box = text_input_xval_integral, dose = text_input_dose, extra_y_ranges = attr_extra_y_ranges: self.integrate(data_dict, source_list, line_list, source_line, figure_data, radio, x_box, dose, extra_y_ranges)) smoothing_button.on_click(lambda source_list = source_list, radio = radio_group, data_dict = data_dict, x_box = text_input_xval_integral: self.smoothing(source_list, data_dict, radio, x_box) ) save_flexDPE_button.on_click(lambda source_list = source_list, attrname = attr_id, radio = radio_group: self.write_to_flexPDE(source_list, attrname, radio)) save_all_flexDPE_button.on_click(lambda source_list = source_list, attrname = attr_id: self.write_all_to_flexPDE(source_list, attrname)) save_textfile_button.on_click(lambda data_dict = data_dict, source_list = source_list, attrname = attr_id, radio = radio_group: self.write_new_datafile(data_dict, source_list, attrname,radio)) text_input_rsf.on_change("value", lambda attr, old, new, radio = radio_group, data_dict = data_dict, figure = figure_obj, source_list = source_list, text_input = text_input_rsf, line_list = line_list, which = "rsf": self.update_data(line_list, data_dict, source_list, figure, radio, text_input, new, which)) text_input_sputter.on_change("value", lambda attr, old, new, radio = radio_group, data_dict = data_dict, figure = figure_obj, source_list = source_list, text_input = text_input_sputter, which = "sputter": self.update_data(data_dict, source_list, figure, radio, text_input, new, which)) text_input_crater_depth.on_change("value", lambda attr, old, new, radio = radio_group, data_dict = data_dict, source_list = source_list, figure = figure_obj, text_input = text_input_crater_depth, which = "crater_depth": self.update_data(data_dict, source_list, figure, radio, text_input, new, which)) #Initialization of actual plotting. tab_plots.append(Panel(child = hplot(figure_obj, vform( vform(radio_group, save_flexDPE_button, save_all_flexDPE_button, save_textfile_button, matplot_button), vform(text_input_rsf, smoothing_button, text_input_sputter, text_input_crater_depth) ), vform(text_input_xval_integral, text_input_dose, do_integral_button)), title = attr_id)) """ Check to see if one or more element exists in the samples and creat a comparison plot for each of those elements. """ for element in self.all_elements: checkers = list(self.all_elements) checkers.remove(element) if element in checkers and not element in self.elements_comparison: self.elements_comparison.append(element) """create plots for each element that is to be compared """ for comparison_element in self.elements_comparison: figure_obj = figure(plot_width = 1000, plot_height = 800, y_axis_type = "log", title = comparison_element, tools = TOOLS) #figure_obj.xaxis.major_label_text_font_size("12pt") #figure_obj.yaxis.major_label_text_font_size("12pt") y_axis_units = [] x_axis_units = [] comparison_datasets = [] for data_dict_iter in self.column(self.figure_data, 1): for dataset in data_dict_iter["data"]: if dataset["sample_element"] == comparison_element: comparison_datasets.append(dataset) y_axis_units.append(dataset["y_unit"]) x_axis_units.append(dataset["x_unit"]) figure_obj.xaxis.axis_label = comparison_datasets[-1]["x_unit"] figure_obj.yaxis.axis_label = comparison_datasets[-1]["y_unit"] if not all(x == y_axis_units[-1] for x in y_axis_units): for unit, data in zip(y_axis_units, comparison_datasets): if not unit == y_axis_units[-1]: figure_obj.extra_y_ranges = {"foo": Range1d(start = np.amin(data["y"]), end = np.amax(data["y"]))} figure_obj.add_layout(LogAxis(y_range_name = "foo", axis_label = unit), "right") break if not all(x == x_axis_units[-1] for x in x_axis_units): for unit, data in zip(x_axis_units, comparison_datasets): if not unit == x_axis_units[-1]: figure_obj.extra_x_ranges = {"bar": Range1d(start = np.amin(data["x"]), end = np.amax(data["x"]))} figure_obj.add_layout(LinearAxis(x_range_name = "bar", axis_label = unit), "above") break active_sources = [] for data_dict, source_line_nested, attr_id, color_index in zip(self.column(self.figure_data, 1), self.source_line, self.attribute_ids, colour_indices): for dataset, source_lis_coup, in zip(data_dict["data"], source_line_nested[0]): source_local = source_lis_coup[0] active_sources.append(source_local) self.source_test(source_local) self.source_dataset_test(source_local, dataset) if dataset["sample_element"] == comparison_element: color = colour_list[color_index] """ Logic that ensures that plots get put with correspoinding axes. """ if dataset["x_unit"] != x_axis_units[-1] or dataset["y_unit"] != y_axis_units[-1]: if dataset["x_unit"] != x_axis_units[-1] and dataset["y_unit"] != y_axis_units[-1]: name_check = data_dict["gen_info"]["DATA FILES"] attr_id = name_check[1][4][:-3] + "_" + name_check[2][2] figure_obj.line("x", "y", source = source_local, line_width = 2, line_color = color, legend = attr_id, x_range_name = "bar", y_range_name = "foo") elif dataset["x_unit"] != x_axis_units[-1]: figure_obj.line("x", "y", source = source_local, line_width = 2, line_color = color, legend = attr_id, x_range_name = "bar") else: figure_obj.line("x", "y", source = source_local, line_width = 2, line_color = color, legend = attr_id, y_range_name = "foo") else: figure_obj.line("x", "y", source = source_local, line_width = 2, line_color = color, legend = attr_id) matplot_button = Button(label = "Create matplotlib fig") save_all_flexDPE_button = Button(label = "Save all elements for FlexPDE") matplot_button.on_click(lambda source_list = active_sources: self.matplotlib_export(source_list)) save_all_flexDPE_button.on_click(lambda source_list = active_sources, attrname = comparison_element: self.write_all_to_flexPDE(source_list, attrname)) tab_plots.append(Panel(child = hplot(figure_obj, vform(save_all_flexDPE_button, matplot_button)), title = comparison_element)) tabs = Tabs(tabs = tab_plots) #curdoc().add_root(tabs) session = push_session(curdoc()) session.show() session.loop_until_closed()
def plot(): # FIGURES AND X-AXIS fig1 = Figure(title = 'Dive Profile', plot_width = WIDTH, plot_height = HEIGHT, tools = TOOLS) fig2 = Figure(title = 'Dive Controls', plot_width = WIDTH, plot_height = HEIGHT, tools = TOOLS, x_range=fig1.x_range) fig3 = Figure(title = 'Attitude', plot_width = WIDTH, plot_height = HEIGHT, tools = TOOLS, x_range=fig1.x_range) figs = gridplot([[fig1],[fig2],[fig3]]) # Formatting x-axis timeticks = DatetimeTickFormatter(formats=dict(seconds =["%b%d %H:%M:%S"], minutes =["%b%d %H:%M"], hourmin =["%b%d %H:%M"], hours =["%b%d %H:%M"], days =["%b%d %H:%M"], months=["%b%d %H:%M"], years =["%b%d %H:%M %Y"])) fig1.xaxis.formatter = timeticks fig2.xaxis.formatter = timeticks fig3.xaxis.formatter = timeticks # removing gridlines fig1.xgrid.grid_line_color = None fig1.ygrid.grid_line_color = None fig2.xgrid.grid_line_color = None fig2.ygrid.grid_line_color = None fig3.xgrid.grid_line_color = None fig3.ygrid.grid_line_color = None # INPUT WIDGETS collection_list = CONN[DB].collection_names(include_system_collections=False) gliders = sorted([platformID for platformID in collection_list if len(platformID)>2]) gliders = Select(title = 'PlatformID', value = gliders[0], options = gliders) prev_glider = Button(label = '<') next_glider = Button(label = '>') glider_controlbox = HBox(children = [gliders, prev_glider, next_glider], height=80) chunkations = Select(title = 'Chunkation', value = 'segment', options = ['segment', '24hr', '30days', '-ALL-']) chunk_indicator = TextInput(title = 'index', value = '0') prev_chunk = Button(label = '<') next_chunk = Button(label = '>') chunk_ID = PreText(height=80) chunk_controlbox = HBox(chunkations, HBox(chunk_indicator, width=25), prev_chunk, next_chunk, chunk_ID, height = 80) control_box = HBox(glider_controlbox, chunk_controlbox) # DATA VARS deadby_date = '' depth = ColumnDataSource(dict(x=[],y=[])) vert_vel = ColumnDataSource(dict(x=[],y=[])) mbpump = ColumnDataSource(dict(x=[],y=[])) battpos = ColumnDataSource(dict(x=[],y=[])) pitch = ColumnDataSource(dict(x=[],y=[])) mfin = ColumnDataSource(dict(x=[],y=[])) cfin = ColumnDataSource(dict(x=[],y=[])) mroll = ColumnDataSource(dict(x=[],y=[])) mheading = ColumnDataSource(dict(x=[],y=[])) cheading = ColumnDataSource(dict(x=[],y=[])) # AXIS setup colors = COLORS[:] fig1.y_range.flipped = True fig1.yaxis.axis_label = 'm_depth (m)' fig1.extra_y_ranges = {'vert_vel': Range1d(start=-50, end=50), 'dummy': Range1d(start=0, end=100)} fig1.add_layout(place = 'right', obj = LinearAxis(y_range_name = 'vert_vel', axis_label = 'vertical velocity (cm/s)')) fig1.add_layout(place = 'left', obj = LinearAxis(y_range_name = 'dummy', axis_label = ' ')) fig1.yaxis[1].visible = False fig1.yaxis[1].axis_line_alpha = 0 fig1.yaxis[1].major_label_text_alpha = 0 fig1.yaxis[1].major_tick_line_alpha = 0 fig1.yaxis[1].minor_tick_line_alpha = 0 fig2.yaxis.axis_label = 'pitch (deg)' fig2.y_range.start, fig2.y_range.end = -40,40 fig2.extra_y_ranges = {'battpos': Range1d(start=-1, end = 1), 'bpump': Range1d(start=-275, end=275)} fig2.add_layout(place = 'right', obj = LinearAxis(y_range_name = 'battpos', axis_label = 'battpos (in)')) fig2.add_layout(place = 'left', obj = LinearAxis(y_range_name = 'bpump', axis_label = 'bpump (cc)')) fig2.yaxis[1].visible = False # necessary for spacing. later gets set to true fig3.yaxis.axis_label = 'fin/roll (deg)' fig3.y_range.start, fig3.y_range.end = -30, 30 fig3.extra_y_ranges = {'heading': Range1d(start=0, end=360), #TODO dynamic avg centering 'dummy': Range1d(start=0, end=100)} fig3.add_layout(place = 'right', obj = LinearAxis(y_range_name = 'heading', axis_label = 'headings (deg)')) fig3.add_layout(place = 'left', obj = LinearAxis(y_range_name = 'dummy', axis_label = ' ')) fig3.yaxis[1].visible = False fig3.yaxis[1].axis_line_alpha = 0 fig3.yaxis[1].major_label_text_alpha = 0 fig3.yaxis[1].major_tick_line_alpha = 0 fig3.yaxis[1].minor_tick_line_alpha = 0 # PLOT OBJECTS fig1.line( 'x', 'y', source = depth, legend = 'm_depth', color = 'red') fig1.circle('x', 'y', source = depth, legend = 'm_depth', color = 'red') fig1.line( 'x', 'y', source = vert_vel, legend = 'vert_vel', color = 'green', y_range_name = 'vert_vel') fig1.circle('x', 'y', source = vert_vel, legend = 'vert_vel', color = 'green', y_range_name = 'vert_vel') fig1.renderers.append(Span(location = 0, dimension = 'width', y_range_name = 'vert_vel', line_color= 'green', line_dash='dashed', line_width=1)) fig2.line( 'x', 'y', source = pitch, legend = "m_pitch", color = 'indigo') fig2.circle('x', 'y', source = pitch, legend = "m_pitch", color = 'indigo') fig2.line( 'x', 'y', source = battpos, legend = 'm_battpos', color = 'magenta', y_range_name = 'battpos') fig2.circle('x', 'y', source = battpos, legend = 'm_battpos', color = 'magenta', y_range_name = 'battpos') fig2.line( 'x', 'y', source = mbpump, legend = "m_'bpump'", color = 'blue', y_range_name = 'bpump') fig2.circle('x', 'y', source = mbpump, legend = "m_'bpump'", color = 'blue', y_range_name = 'bpump') fig2.renderers.append(Span(location = 0, dimension = 'width', line_color= 'black', line_dash='dashed', line_width=1)) fig3.line( 'x', 'y', source = mfin, legend = 'm_fin', color = 'cyan') fig3.circle('x', 'y', source = mfin, legend = 'm_fin', color = 'cyan') fig3.line( 'x', 'y', source = cfin, legend = 'c_fin', color = 'orange') fig3.circle('x', 'y', source = cfin, legend = 'c_fin', color = 'orange') fig3.line( 'x', 'y', source = mroll, legend = 'm_roll', color = 'magenta') fig3.circle('x', 'y', source = mroll, legend = 'm_roll', color = 'magenta') fig3.line( 'x', 'y', source = mheading, legend = 'm_heading', color = 'blue', y_range_name = 'heading') fig3.circle('x', 'y', source = mheading, legend = 'm_heading', color = 'blue', y_range_name = 'heading') fig3.line( 'x', 'y', source = cheading, legend = 'c_heading', color = 'indigo', y_range_name = 'heading') fig3.circle('x', 'y', source = cheading, legend = 'c_heading', color = 'indigo', y_range_name = 'heading') fig3.renderers.append(Span(location = 0, dimension = 'width', y_range_name = 'default', line_color= 'black', line_dash='dashed', line_width=1)) # CALLBACK FUNCS def update_data(attrib,old,new): g = gliders.value chnk = chunkations.value chindex = abs(int(chunk_indicator.value)) depth.data = dict(x=[],y=[]) vert_vel.data = dict(x=[],y=[]) mbpump.data = dict(x=[],y=[]) battpos.data = dict(x=[],y=[]) pitch.data = dict(x=[],y=[]) mfin.data = dict(x=[],y=[]) cfin.data = dict(x=[],y=[]) mroll.data = dict(x=[],y=[]) mheading.data = dict(x=[],y=[]) cheading.data = dict(x=[],y=[]) depth.data,startend = load_sensor(g, 'm_depth', chnk, chindex) if chnk == 'segment': xbd = startend[2] chunk_ID.text = '{} {} \n{} ({}) \nSTART: {} \nEND: {}'.format(g, xbd['mission'], xbd['onboard_filename'], xbd['the8x3_filename'], e2ts(xbd['start']), e2ts(xbd['end'])) if len(set(depth.data['x']))<=1 and attrib == 'chunk': if old > new: next_chunk.clicks += 1 else: prev_chunk.clicks += 1 return elif len(set(depth.data['x']))<=1 and chunk_indicator.value == 0: chunk_indicator.value = 1 elif chnk in ['24hr', '30days']: chunk_ID.text = '{} \nSTART: {} \nEND: {}'.format(g, e2ts(startend[0]), e2ts(startend[1])) elif chnk == '-ALL-': chunk_ID.text = '{} \nSTART: {} \nEND: {}'.format(g,e2ts(depth.data['x'][0] /1000), e2ts(depth.data['x'][-1]/1000)) vert_vel.data = calc_vert_vel(depth.data) mbpump.data,_ = load_sensor(g, 'm_de_oil_vol', chnk, chindex) if len(mbpump.data['x']) > 1: #for yax in fig2.select('mbpump'): # yax.legend = 'm_de_oil_vol' pass else: mbpump.data,_ = load_sensor(g, 'm_ballast_pumped', chnk, chindex) #for yax in fig2.select('mbpump'): # yax.legend = 'm_ballast_pumped' battpos.data,_ = load_sensor(g, 'm_battpos', chnk, chindex) pitch.data,_ = load_sensor(g, 'm_pitch', chnk, chindex) pitch.data['y'] = [math.degrees(y) for y in pitch.data['y']] mfin.data,_ = load_sensor(g, 'm_fin', chnk, chindex) cfin.data,_ = load_sensor(g, 'c_fin', chnk, chindex) mroll.data,_ = load_sensor(g, 'm_roll', chnk, chindex) mheading.data,_ = load_sensor(g, 'm_heading', chnk, chindex) cheading.data,_ = load_sensor(g, 'c_heading', chnk, chindex) mfin.data['y'] = [math.degrees(y) for y in mfin.data['y']] cfin.data['y'] = [math.degrees(y) for y in cfin.data['y']] mheading.data['y'] = [math.degrees(y) for y in mheading.data['y']] cheading.data['y'] = [math.degrees(y) for y in cheading.data['y']] mroll.data['y'] = [math.degrees(y) for y in mroll.data['y']] fig1.yaxis[1].visible = True fig2.yaxis[1].visible = True fig3.yaxis[1].visible = True #GLIDER SELECTS def glider_buttons(increment): ops = gliders.options new_index = ops.index(gliders.value) + increment if new_index >= len(ops): new_index = 0 elif new_index < 0: new_index = len(ops)-1 gliders.value = ops[new_index] chunkation_update(None, None, None) #reset chunk indicator and clicks def next_glider_func(): glider_buttons(1) def prev_glider_func(): glider_buttons(-1) def update_glider(attrib,old,new): chunk_indicator.value = '0' #update_data(None,None,None) gliders.on_change('value', update_glider) next_glider.on_click(next_glider_func) prev_glider.on_click(prev_glider_func) #CHUNK SELECTS def chunkation_update(attrib,old,new): chunk_indicator.value = '0' prev_chunk.clicks = 0 next_chunk.clicks = 0 update_data(None,None,None) if new == '-ALL-': chunk_indicator.value = '-' def chunk_func(): chunkdiff = prev_chunk.clicks - next_chunk.clicks if chunkdiff < 0: prev_chunk.clicks = 0 next_chunk.clicks = 0 chunkdiff = 0 print (chunkdiff) chunk_indicator.value = str(chunkdiff) def chunk_indicator_update(attrib,old,new): try: if abs(int(old)-int(new))>1: #manual update, triggers new non-manual indicator update, ie else clause below prev_chunk.clicks = int(new) next_chunk.clicks = 0 else: update_data('chunk',int(old),int(new)) print("UPDATE", old, new) except Exception as e: print(type(e),e, old, new) chunkations.on_change('value', chunkation_update) chunk_indicator.on_change('value', chunk_indicator_update) next_chunk.on_click(chunk_func) prev_chunk.on_click(chunk_func) update_data(None,None,None) return vplot(control_box, figs)
# show a separate signal for each file in a group selected_file.show_files_separately(1 in new) def change_displayed_doc(): if doc.roots[0] == landing_page: doc.remove_root(landing_page) doc.add_root(layout) # ---------------- Build Website Layout ------------------- # select file file_selection_button = Button(label="Select Files", button_type="success", width=120) file_selection_button.on_click(load_files_group) files_selector_spacer = Spacer(width=10) group_selection_button = Button(label="Select Directory", button_type="primary", width=140) group_selection_button.on_click(load_directory_group) unload_file_button = Button(label="Unload", button_type="danger", width=50) unload_file_button.on_click(unload_file) # files selection box files_selector = Select(title="Files:", options=[])
def _create_interact_ui(doc, minp=minimum_period, maxp=maximum_period, resolution=resolution): """Create BLS interact user interface.""" if minp is None: minp = 0.3 if maxp is None: maxp = (lc.time[-1].value - lc.time[0].value) / 2 # TODO: consider to accept Time as minp / maxp, and convert it to unitless days time_format = "" if lc.time.format == "bkjd": time_format = " - 2454833 days" if lc.time.format == "btjd": time_format = " - 2457000 days" # Some sliders duration_slider = Slider( start=0.01, end=0.5, value=0.05, step=0.01, title="Duration [Days]", width=400, ) npoints_slider = Slider( start=500, end=10000, value=resolution, step=100, title="BLS Resolution", width=400, ) # Set up the period values, BLS model and best period period_values = np.logspace(np.log10(minp), np.log10(maxp), npoints_slider.value) period_values = period_values[(period_values > duration_slider.value) & (period_values < maxp)] model = BoxLeastSquares(lc.time, lc.flux) result = model.power(period_values, duration_slider.value) loc = np.argmax(result.power) best_period = result.period[loc] best_t0 = result.transit_time[loc] # Some Buttons double_button = Button(label="Double Period", button_type="danger", width=100) half_button = Button(label="Half Period", button_type="danger", width=100) text_output = Paragraph( text="Period: {} days, T0: {}{}".format( _round_strip_unit(best_period, 7), _round_strip_unit(best_t0, 7), time_format, ), width=350, height=40, ) # Set up BLS source bls_source = prepare_bls_datasource(result, loc) bls_source_units = dict( transit_time_format=result["transit_time"].format, transit_time_scale=result["transit_time"].scale, period=result["period"].unit, ) bls_help_source = prepare_bls_help_source(bls_source, npoints_slider.value) # Set up the model LC mf = model.model(lc.time, best_period, duration_slider.value, best_t0) mf /= np.median(mf) mask = ~(convolve(np.asarray(mf == np.median(mf)), Box1DKernel(2)) > 0.9) model_lc = _to_lc(lc.time[mask], mf[mask]) model_lc_source = _to_ColumnDataSource( data=dict(time=model_lc.time, flux=model_lc.flux)) # Set up the LC nb = int(np.ceil(len(lc.flux) / 5000)) lc_source = prepare_lightcurve_datasource(lc[::nb]) lc_help_source = prepare_lc_help_source(lc) # Set up folded LC nb = int(np.ceil(len(lc.flux) / 10000)) f = lc.fold(best_period, best_t0) f_source = prepare_folded_datasource(f[::nb]) f_help_source = prepare_f_help_source(f) f_model_lc = model_lc.fold(best_period, best_t0) f_model_lc = _to_lc(_as_1d(f.time.min()), [1]).append(f_model_lc) f_model_lc = f_model_lc.append(_to_lc(_as_1d(f.time.max()), [1])) f_model_lc_source = _to_ColumnDataSource( data=dict(phase=f_model_lc.time, flux=f_model_lc.flux)) def _update_light_curve_plot(event): """If we zoom in on LC plot, update the binning.""" mint, maxt = fig_lc.x_range.start, fig_lc.x_range.end inwindow = (lc.time.value > mint) & (lc.time.value < maxt) nb = int(np.ceil(inwindow.sum() / 5000)) temp_lc = lc[inwindow] _update_source(lc_source, { "time": temp_lc.time[::nb], "flux": temp_lc.flux[::nb] }) def _update_folded_plot(event): loc = np.argmax(bls_source.data["power"]) best_period = bls_source.data["period"][loc] best_t0 = bls_source.data["transit_time"][loc] # Otherwise, we can just update the best_period index minphase, maxphase = fig_folded.x_range.start, fig_folded.x_range.end f = lc.fold(best_period, best_t0) inwindow = (f.time > minphase) & (f.time < maxphase) nb = int(np.ceil(inwindow.sum() / 10000)) _update_source( f_source, { "phase": f[inwindow].time[::nb], "flux": f[inwindow].flux[::nb] }, ) # Function to update the widget def _update_params(all=False, best_period=None, best_t0=None): if all: # If we're updating everything, recalculate the BLS model minp, maxp = fig_bls.x_range.start, fig_bls.x_range.end period_values = np.logspace(np.log10(minp), np.log10(maxp), npoints_slider.value) ok = (period_values > duration_slider.value) & (period_values < maxp) if ok.sum() == 0: return period_values = period_values[ok] result = model.power(period_values, duration_slider.value) ok = (_isfinite(result["power"]) & _isfinite(result["duration"]) & _isfinite(result["transit_time"]) & _isfinite(result["period"])) ok_result = dict( period=result["period"] [ok], # useful for accessing values with units needed later power=result["power"][ok], duration=result["duration"][ok], transit_time=result["transit_time"][ok], ) _update_source(bls_source, ok_result) loc = np.nanargmax(ok_result["power"]) best_period = ok_result["period"][loc] best_t0 = ok_result["transit_time"][loc] minpow, maxpow = ( bls_source.data["power"].min() * 0.95, bls_source.data["power"].max() * 1.05, ) fig_bls.y_range.start = minpow fig_bls.y_range.end = maxpow # Otherwise, we can just update the best_period index minphase, maxphase = fig_folded.x_range.start, fig_folded.x_range.end f = lc.fold(best_period, best_t0) inwindow = (f.time > minphase) & (f.time < maxphase) nb = int(np.ceil(inwindow.sum() / 10000)) _update_source( f_source, { "phase": f[inwindow].time[::nb], "flux": f[inwindow].flux[::nb] }, ) mf = model.model(lc.time, best_period, duration_slider.value, best_t0) mf /= np.median(mf) mask = ~(convolve(np.asarray(mf == np.median(mf)), Box1DKernel(2)) > 0.9) model_lc = _to_lc(lc.time[mask], mf[mask]) _update_source(model_lc_source, { "time": model_lc.time, "flux": model_lc.flux }) f_model_lc = model_lc.fold(best_period, best_t0) f_model_lc = _to_lc(_as_1d(f.time.min()), [1]).append(f_model_lc) f_model_lc = f_model_lc.append(_to_lc(_as_1d(f.time.max()), [1])) _update_source(f_model_lc_source, { "phase": f_model_lc.time, "flux": f_model_lc.flux }) vertical_line.update(location=best_period.value) fig_folded.title.text = "Period: {} days \t T0: {}{}".format( _round_strip_unit(best_period, 7), _round_strip_unit(best_t0, 7), time_format, ) text_output.text = "Period: {} days, \t T0: {}{}".format( _round_strip_unit(best_period, 7), _round_strip_unit(best_t0, 7), time_format, ) # Callbacks def _update_upon_period_selection(attr, old, new): """When we select a period we should just update a few things, but we should not recalculate model""" if len(new) > 0: new = new[0] best_period = (bls_source.data["period"][new] * bls_source_units["period"]) best_t0 = Time( bls_source.data["transit_time"][new], format=bls_source_units["transit_time_format"], scale=bls_source_units["transit_time_scale"], ) _update_params(best_period=best_period, best_t0=best_t0) def _update_model_slider(attr, old, new): """If the duration slider is updated, then update the whole model set.""" _update_params(all=True) def _update_model_slider_EVENT(event): """If we update the duration slider, we should update the whole model set. This is the same as the _update_model_slider but it has a different call signature... """ _update_params(all=True) def _double_period_event(): fig_bls.x_range.start *= 2 fig_bls.x_range.end *= 2 _update_params(all=True) def _half_period_event(): fig_bls.x_range.start /= 2 fig_bls.x_range.end /= 2 _update_params(all=True) # Help Hover Call Backs def _update_folded_plot_help_reset(event): f_help_source.data["phase"] = [_at_ratio(f.time, 0.95)] f_help_source.data["flux"] = [_at_ratio(f.flux, 0.95)] def _update_folded_plot_help(event): f_help_source.data["phase"] = [_at_ratio(fig_folded.x_range, 0.95)] f_help_source.data["flux"] = [_at_ratio(fig_folded.y_range, 0.95)] def _update_lc_plot_help_reset(event): lc_help_source.data["time"] = [_at_ratio(lc.time, 0.98)] lc_help_source.data["flux"] = [_at_ratio(lc.flux, 0.95)] def _update_lc_plot_help(event): lc_help_source.data["time"] = [_at_ratio(fig_lc.x_range, 0.98)] lc_help_source.data["flux"] = [_at_ratio(fig_lc.y_range, 0.95)] def _update_bls_plot_help_event(event): # cannot use _at_ratio helper for period, because period is log scaled. bls_help_source.data["period"] = [ bls_source.data["period"][int(npoints_slider.value * 0.95)] ] bls_help_source.data["power"] = [ _at_ratio(bls_source.data["power"], 0.98) ] def _update_bls_plot_help(attr, old, new): bls_help_source.data["period"] = [ bls_source.data["period"][int(npoints_slider.value * 0.95)] ] bls_help_source.data["power"] = [ _at_ratio(bls_source.data["power"], 0.98) ] # Create all the figures. fig_folded = make_folded_figure_elements(f, f_model_lc, f_source, f_model_lc_source, f_help_source) fig_folded.title.text = "Period: {} days \t T0: {}{}".format( _round_strip_unit(best_period, 7), _round_strip_unit(best_t0, 5), time_format, ) fig_bls, vertical_line = make_bls_figure_elements( result, bls_source, bls_help_source) fig_lc = make_lightcurve_figure_elements(lc, model_lc, lc_source, model_lc_source, lc_help_source) # Map changes # If we click a new period, update bls_source.selected.on_change("indices", _update_upon_period_selection) # If we change the duration, update everything, including help button for BLS duration_slider.on_change("value", _update_model_slider) duration_slider.on_change("value", _update_bls_plot_help) # If we increase resolution, update everything npoints_slider.on_change("value", _update_model_slider) # Make sure the vertical line always goes to the best period. vertical_line.update(location=best_period.value) # If we pan in the BLS panel, update everything fig_bls.on_event(PanEnd, _update_model_slider_EVENT) fig_bls.on_event(Reset, _update_model_slider_EVENT) # If we pan in the LC panel, rebin the points fig_lc.on_event(PanEnd, _update_light_curve_plot) fig_lc.on_event(Reset, _update_light_curve_plot) # If we pan in the Folded panel, rebin the points fig_folded.on_event(PanEnd, _update_folded_plot) fig_folded.on_event(Reset, _update_folded_plot) # Deal with help button fig_bls.on_event(PanEnd, _update_bls_plot_help_event) fig_bls.on_event(Reset, _update_bls_plot_help_event) fig_folded.on_event(PanEnd, _update_folded_plot_help) fig_folded.on_event(Reset, _update_folded_plot_help_reset) fig_lc.on_event(PanEnd, _update_lc_plot_help) fig_lc.on_event(Reset, _update_lc_plot_help_reset) # Buttons double_button.on_click(_double_period_event) half_button.on_click(_half_period_event) # Layout the widget doc.add_root( layout([ [fig_bls, fig_folded], fig_lc, [ Spacer(width=70), duration_slider, Spacer(width=50), npoints_slider, ], [ Spacer(width=70), double_button, Spacer(width=70), half_button, Spacer(width=300), text_output, ], ]))
x = [i for i in xrange(np.shape(rec)[0])] y = [v for v in rec] source = ColumnDataSource(data=dict(x=x, y=y)) # Set up plot plot = Figure(plot_height=800, plot_width=1200, title="Eigenvector Analysis", tools="", x_range=[0, 289], y_range=[0, 1500.], x_axis_label='Time', y_axis_label='Veh/5m') plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6) # Set up widgets v0 = Slider(title="V0_Coefficient", value=m_projection[0], start=v0_struct[0], end=v0_struct[1]) v1 = Slider(title="V1_Coefficient", value=m_projection[1], start=v1_struct[0], end=v1_struct[1]) v2 = Slider(title="V2_Coefficient", value=m_projection[2], start=v2_struct[0], end=v2_struct[1]) v3 = Slider(title="V3_Coefficient", value=m_projection[3], start=v3_struct[0], end=v3_struct[1]) button= Button(label='Reset') # Set up callbacks def update_data(attrname, old, new): # Get the current slider values v0_value = v0.value v1_value = v1.value v2_value = v2.value v3_value = v3.value # Generate the new curve m_projection = [v0_value, v1_value, v2_value, v3_value] rec = get_reconstruction(m_eigs_t, m_projection, m_mean_vector) x = [i for i in xrange(np.shape(rec)[0])] y = [v for v in rec]
def generate_plots(ulog, px4_ulog, db_data, vehicle_data, link_to_3d_page): """ create a list of bokeh plots (and widgets) to show """ plots = [] data = ulog.data_list # COMPATIBILITY support for old logs if any(elem.name == 'vehicle_air_data' or elem.name == 'vehicle_magnetometer' for elem in data): baro_alt_meter_topic = 'vehicle_air_data' magnetometer_ga_topic = 'vehicle_magnetometer' else: # old baro_alt_meter_topic = 'sensor_combined' magnetometer_ga_topic = 'sensor_combined' for topic in data: if topic.name == 'system_power': # COMPATIBILITY: rename fields to new format if 'voltage5V_v' in topic.data: # old (prior to PX4/Firmware:213aa93) topic.data['voltage5v_v'] = topic.data.pop('voltage5V_v') if 'voltage3V3_v' in topic.data: # old (prior to PX4/Firmware:213aa93) topic.data['voltage3v3_v'] = topic.data.pop('voltage3V3_v') # initialize flight mode changes flight_mode_changes = get_flight_mode_changes(ulog) # VTOL state changes & vehicle type is_multicopter = False # this is False for VTOLs as well vtol_states = None try: cur_dataset = ulog.get_dataset('vehicle_status') if np.amax(cur_dataset.data['is_vtol']) == 1: vtol_states = cur_dataset.list_value_changes('in_transition_mode') # find mode after transitions (states: 1=transition, 2=FW, 3=MC) for i in range(len(vtol_states)): if vtol_states[i][1] == 0: t = vtol_states[i][0] idx = np.argmax(cur_dataset.data['timestamp'] >= t) + 1 vtol_states[i] = (t, 2 + cur_dataset.data['is_rotary_wing'][idx]) vtol_states.append((ulog.last_timestamp, -1)) elif np.amax(cur_dataset.data['is_rotary_wing']) == 1: is_multicopter = True except (KeyError, IndexError) as error: vtol_states = None # Heading curdoc().template_variables['title_html'] = get_heading_html( ulog, px4_ulog, db_data, link_to_3d_page) # info text on top (logging duration, max speed, ...) curdoc().template_variables['info_table_html'] = \ get_info_table_html(ulog, px4_ulog, db_data, vehicle_data, vtol_states) curdoc().template_variables['error_labels_html'] = get_error_labels_html() hardfault_html = get_hardfault_html(ulog) if hardfault_html is not None: curdoc().template_variables['hardfault_html'] = hardfault_html # Position plot data_plot = DataPlot2D(data, plot_config, 'vehicle_local_position', x_axis_label='[m]', y_axis_label='[m]', plot_height='large') data_plot.add_graph('y', 'x', colors2[0], 'Estimated', check_if_all_zero=True) if not data_plot.had_error: # vehicle_local_position is required data_plot.change_dataset('vehicle_local_position_setpoint') data_plot.add_graph('y', 'x', colors2[1], 'Setpoint') # groundtruth (SITL only) data_plot.change_dataset('vehicle_local_position_groundtruth') data_plot.add_graph('y', 'x', color_gray, 'Groundtruth') # GPS + position setpoints plot_map(ulog, plot_config, map_type='plain', setpoints=True, bokeh_plot=data_plot.bokeh_plot) if data_plot.finalize() is not None: plots.append(data_plot.bokeh_plot) # Leaflet Map try: pos_datas, flight_modes = ulog_to_polyline(ulog, flight_mode_changes) curdoc().template_variables['pos_datas'] = pos_datas curdoc().template_variables['pos_flight_modes'] = flight_modes except: pass curdoc().template_variables['has_position_data'] = True # initialize parameter changes changed_params = None if not 'replay' in ulog.msg_info_dict: # replay can have many param changes if len(ulog.changed_parameters) > 0: changed_params = ulog.changed_parameters plots.append(None) # save space for the param change button ### Add all data plots ### x_range_offset = (ulog.last_timestamp - ulog.start_timestamp) * 0.05 x_range = Range1d(ulog.start_timestamp - x_range_offset, ulog.last_timestamp + x_range_offset) # Altitude estimate data_plot = DataPlot(data, plot_config, 'vehicle_gps_position', y_axis_label='[m]', title='Altitude Estimate', changed_params=changed_params, x_range=x_range) data_plot.add_graph([lambda data: ('alt', data['alt']*0.001)], colors8[0:1], ['GPS Altitude']) data_plot.change_dataset(baro_alt_meter_topic) data_plot.add_graph(['baro_alt_meter'], colors8[1:2], ['Barometer Altitude']) data_plot.change_dataset('vehicle_global_position') data_plot.add_graph(['alt'], colors8[2:3], ['Fused Altitude Estimation']) data_plot.change_dataset('position_setpoint_triplet') data_plot.add_circle(['current.alt'], [plot_config['mission_setpoint_color']], ['Altitude Setpoint']) data_plot.change_dataset('actuator_controls_0') data_plot.add_graph([lambda data: ('thrust', data['control[3]']*100)], colors8[6:7], ['Thrust [0, 100]']) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) if data_plot.finalize() is not None: plots.append(data_plot) # Roll/Pitch/Yaw angle & angular rate for axis in ['roll', 'pitch', 'yaw']: # angle axis_name = axis.capitalize() data_plot = DataPlot(data, plot_config, 'vehicle_attitude', y_axis_label='[deg]', title=axis_name+' Angle', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph([lambda data: (axis, np.rad2deg(data[axis]))], colors3[0:1], [axis_name+' Estimated'], mark_nan=True) data_plot.change_dataset('vehicle_attitude_setpoint') # in fixed-wing, the attitude setpoint is allowed to be NaN data_plot.add_graph([lambda data: (axis+'_d', np.rad2deg(data[axis+'_d']))], colors3[1:2], [axis_name+' Setpoint'], mark_nan=is_multicopter, use_step_lines=True) if axis == 'yaw': data_plot.add_graph( [lambda data: ('yaw_sp_move_rate', np.rad2deg(data['yaw_sp_move_rate']))], colors3[2:3], [axis_name+' FF Setpoint [deg/s]'], use_step_lines=True) data_plot.change_dataset('vehicle_attitude_groundtruth') data_plot.add_graph([lambda data: (axis, np.rad2deg(data[axis]))], [color_gray], [axis_name+' Groundtruth']) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) if data_plot.finalize() is not None: plots.append(data_plot) # rate data_plot = DataPlot(data, plot_config, 'vehicle_attitude', y_axis_label='[deg/s]', title=axis_name+' Angular Rate', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph([lambda data: (axis+'speed', np.rad2deg(data[axis+'speed']))], colors3[0:1], [axis_name+' Rate Estimated'], mark_nan=True) data_plot.change_dataset('vehicle_rates_setpoint') data_plot.add_graph([lambda data: (axis, np.rad2deg(data[axis]))], colors3[1:2], [axis_name+' Rate Setpoint'], mark_nan=True, use_step_lines=True) axis_letter = axis[0].upper() rate_int_limit = '(*100)' # this param is MC/VTOL only (it will not exist on FW) rate_int_limit_param = 'MC_' + axis_letter + 'R_INT_LIM' if rate_int_limit_param in ulog.initial_parameters: rate_int_limit = '[-{0:.0f}, {0:.0f}]'.format( ulog.initial_parameters[rate_int_limit_param]*100) data_plot.change_dataset('rate_ctrl_status') data_plot.add_graph([lambda data: (axis, data[axis+'speed_integ']*100)], colors3[2:3], [axis_name+' Rate Integral '+rate_int_limit]) data_plot.change_dataset('vehicle_attitude_groundtruth') data_plot.add_graph([lambda data: (axis+'speed', np.rad2deg(data[axis+'speed']))], [color_gray], [axis_name+' Rate Groundtruth']) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) if data_plot.finalize() is not None: plots.append(data_plot) # Local position for axis in ['x', 'y', 'z']: data_plot = DataPlot(data, plot_config, 'vehicle_local_position', y_axis_label='[m]', title='Local Position '+axis.upper(), plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph([axis], colors2[0:1], [axis.upper()+' Estimated'], mark_nan=True) data_plot.change_dataset('vehicle_local_position_setpoint') data_plot.add_graph([axis], colors2[1:2], [axis.upper()+' Setpoint'], mark_nan=True, use_step_lines=True) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) if data_plot.finalize() is not None: plots.append(data_plot) # Velocity data_plot = DataPlot(data, plot_config, 'vehicle_local_position', y_axis_label='[m/s]', title='Velocity', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph(['vx', 'vy', 'vz'], colors8[0:3], ['X', 'Y', 'Z']) data_plot.change_dataset('vehicle_local_position_setpoint') data_plot.add_graph(['vx', 'vy', 'vz'], [colors8[5], colors8[4], colors8[6]], ['X Setpoint', 'Y Setpoint', 'Z Setpoint'], use_step_lines=True) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) if data_plot.finalize() is not None: plots.append(data_plot) # Visual Odometry (only if topic found) if any(elem.name == 'vehicle_visual_odometry' for elem in data): # Vision position data_plot = DataPlot(data, plot_config, 'vehicle_visual_odometry', y_axis_label='[m]', title='Visual Odometry Position', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph(['x', 'y', 'z'], colors3, ['X', 'Y', 'Z'], mark_nan=True) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) data_plot.change_dataset('vehicle_local_position_groundtruth') data_plot.add_graph(['x', 'y', 'z'], colors8[2:5], ['Groundtruth X', 'Groundtruth Y', 'Groundtruth Z']) if data_plot.finalize() is not None: plots.append(data_plot) # Vision velocity data_plot = DataPlot(data, plot_config, 'vehicle_visual_odometry', y_axis_label='[m]', title='Visual Odometry Velocity', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph(['vx', 'vy', 'vz'], colors3, ['X', 'Y', 'Z'], mark_nan=True) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) data_plot.change_dataset('vehicle_local_position_groundtruth') data_plot.add_graph(['vx', 'vy', 'vz'], colors8[2:5], ['Groundtruth VX', 'Groundtruth VY', 'Groundtruth VZ']) if data_plot.finalize() is not None: plots.append(data_plot) # Vision attitude data_plot = DataPlot(data, plot_config, 'vehicle_visual_odometry', y_axis_label='[deg]', title='Visual Odometry Attitude', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph([lambda data: ('roll', np.rad2deg(data['roll'])), lambda data: ('pitch', np.rad2deg(data['pitch'])), lambda data: ('yaw', np.rad2deg(data['yaw']))], colors3, ['Roll', 'Pitch', 'Yaw'], mark_nan=True) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) data_plot.change_dataset('vehicle_attitude_groundtruth') data_plot.add_graph([lambda data: ('roll', np.rad2deg(data['roll'])), lambda data: ('pitch', np.rad2deg(data['pitch'])), lambda data: ('yaw', np.rad2deg(data['yaw']))], colors8[2:5], ['Roll Groundtruth', 'Pitch Groundtruth', 'Yaw Groundtruth']) # Vision attitude rate data_plot = DataPlot(data, plot_config, 'vehicle_visual_odometry', y_axis_label='[deg]', title='Visual Odometry Attitude Rate', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph([lambda data: ('rollspeed', np.rad2deg(data['rollspeed'])), lambda data: ('pitchspeed', np.rad2deg(data['pitchspeed'])), lambda data: ('yawspeed', np.rad2deg(data['yawspeed']))], colors3, ['Roll Rate', 'Pitch Rate', 'Yaw Rate'], mark_nan=True) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) data_plot.change_dataset('vehicle_attitude_groundtruth') data_plot.add_graph([lambda data: ('rollspeed', np.rad2deg(data['rollspeed'])), lambda data: ('pitchspeed', np.rad2deg(data['pitchspeed'])), lambda data: ('yawspeed', np.rad2deg(data['yawspeed']))], colors8[2:5], ['Roll Rate Groundtruth', 'Pitch Rate Groundtruth', 'Yaw Rate Groundtruth']) if data_plot.finalize() is not None: plots.append(data_plot) # Airspeed vs Ground speed: but only if there's valid airspeed data try: cur_dataset = ulog.get_dataset('airspeed') if np.amax(cur_dataset.data['indicated_airspeed_m_s']) > 0.1: data_plot = DataPlot(data, plot_config, 'vehicle_global_position', y_axis_label='[m/s]', title='Airspeed', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph([lambda data: ('groundspeed_estimated', np.sqrt(data['vel_n']**2 + data['vel_e']**2))], colors3[2:3], ['Ground Speed Estimated']) data_plot.change_dataset('airspeed') data_plot.add_graph(['indicated_airspeed_m_s'], colors2[0:1], ['Airspeed Indicated']) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) if data_plot.finalize() is not None: plots.append(data_plot) except (KeyError, IndexError) as error: pass # manual control inputs # prefer the manual_control_setpoint topic. Old logs do not contain it if any(elem.name == 'manual_control_setpoint' for elem in data): data_plot = DataPlot(data, plot_config, 'manual_control_setpoint', title='Manual Control Inputs (Radio or Joystick)', plot_height='small', y_range=Range1d(-1.1, 1.1), changed_params=changed_params, x_range=x_range) data_plot.add_graph(['y', 'x', 'r', 'z', lambda data: ('mode_slot', data['mode_slot']/6), 'aux1', 'aux2', lambda data: ('kill_switch', data['kill_switch'] == 1)], colors8, ['Y / Roll', 'X / Pitch', 'Yaw', 'Throttle [0, 1]', 'Flight Mode', 'Aux1', 'Aux2', 'Kill Switch']) # TODO: add RTL switch and others? Look at params which functions are mapped? plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) if data_plot.finalize() is not None: plots.append(data_plot) else: # it's an old log (COMPATIBILITY) data_plot = DataPlot(data, plot_config, 'rc_channels', title='Raw Radio Control Inputs', plot_height='small', y_range=Range1d(-1.1, 1.1), changed_params=changed_params, x_range=x_range) num_rc_channels = 8 if data_plot.dataset: max_channels = np.amax(data_plot.dataset.data['channel_count']) if max_channels < num_rc_channels: num_rc_channels = max_channels legends = [] for i in range(num_rc_channels): channel_names = px4_ulog.get_configured_rc_input_names(i) if channel_names is None: legends.append('Channel '+str(i)) else: legends.append('Channel '+str(i)+' ('+', '.join(channel_names)+')') data_plot.add_graph(['channels['+str(i)+']' for i in range(num_rc_channels)], colors8[0:num_rc_channels], legends, mark_nan=True) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) if data_plot.finalize() is not None: plots.append(data_plot) # actuator controls 0 data_plot = DataPlot(data, plot_config, 'actuator_controls_0', y_start=0, title='Actuator Controls 0', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph(['control[0]', 'control[1]', 'control[2]', 'control[3]'], colors8[0:4], ['Roll', 'Pitch', 'Yaw', 'Thrust'], mark_nan=True) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) if data_plot.finalize() is not None: plots.append(data_plot) # actuator controls (Main) FFT (for filter & output noise analysis) data_plot = DataPlotFFT(data, plot_config, 'actuator_controls_0', title='Actuator Controls FFT') data_plot.add_graph(['control[0]', 'control[1]', 'control[2]'], colors3, ['Roll', 'Pitch', 'Yaw']) if not data_plot.had_error: if 'MC_DTERM_CUTOFF' in ulog.initial_parameters: data_plot.mark_frequency( ulog.initial_parameters['MC_DTERM_CUTOFF'], 'MC_DTERM_CUTOFF') if 'IMU_GYRO_CUTOFF' in ulog.initial_parameters: data_plot.mark_frequency( ulog.initial_parameters['IMU_GYRO_CUTOFF'], 'IMU_GYRO_CUTOFF', 20) if data_plot.finalize() is not None: plots.append(data_plot) # actuator controls 1 # (only present on VTOL, Fixed-wing config) data_plot = DataPlot(data, plot_config, 'actuator_controls_1', y_start=0, title='Actuator Controls 1 (VTOL in Fixed-Wing mode)', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph(['control[0]', 'control[1]', 'control[2]', 'control[3]'], colors8[0:4], ['Roll', 'Pitch', 'Yaw', 'Thrust'], mark_nan=True) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) if data_plot.finalize() is not None: plots.append(data_plot) # actuator outputs 0: Main data_plot = DataPlot(data, plot_config, 'actuator_outputs', y_start=0, title='Actuator Outputs (Main)', plot_height='small', changed_params=changed_params, x_range=x_range) num_actuator_outputs = 8 if data_plot.dataset: max_outputs = np.amax(data_plot.dataset.data['noutputs']) if max_outputs < num_actuator_outputs: num_actuator_outputs = max_outputs data_plot.add_graph(['output['+str(i)+']' for i in range(num_actuator_outputs)], colors8[0:num_actuator_outputs], ['Output '+str(i) for i in range(num_actuator_outputs)], mark_nan=True) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) if data_plot.finalize() is not None: plots.append(data_plot) # actuator outputs 1: AUX data_plot = DataPlot(data, plot_config, 'actuator_outputs', y_start=0, title='Actuator Outputs (AUX)', plot_height='small', changed_params=changed_params, topic_instance=1, x_range=x_range) num_actuator_outputs = 8 # only plot if at least one of the outputs is not constant all_constant = True if data_plot.dataset: max_outputs = np.amax(data_plot.dataset.data['noutputs']) if max_outputs < num_actuator_outputs: num_actuator_outputs = max_outputs for i in range(num_actuator_outputs): output_data = data_plot.dataset.data['output['+str(i)+']'] if not np.all(output_data == output_data[0]): all_constant = False if not all_constant: data_plot.add_graph(['output['+str(i)+']' for i in range(num_actuator_outputs)], colors8[0:num_actuator_outputs], ['Output '+str(i) for i in range(num_actuator_outputs)], mark_nan=True) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) if data_plot.finalize() is not None: plots.append(data_plot) # raw acceleration data_plot = DataPlot(data, plot_config, 'sensor_combined', y_axis_label='[m/s^2]', title='Raw Acceleration', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph(['accelerometer_m_s2[0]', 'accelerometer_m_s2[1]', 'accelerometer_m_s2[2]'], colors3, ['X', 'Y', 'Z']) if data_plot.finalize() is not None: plots.append(data_plot) # raw angular speed data_plot = DataPlot(data, plot_config, 'sensor_combined', y_axis_label='[deg/s]', title='Raw Angular Speed (Gyroscope)', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph([ lambda data: ('gyro_rad[0]', np.rad2deg(data['gyro_rad[0]'])), lambda data: ('gyro_rad[1]', np.rad2deg(data['gyro_rad[1]'])), lambda data: ('gyro_rad[2]', np.rad2deg(data['gyro_rad[2]']))], colors3, ['X', 'Y', 'Z']) if data_plot.finalize() is not None: plots.append(data_plot) # magnetic field strength data_plot = DataPlot(data, plot_config, magnetometer_ga_topic, y_axis_label='[gauss]', title='Raw Magnetic Field Strength', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph(['magnetometer_ga[0]', 'magnetometer_ga[1]', 'magnetometer_ga[2]'], colors3, ['X', 'Y', 'Z']) if data_plot.finalize() is not None: plots.append(data_plot) # distance sensor data_plot = DataPlot(data, plot_config, 'distance_sensor', y_start=0, y_axis_label='[m]', title='Distance Sensor', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph(['current_distance', 'covariance'], colors3[0:2], ['Distance', 'Covariance']) if data_plot.finalize() is not None: plots.append(data_plot) # gps uncertainty # the accuracy values can be really large if there is no fix, so we limit the # y axis range to some sane values data_plot = DataPlot(data, plot_config, 'vehicle_gps_position', title='GPS Uncertainty', y_range=Range1d(0, 40), plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph(['eph', 'epv', 'satellites_used', 'fix_type'], colors8[::2], ['Horizontal position accuracy [m]', 'Vertical position accuracy [m]', 'Num Satellites used', 'GPS Fix']) if data_plot.finalize() is not None: plots.append(data_plot) # gps noise & jamming data_plot = DataPlot(data, plot_config, 'vehicle_gps_position', y_start=0, title='GPS Noise & Jamming', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph(['noise_per_ms', 'jamming_indicator'], colors3[0:2], ['Noise per ms', 'Jamming Indicator']) if data_plot.finalize() is not None: plots.append(data_plot) # thrust and magnetic field data_plot = DataPlot(data, plot_config, magnetometer_ga_topic, y_start=0, title='Thrust and Magnetic Field', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph( [lambda data: ('len_mag', np.sqrt(data['magnetometer_ga[0]']**2 + data['magnetometer_ga[1]']**2 + data['magnetometer_ga[2]']**2))], colors2[0:1], ['Norm of Magnetic Field']) data_plot.change_dataset('actuator_controls_0') data_plot.add_graph([lambda data: ('thrust', data['control[3]'])], colors2[1:2], ['Thrust']) if data_plot.finalize() is not None: plots.append(data_plot) # Acceleration Spectrogram data_plot = DataPlotSpec(data, plot_config, 'sensor_combined', y_axis_label='[Hz]', title='Acceleration Power Spectral Density', plot_height='small', x_range=x_range) data_plot.add_graph(['accelerometer_m_s2[0]', 'accelerometer_m_s2[1]', 'accelerometer_m_s2[2]'], ['X', 'Y', 'Z']) if data_plot.finalize() is not None: plots.append(data_plot) # power data_plot = DataPlot(data, plot_config, 'battery_status', y_start=0, title='Power', plot_height='small', changed_params=changed_params, x_range=x_range) data_plot.add_graph(['voltage_v', 'voltage_filtered_v', 'current_a', lambda data: ('discharged_mah', data['discharged_mah']/100), lambda data: ('remaining', data['remaining']*10)], colors8[::2]+colors8[1:2], ['Battery Voltage [V]', 'Battery Voltage filtered [V]', 'Battery Current [A]', 'Discharged Amount [mAh / 100]', 'Battery remaining [0=empty, 10=full]']) data_plot.change_dataset('system_power') if data_plot.dataset: if 'voltage5v_v' in data_plot.dataset.data and \ np.amax(data_plot.dataset.data['voltage5v_v']) > 0.0001: data_plot.add_graph(['voltage5v_v'], colors8[7:8], ['5 V']) if 'voltage3v3_v' in data_plot.dataset.data and \ np.amax(data_plot.dataset.data['voltage3v3_v']) > 0.0001: data_plot.add_graph(['voltage3v3_v'], colors8[5:6], ['3.3 V']) if data_plot.finalize() is not None: plots.append(data_plot) # estimator watchdog try: data_plot = DataPlot(data, plot_config, 'estimator_status', y_start=0, title='Estimator Watchdog', plot_height='small', changed_params=changed_params, x_range=x_range) estimator_status = ulog.get_dataset('estimator_status').data plot_data = [] plot_labels = [] input_data = [ ('Health Flags (vel, pos, hgt)', estimator_status['health_flags']), ('Timeout Flags (vel, pos, hgt)', estimator_status['timeout_flags']), ('Velocity Check Bit', (estimator_status['innovation_check_flags'])&0x1), ('Horizontal Position Check Bit', (estimator_status['innovation_check_flags']>>1)&1), ('Vertical Position Check Bit', (estimator_status['innovation_check_flags']>>2)&1), ('Mag X, Y, Z Check Bits', (estimator_status['innovation_check_flags']>>3)&0x7), ('Yaw Check Bit', (estimator_status['innovation_check_flags']>>6)&1), ('Airspeed Check Bit', (estimator_status['innovation_check_flags']>>7)&1), ('Synthetic Sideslip Check Bit', (estimator_status['innovation_check_flags']>>8)&1), ('Height to Ground Check Bit', (estimator_status['innovation_check_flags']>>9)&1), ('Optical Flow X, Y Check Bits', (estimator_status['innovation_check_flags']>>10)&0x3), ] # filter: show only the flags that have non-zero samples for cur_label, cur_data in input_data: if np.amax(cur_data) > 0.1: data_label = 'flags_'+str(len(plot_data)) # just some unique string plot_data.append(lambda d, data=cur_data, label=data_label: (label, data)) plot_labels.append(cur_label) if len(plot_data) >= 8: # cannot add more than that break if len(plot_data) == 0: # add the plot even in the absence of any problem, so that the user # can validate that (otherwise it's ambiguous: it could be that the # estimator_status topic is not logged) plot_data = [lambda d: ('flags', input_data[0][1])] plot_labels = [input_data[0][0]] data_plot.add_graph(plot_data, colors8[0:len(plot_data)], plot_labels) if data_plot.finalize() is not None: plots.append(data_plot) except (KeyError, IndexError) as error: print('Error in estimator plot: '+str(error)) # RC Quality data_plot = DataPlot(data, plot_config, 'input_rc', title='RC Quality', plot_height='small', y_range=Range1d(0, 1), changed_params=changed_params, x_range=x_range) data_plot.add_graph([lambda data: ('rssi', data['rssi']/100), 'rc_lost'], colors3[0:2], ['RSSI [0, 1]', 'RC Lost (Indicator)']) data_plot.change_dataset('vehicle_status') data_plot.add_graph(['rc_signal_lost'], colors3[2:3], ['RC Lost (Detected)']) if data_plot.finalize() is not None: plots.append(data_plot) # cpu load data_plot = DataPlot(data, plot_config, 'cpuload', title='CPU & RAM', plot_height='small', y_range=Range1d(0, 1), changed_params=changed_params, x_range=x_range) data_plot.add_graph(['ram_usage', 'load'], [colors3[1], colors3[2]], ['RAM Usage', 'CPU Load']) data_plot.add_span('load', line_color=colors3[2]) data_plot.add_span('ram_usage', line_color=colors3[1]) plot_flight_modes_background(data_plot, flight_mode_changes, vtol_states) if data_plot.finalize() is not None: plots.append(data_plot) # sampling: time difference try: data_plot = DataPlot(data, plot_config, 'sensor_combined', y_range=Range1d(0, 25e3), y_axis_label='[us]', title='Sampling Regularity of Sensor Data', plot_height='small', changed_params=changed_params, x_range=x_range) sensor_combined = ulog.get_dataset('sensor_combined').data sampling_diff = np.diff(sensor_combined['timestamp']) min_sampling_diff = np.amin(sampling_diff) plot_dropouts(data_plot.bokeh_plot, ulog.dropouts, min_sampling_diff) data_plot.add_graph([lambda data: ('timediff', np.append(sampling_diff, 0))], [colors3[2]], ['delta t (between 2 logged samples)']) data_plot.change_dataset('estimator_status') data_plot.add_graph([lambda data: ('time_slip', data['time_slip']*1e6)], [colors3[1]], ['Estimator time slip (cumulative)']) if data_plot.finalize() is not None: plots.append(data_plot) except: pass # exchange all DataPlot's with the bokeh_plot and handle parameter changes param_changes_button = Button(label="Hide Parameter Changes", width=170) param_change_labels = [] # FIXME: this should be a CustomJS callback, not on the server. However this # did not work for me. def param_changes_button_clicked(): """ callback to show/hide parameter changes """ for label in param_change_labels: if label.visible: param_changes_button.label = 'Show Parameter Changes' label.visible = False label.text_alpha = 0 # label.visible does not work, so we use this instead else: param_changes_button.label = 'Hide Parameter Changes' label.visible = True label.text_alpha = 1 param_changes_button.on_click(param_changes_button_clicked) jinja_plot_data = [] for i in range(len(plots)): if plots[i] is None: plots[i] = widgetbox(param_changes_button, width=int(plot_width * 0.99)) if isinstance(plots[i], DataPlot): if plots[i].param_change_label is not None: param_change_labels.append(plots[i].param_change_label) plot_title = plots[i].title plots[i] = plots[i].bokeh_plot fragment = 'Nav-'+plot_title.replace(' ', '-') \ .replace('&', '_').replace('(', '').replace(')', '') jinja_plot_data.append({ 'model_id': plots[i].ref['id'], 'fragment': fragment, 'title': plot_title }) # changed parameters plots.append(get_changed_parameters(ulog.initial_parameters, plot_width)) # information about which messages are contained in the log # TODO: need to load all topics for this (-> log loading will take longer) # but if we load all topics and the log contains some (external) topics # with buggy timestamps, it will affect the plotting. # data_list_sorted = sorted(ulog.data_list, key=lambda d: d.name + str(d.multi_id)) # table_text = [] # for d in data_list_sorted: # message_size = sum([ULog.get_field_size(f.type_str) for f in d.field_data]) # num_data_points = len(d.data['timestamp']) # table_text.append((d.name, str(d.multi_id), str(message_size), str(num_data_points), # str(message_size * num_data_points))) # topics_info = '<table><tr><th>Name</th><th>Topic instance</th><th>Message Size</th>' \ # '<th>Number of data points</th><th>Total bytes</th></tr>' + ''.join( # ['<tr><td>'+'</td><td>'.join(list(x))+'</td></tr>' for x in table_text]) + '</table>' # topics_div = Div(text=topics_info, width=int(plot_width*0.9)) # plots.append(widgetbox(topics_div, width=int(plot_width*0.9))) # log messages plots.append(get_logged_messages(ulog.logged_messages, plot_width)) # perf & top output top_data = '' perf_data = '' for state in ['pre', 'post']: if 'perf_top_'+state+'flight' in ulog.msg_info_multiple_dict: current_top_data = ulog.msg_info_multiple_dict['perf_top_'+state+'flight'][0] flight_data = escape('\n'.join(current_top_data)) top_data += '<p>'+state.capitalize()+' Flight:<br/><pre>'+flight_data+'</pre></p>' if 'perf_counter_'+state+'flight' in ulog.msg_info_multiple_dict: current_perf_data = ulog.msg_info_multiple_dict['perf_counter_'+state+'flight'][0] flight_data = escape('\n'.join(current_perf_data)) perf_data += '<p>'+state.capitalize()+' Flight:<br/><pre>'+flight_data+'</pre></p>' additional_data_html = '' if len(top_data) > 0: additional_data_html += '<h5>Processes</h5>'+top_data if len(perf_data) > 0: additional_data_html += '<h5>Performance Counters</h5>'+perf_data if len(additional_data_html) > 0: # hide by default & use a button to expand additional_data_html = ''' <button class="btn btn-secondary" data-toggle="collapse" style="min-width:0;" data-target="#show-additional-data">Show additional Data</button> <div id="show-additional-data" class="collapse"> {:} </div> '''.format(additional_data_html) additional_data_div = Div(text=additional_data_html, width=int(plot_width*0.9)) plots.append(widgetbox(additional_data_div, width=int(plot_width*0.9))) curdoc().template_variables['plots'] = jinja_plot_data return plots
t.patches(xs="xss", ys="yss", color="colors", source=session_source, line_width=0, alpha=1) hover = t.select_one(HoverTool) hover.point_policy = "follow_mouse" hover.tooltips = [ ("task type", "@tasktype"), ("#tasks", "@running_tasks"), ] # Function that clears all checkboxes and calls checkbox to redraw the plots def clear(): checkbox_group_p.active = [] checkbox("", "", "") # Button to clear all checkboxes clear_button = Button(label="clear all", width=20) clear_button.on_click(clear) # Function that sets all checkboxes and calls checkbox to redraw the plots def select_all(): checkbox_group_p.active = [i for i in range(len(attributes[1:]))] checkbox("", "", "") # Button to select all checkboxes all_button = Button(label="select all", width=20) all_button.on_click(select_all) layout = column( #row(WidgetBox(dropdown, width=405, height=100), WidgetBox(width=500),WidgetBox(runID)), row(WidgetBox(dropdown, width=410, height=100)), row(runID, startTime),
def openLog(doc): ''' :param doc: :return: document ''' doc.theme = settings.colortheme global data try: data = user_equations(data) except: print("Bad user equations, contact developer for erro code #03") #with pd.option_context('display.max_columns', None): # more options can be specified also # print(data) #atention to not overflow bokeh server starting maxSizeArray = 80000 if maxSizeArray > len(data['time']): maxSizeArray = len(data['time'])-1 last_t = 0 for index, df in data.iterrows(): t=df['time'] if t-last_t>150: remove_time = t-last_t print('Developer note: difftime: ' + str((t-last_t)/1000) + ' on data point time: ' + str(t/1000) + '. Index: ' + str(index)) data.iloc[index:,data.columns.get_loc("time")] -= remove_time last_t = t data['time'] = data['time']/1000 source = ColumnDataSource(data=data.iloc[0:maxSizeArray,:]) ##################### TIMER SLIDER GLOBAL ###################### def update(event): ''' callback for button to upgrade plots :param event: handler :return: none ''' new = time_slider.value min_index = 0 max_index = len(data['time']) for j in range(0, int(len(data['time'])/1000)): if data['time'].iloc[j*1000] > new[0]: min_index = j*1000 break for j in range(0, int(len(data['time'])/1000)): if data['time'].iloc[j*1000] > new[1]: max_index = j*1000 break #to block max size of source #if max_index-min_index > maxSizeArray: # max_index = min_index + maxSizeArray # time_slider.value = [data['time'].iloc[min_index], data['time'].iloc[maxSizeArray]] try: source.data = ColumnDataSource.from_df(data.iloc[min_index:max_index, :]) except: print("Cotact developer: Error code #2") btn_update = Button(label = 'Update', button_type="success", width_policy='min')#, width_policy='min', button_type='primary') btn_update.on_click(update) time_slider = RangeSlider(value=(data['time'].min(), data['time'].iloc[maxSizeArray]), start=data['time'].min(), end=data['time'].max(), step=10, title="Timing Data", default_size = 1300) def end(event): ''' callback function button for end program :param event: :return: none ''' sys.exit() btn_end = Button(label='Exit', button_type="success", width_policy='min') # , width_policy='min', button_type='primary') btn_end.on_click(end) doc.add_root(row(btn_update, time_slider, btn_end)) #Check if descompressed file have an CSV named correctly inside setup_tabs = open('projectfolder/configuration/tabs/globalSetup.txt').readlines() title_tabs = setup_tabs[0].split(':')[1] #title_tabs = (title_tabs.encode()[:-2]).decode() number_tabs = setup_tabs[1].split(':')[1] #number_tabs = (number_tabs.encode()[:-2]).decode() global go if go: #if (len(data.columns) == 83): if (True): ''' #Configure the HTML final to the output graphics logHTMLFile = 'finalReport_ncu/logFinal_part_' + str(l) + '.html' output_file(logHTMLFile, title='NCU LOG ' + str(l) + ' | FORMULA UFSM') curdoc().theme = 'dark_minimal' #Get each tab pannel to render the HTML file tab0 = pilot(data) tab1 = BAT(data) tab2 = LVDT(data) tab3 = TK(data) tab4 = mpu6050(data) tab5 = suspFFT(data) tab6 = suspHisto(data) tab7 = gps(data) tab8 = ncu(data) tab9 = engine(data) tab10 = tireTemp(data) ''' # Join tabs tabs = Tabs(tabs=make_ncu_tabs(source, number_tabs), name=title_tabs) ''' #for ensure the program, try to save the file with the tabs. canShow = True try: save(tabs) except: print("Error... contact developer for error code #01") canShow = False #if not get exception, display the HTML if(canShow): show(tabs) #remove the full HTML archive to clean disk space, HTML files is higher time.sleep(10) os.remove(logHTMLFile) ''' doc.add_root(tabs) doc.title = 'NCU LOG' wculogcol = pd.read_csv('./projectfolder/configuration/dataWCU.csv').shape[0] #number of lines indicates the number of collumn in a log file if ((data.shape[1]) == wculogcol): # Configure the HTML final to the output graphics #logHTMLFile = 'finalReport_ncu/logWCU.html' #output_file(logHTMLFile, title='LOG WCU | FORMULA UFSM') # curdoc().theme = 'dark_minimal' # Get each tab pannel to render the HTML file tab0 = pilot(data) tab7 = gps(data) tab9 = engine(data) tab10 = tireTemp(data) # Join tabs tabs = Tabs(tabs=[ tab0, tab9, tab7, tab10, ], name='WCU TABS') ''' # for ensure the program, try to save the file with the tabs. canShow = True try: save(tabs) except: print("Error... contact developer for error code #01") canShow = False # if not get exception, display the HTML if (canShow): show(tabs) # remove the full HTML archive to clean disk space, HTML files is higher time.sleep(10) os.remove(logHTMLFile) ''' doc.add_root(tabs) doc.title = 'WCU LOG' return doc
class SeparationDash(): """ A dashboard that displays separation data. Pass a reference to the Bokeh document for threading access. """ def __init__(self, model): """ Construct separation dashboard """ # Save reference to model self.model = model ################################ # Process button ################################ self.process = Button(label="Generate", button_type="primary", name='process', sizing_mode='scale_width', css_classes=['generate']) self.process.js_on_click(CustomJS(code="toggleLoading()")) ################################ # Widgets ################################ # Data type selection self.data_type = RadioButtonGroup( labels=["All Data", "Experimental", "Simulated"], active=0, css_classes=['dtypes']) # Adsorbate drop-down selections self.g1_sel = Select(title="Adsorbate 1", options=self.model.ads_list, value=self.model.g1, css_classes=['g-selectors']) self.g2_sel = Select(title="Adsorbate 2", options=self.model.ads_list, value=self.model.g2) # Temperature selection self.t_absolute = Spinner(value=self.model.t_abs, title='Temperature:', css_classes=['t-abs']) self.t_tolerance = Spinner(value=self.model.t_tol, title='Tolerance:', css_classes=['t-tol']) # Combined in a layout self.dsel_widgets = layout([ [self.data_type], [self.g1_sel, self.g2_sel, self.t_absolute, self.t_tolerance], ], sizing_mode='scale_width', name="widgets") ################################ # KPI Plots ################################ # Top graph generation tooltip = load_tooltip() self.p_henry, rend1 = self.top_graph("K", "Henry coefficient (log)", self.model.data, self.model.errors, tooltip) self.p_loading, rend2 = self.top_graph( "L", "Uptake at selected pressure (bar)", self.model.data, self.model.errors, tooltip) self.p_wc, rend3 = self.top_graph( "W", "Working capacity in selected range (bar)", self.model.data, self.model.errors, tooltip) # Give graphs the same hover and select effect sel = Circle(fill_alpha=1, fill_color="red", line_color=None) nonsel = Circle(fill_alpha=0.2, fill_color="blue", line_color=None) for rend in [rend1, rend2, rend3]: rend.selection_glyph = sel rend.nonselection_glyph = nonsel rend.hover_glyph = sel # Pressure slider self.p_slider = Slider( title="Pressure (bar)", value=0.5, start=0, end=20, step=0.5, callback_policy='throttle', callback_throttle=200, ) # Working capacity slider self.wc_slider = RangeSlider( title="Working capacity (bar)", value=(0.5, 5), start=0, end=20, step=0.5, callback_policy='throttle', callback_throttle=200, ) # Material datatable self.mat_list = DataTable( columns=[ TableColumn(field="labels", title="Material", width=300), TableColumn(field="sel", title="KH2/KH1", width=35, formatter=NumberFormatter(format='‘0.0a’')), TableColumn(field="psa_W", title="PSA-API", width=35, formatter=NumberFormatter(format='‘0.0a’')), ], source=self.model.data, index_position=None, selectable='checkbox', scroll_to_selection=True, width=400, fit_columns=True, ) # Custom css classes for interactors self.p_henry.css_classes = ['g-henry'] self.p_loading.css_classes = ['g-load'] self.p_wc.css_classes = ['g-wcap'] self.mat_list.css_classes = ['t-details'] # Generate the axis labels self.top_graph_labels() self.kpi_plots = layout([ [ gridplot([[self.mat_list, self.p_henry], [self.p_loading, self.p_wc]], sizing_mode='scale_width') ], [self.p_slider, self.wc_slider], ], sizing_mode='scale_width', name="kpiplots") self.kpi_plots.children[0].css_classes = ['kpi'] self.kpi_plots.children[1].css_classes = ['p-selectors'] ################################ # Isotherm details explorer ################################ # Isotherm display graphs self.p_g1iso = self.bottom_graph(self.model.g1_iso_sel, self.model.g1) self.p_g2iso = self.bottom_graph(self.model.g2_iso_sel, self.model.g2) # Isotherm display palette self.c_cyc = cycle(gen_palette(20)) self.detail_plots = layout([ [self.p_g1iso, self.p_g2iso], ], sizing_mode='scale_width', name="detailplots") self.detail_plots.children[0].css_classes = ['isotherms'] # ######################################################################### # Graph generators def top_graph(self, ind, title, d_source, e_source, tooltip, **kwargs): """Generate the top graphs (KH, uptake, WC).""" # Generate figure dict plot_side_size = 400 fig_dict = dict(tools="pan,wheel_zoom,tap,reset,save", active_scroll="wheel_zoom", plot_width=plot_side_size, plot_height=plot_side_size, title=title) fig_dict.update(kwargs) # Create a colour mapper for number of isotherms mapper = log_cmap(field_name='{0}_n'.format(ind), palette="Viridis256", low_color='grey', high_color='yellow', low=3, high=100) # Create a new plot graph = figure(**fig_dict) # Add the hover tooltip graph.add_tools( HoverTool(names=["{0}_data".format(ind)], tooltips=tooltip.render(p=ind))) # Plot the data rend = graph.circle("{0}_x".format(ind), "{0}_y".format(ind), source=d_source, size=10, line_color=mapper, color=mapper, name="{0}_data".format(ind)) # Plot guide line graph.add_layout( Slope(gradient=1, y_intercept=0, line_color='black', line_dash='dashed', line_width=2)) # Plot the error margins graph.segment('{0}_x0'.format(ind), '{0}_y0'.format(ind), '{0}_x1'.format(ind), '{0}_y1'.format(ind), source=e_source, color="black", line_width=2, line_cap='square', line_dash='dotted') # Plot labels next to selected materials graph.add_layout( LabelSet( x='{0}_x'.format(ind), y='{0}_y'.format(ind), source=e_source, text='labels', level='glyph', x_offset=5, y_offset=5, render_mode='canvas', text_font_size='10pt', )) # Add the colorbar to the side graph.add_layout( ColorBar(color_mapper=mapper['transform'], ticker=LogTicker(desired_num_ticks=10), width=8, location=(0, 0)), 'right') return graph, rend def top_graph_labels(self): """Generate the top graph labels from selected ads_list.""" self.p_loading.xaxis.axis_label = '{0} (mmol/g)'.format(self.model.g1) self.p_loading.yaxis.axis_label = '{0} (mmol/g)'.format(self.model.g2) self.p_henry.xaxis.axis_label = '{0} (mmol/bar)'.format(self.model.g1) self.p_henry.yaxis.axis_label = '{0} (mmol/bar)'.format(self.model.g2) self.p_wc.xaxis.axis_label = '{0} (mmol/g)'.format(self.model.g1) self.p_wc.yaxis.axis_label = '{0} (mmol/g)'.format(self.model.g2) def bottom_graph(self, source, ads): """Generate the bottom graphs (isotherm display).""" graph = figure(tools="pan,wheel_zoom,reset", active_scroll="wheel_zoom", plot_width=400, plot_height=250, x_range=(-0.01, 0.01), y_range=(-0.01, 0.01), title='Isotherms {0}'.format(ads)) rend = graph.multi_line('x', 'y', source=source, alpha=0.6, line_width=3, hover_line_alpha=1.0, hover_line_color="black", line_color='color') # Make clicking a graph open the NIST database graph.add_tools( HoverTool(show_arrow=False, line_policy='nearest', tooltips="""Click for details""")) graph.add_tools( TapTool(renderers=[rend], callback=CustomJS(args={ 'tp': load_details().render(), }, code=load_details_js()))) source.selected.js_on_change( 'indices', CustomJS( code= 'if (cb_obj.indices.length == 0) document.getElementById("iso-details").style.display = \"none\"' )) graph.xaxis.axis_label = 'Pressure (bar)' graph.yaxis.axis_label = 'Uptake (mmol/g)' return graph
def make_document(doc): TICKER = "" base = "http://192.168.50.62/get?accX=%s|acc_time&acc_time=%s&accY=%s|acc_time&accZ=%s|acc_time" data = ColumnDataSource( dict( time=[], # display_time=[], x=[], y=[], z=[], )) def get_last(): global current_time # print(current_time) raw = requests.get( base % (current_time, current_time, current_time, current_time)) j = raw.json() ln = min( len(j['buffer']["acc_time"]["buffer"]), len(j['buffer']["accX"]["buffer"]), len(j['buffer']["accY"]["buffer"]), len(j['buffer']["accZ"]["buffer"]), ) prices_df = pd.DataFrame.from_dict({ "time": j['buffer']["acc_time"]["buffer"][:ln], "x": j['buffer']["accX"]["buffer"][:ln], "y": j['buffer']["accY"]["buffer"][:ln], "z": j['buffer']["accZ"]["buffer"][:ln], }) if len(j['buffer']["acc_time"]["buffer"]) == 0: current_time = 0 else: current_time = j['buffer']["acc_time"]["buffer"][-1] # prices_df["time"] = pd.to_datetime(prices_df["time"], unit="ms") # prices_df["display_time"] = prices_df["time"].dt.strftime("%m-%d-%Y %H:%M:%S.%f") return prices_df def update_price(): new_price = get_last() print(len(new_price['time']), end='\n\n') data.stream( dict(time=new_price["time"], x=new_price["x"], y=new_price["y"], z=new_price["z"]), 1000) return hover = HoverTool( tooltips=[("Time", "@display_time"), ("IEX Real-Time Price", "@price")]) fig_x = figure(plot_width=800, plot_height=400, x_axis_type='datetime', tools=[WheelZoomTool(), ResetTool(), PanTool(), SaveTool()], title="Real-Time Price Plot") fig_x.line(source=data, color="navy", x='time', y='x') fig_x.xaxis.axis_label = "Time" fig_x.yaxis.axis_label = "IEX Real-Time Price" fig_x.title.text = "IEX Real Time Price: " + TICKER fig_y = figure(plot_width=800, plot_height=400, x_axis_type='datetime', tools=[WheelZoomTool(), ResetTool(), PanTool(), SaveTool()], title="Real-Time Price Plot", x_range=fig_x.x_range, y_range=fig_x.y_range) fig_y.line(source=data, color="navy", x='time', y='y') fig_y.xaxis.axis_label = "Time" fig_y.yaxis.axis_label = "IEX Real-Time Price" fig_y.title.text = "IEX Real Time Price: " + TICKER fig_z = figure(plot_width=800, plot_height=400, x_axis_type='datetime', tools=[WheelZoomTool(), ResetTool(), PanTool(), SaveTool()], title="Real-Time Price Plot", x_range=fig_x.x_range, y_range=fig_x.y_range) fig_z.line(source=data, color="navy", x='time', y='z') fig_z.xaxis.axis_label = "Time" fig_z.yaxis.axis_label = "IEX Real-Time Price" fig_z.title.text = "IEX Real Time Price: " + TICKER ticker_textbox = TextInput(placeholder="Ticker") update = Button(label="Update") inputs = widgetbox([ticker_textbox, update], width=200) doc.add_root(column(fig_x, fig_y, fig_z, width=1600)) doc.title = "Real-Time Price Plot from IEX" doc.add_periodic_callback(update_price, 30)
print("checkbox_group_handler: %s" % active) session.store_document(document) def radio_group_handler(active): print("radio_group_handler: %s" % active) session.store_document(document) def checkbox_button_group_handler(active): print("checkbox_button_group_handler: %s" % active) session.store_document(document) def radio_button_group_handler(active): print("radio_button_group_handler: %s" % active) session.store_document(document) button = Button(label="Push button", icon=Icon(name="check"), type="primary") button.on_click(button_handler) toggle = Toggle(label="Toggle button", type="success") toggle.on_click(toggle_handler) menu = [("Item 1", "item_1"), ("Item 2", "item_2"), None, ("Item 3", "item_3")] dropdown = Dropdown(label="Dropdown button", type="warning", menu=menu) dropdown.on_click(dropdown_handler) menu = [("Item 1", "foo"), ("Item 2", "bar"), None, ("Item 3", "baz")] split = Dropdown(label="Split button", type="danger", menu=menu, default_action="baz") split.on_click(split_handler) checkbox_group = CheckboxGroup(labels=["Option 1", "Option 2", "Option 3"], active=[0, 1]) checkbox_group.on_click(checkbox_group_handler)
def __init__(self, model): """ Construct separation dashboard """ # Save reference to model self.model = model ################################ # Process button ################################ self.process = Button(label="Generate", button_type="primary", name='process', sizing_mode='scale_width', css_classes=['generate']) self.process.js_on_click(CustomJS(code="toggleLoading()")) ################################ # Widgets ################################ # Data type selection self.data_type = RadioButtonGroup( labels=["All Data", "Experimental", "Simulated"], active=0, css_classes=['dtypes']) # Adsorbate drop-down selections self.g1_sel = Select(title="Adsorbate 1", options=self.model.ads_list, value=self.model.g1, css_classes=['g-selectors']) self.g2_sel = Select(title="Adsorbate 2", options=self.model.ads_list, value=self.model.g2) # Temperature selection self.t_absolute = Spinner(value=self.model.t_abs, title='Temperature:', css_classes=['t-abs']) self.t_tolerance = Spinner(value=self.model.t_tol, title='Tolerance:', css_classes=['t-tol']) # Combined in a layout self.dsel_widgets = layout([ [self.data_type], [self.g1_sel, self.g2_sel, self.t_absolute, self.t_tolerance], ], sizing_mode='scale_width', name="widgets") ################################ # KPI Plots ################################ # Top graph generation tooltip = load_tooltip() self.p_henry, rend1 = self.top_graph("K", "Henry coefficient (log)", self.model.data, self.model.errors, tooltip) self.p_loading, rend2 = self.top_graph( "L", "Uptake at selected pressure (bar)", self.model.data, self.model.errors, tooltip) self.p_wc, rend3 = self.top_graph( "W", "Working capacity in selected range (bar)", self.model.data, self.model.errors, tooltip) # Give graphs the same hover and select effect sel = Circle(fill_alpha=1, fill_color="red", line_color=None) nonsel = Circle(fill_alpha=0.2, fill_color="blue", line_color=None) for rend in [rend1, rend2, rend3]: rend.selection_glyph = sel rend.nonselection_glyph = nonsel rend.hover_glyph = sel # Pressure slider self.p_slider = Slider( title="Pressure (bar)", value=0.5, start=0, end=20, step=0.5, callback_policy='throttle', callback_throttle=200, ) # Working capacity slider self.wc_slider = RangeSlider( title="Working capacity (bar)", value=(0.5, 5), start=0, end=20, step=0.5, callback_policy='throttle', callback_throttle=200, ) # Material datatable self.mat_list = DataTable( columns=[ TableColumn(field="labels", title="Material", width=300), TableColumn(field="sel", title="KH2/KH1", width=35, formatter=NumberFormatter(format='‘0.0a’')), TableColumn(field="psa_W", title="PSA-API", width=35, formatter=NumberFormatter(format='‘0.0a’')), ], source=self.model.data, index_position=None, selectable='checkbox', scroll_to_selection=True, width=400, fit_columns=True, ) # Custom css classes for interactors self.p_henry.css_classes = ['g-henry'] self.p_loading.css_classes = ['g-load'] self.p_wc.css_classes = ['g-wcap'] self.mat_list.css_classes = ['t-details'] # Generate the axis labels self.top_graph_labels() self.kpi_plots = layout([ [ gridplot([[self.mat_list, self.p_henry], [self.p_loading, self.p_wc]], sizing_mode='scale_width') ], [self.p_slider, self.wc_slider], ], sizing_mode='scale_width', name="kpiplots") self.kpi_plots.children[0].css_classes = ['kpi'] self.kpi_plots.children[1].css_classes = ['p-selectors'] ################################ # Isotherm details explorer ################################ # Isotherm display graphs self.p_g1iso = self.bottom_graph(self.model.g1_iso_sel, self.model.g1) self.p_g2iso = self.bottom_graph(self.model.g2_iso_sel, self.model.g2) # Isotherm display palette self.c_cyc = cycle(gen_palette(20)) self.detail_plots = layout([ [self.p_g1iso, self.p_g2iso], ], sizing_mode='scale_width', name="detailplots") self.detail_plots.children[0].css_classes = ['isotherms']
tsne_figure.select(BoxSelectTool).select_every_mousemove = False tsne_figure.select(LassoSelectTool).select_every_mousemove = False def on_tsne_data_update(attr, old, new): global previously_selected_spike_indices previously_selected_spike_indices = np.array(old['1d']['indices']) tsne_source.on_change('selected', on_tsne_data_update) # Undo button undo_selected_points_button = Button(label='Undo last selection') def on_button_undo_selection(): global previously_selected_spike_indices tsne_source.data = {'tsne-x': tsne[0], 'tsne-y': tsne[1]} tsne_source.selected['1d']['indices'] = previously_selected_spike_indices old = new = tsne_source.selected tsne_source.trigger('selected', old, new) undo_selected_points_button.on_click(on_button_undo_selection) # Layout lay = column(tsne_figure, undo_selected_points_button) session = push_session(curdoc())
from bokeh.io import curdoc from jsmol_bokeh_extension import JSMol #from import_db import get_cif_content from detail.query import get_sqlite_data as get_data html = bmd.Div(text=open(join(dirname(__file__), "description.html")).read(), width=800) download_js = open(join(dirname(__file__), "static", "download.js")).read() script_source = bmd.ColumnDataSource() plot_info = PreText(text='', width=300, height=100) btn_download_table = Button(label="Download json", button_type="primary") btn_download_cif = Button(label="Download cif", button_type="primary") def get_name_from_url(): args = curdoc().session_context.request.arguments try: name = args.get('name')[0] if isinstance(name, bytes): name = name.decode() except (TypeError, KeyError): name = 'linker91_CH_linker92_N_clh_relaxed' return name
glyphDict = create_glyphs() fig = make_trial_figure() # Setup callbacks for tools and sources trialSourceDict['undefined'].on_change('selected', undefined_selected) trialSourceDict['saccade'].on_change('selected', saccade_selected) trialSourceDict['pursuit'].on_change('selected', pursuit_selected) trialSourceDict['fixation'].on_change('selected', fixation_selected) ########################################################################### # Add widgets and their callbacks #widgets = add_widgets() from bokeh.models.widgets import Button, TextInput label_saccade_button = Button(label='saccade') label_saccade_button.on_click(label_saccade_cb) label_pursuit_button = Button(label='pursuit') label_pursuit_button.on_click(label_pursuit_cb) label_fixation_button = Button(label='fixation') label_fixation_button.on_click(label_fixation_cb) remove_button = Button(label='remove') remove_button.on_click(remove_cb) trial_text = TextInput(value=str(trialNum)) trial_text.on_change('value', trial_text_cb) nextTrial_button = Button(label='+trial')
def create_interact_ui(doc): # The data source includes metadata for hover-over tooltips lc_source = prepare_lightcurve_datasource(lc) tpf_source = prepare_tpf_datasource(tpf) # Create the lightcurve figure and its vertical marker fig_lc, vertical_line = make_lightcurve_figure_elements(lc, lc_source) # Create the TPF figure and its stretch slider pedestal = np.nanmin(tpf.flux) fig_tpf, stretch_slider = make_tpf_figure_elements(tpf, tpf_source, pedestal=pedestal) # Helper lookup table which maps cadence number onto flux array index. tpf_index_lookup = {cad: idx for idx, cad in enumerate(tpf.cadenceno)} # Interactive slider widgets and buttons to select the cadence number cadence_slider = Slider(start=np.min(tpf.cadenceno), end=np.max(tpf.cadenceno), value=np.min(tpf.cadenceno), step=1, title="Cadence Number", width=490) r_button = Button(label=">", button_type="default", width=30) l_button = Button(label="<", button_type="default", width=30) # Callbacks def update_upon_pixel_selection(attr, old, new): """Callback to take action when pixels are selected.""" if ((sorted(old) == sorted(new)) & (new != [])): # Trigger recursion tpf_source.selected.indices = new[1:] if new != []: selected_indices = np.array(new) selected_mask = np.isin(pixel_index_array, selected_indices) lc_new = tpf.to_lightcurve(aperture_mask=selected_mask) lc_source.data['flux'] = lc_new.flux ylims = get_lightcurve_y_limits(lc_source) fig_lc.y_range.start = ylims[0] fig_lc.y_range.end = ylims[1] else: lc_source.data['flux'] = lc.flux * 0.0 fig_lc.y_range.start = -1 fig_lc.y_range.end = 1 def update_upon_cadence_change(attr, old, new): '''Callback to take action when cadence slider changes''' if new in tpf.cadenceno: frameno = tpf_index_lookup[new] fig_tpf.select('tpfimg')[0].data_source.data['image'] = [ tpf.flux[frameno, :, :] - pedestal ] vertical_line.update(location=tpf.time[frameno]) else: fig_tpf.select('tpfimg')[0].data_source.data['image'] = [ tpf.flux[0, :, :] * np.NaN ] lc_source.selected.indices = [] def go_right_by_one(): existing_value = cadence_slider.value if existing_value < np.max(tpf.cadenceno): cadence_slider.value = existing_value + 1 def go_left_by_one(): existing_value = cadence_slider.value if existing_value > np.min(tpf.cadenceno): cadence_slider.value = existing_value - 1 def jump_to_lightcurve_position(attr, old, new): if new != []: cadence_slider.value = lc.cadenceno[new[0]] # Map changes to callbacks r_button.on_click(go_right_by_one) l_button.on_click(go_left_by_one) tpf_source.selected.on_change('indices', update_upon_pixel_selection) lc_source.selected.on_change('indices', jump_to_lightcurve_position) cadence_slider.on_change('value', update_upon_cadence_change) # Layout all of the plots space1, space2, space3 = Spacer(width=15), Spacer(width=30), Spacer( width=80) widgets_and_figures = layout([fig_lc, fig_tpf], [ l_button, space1, r_button, space2, cadence_slider, space3, stretch_slider ]) doc.add_root(widgets_and_figures)