def salt_app(doc): import app.bokeh.salt_config as cfg # TODO: abstract parts of this to a separate file # TODO: following above, make parts reusable? # load continuous CTD data and make into a dict (only ~20MB) file_list = sorted( glob.glob("/Users/mkovatch/Documents/ctdcal/data/pressure/*.csv")) ssscc_list = [ ssscc.strip("/Users/mkovatch/Documents/ctdcal/data/pressure/")[:5] for ssscc in file_list ] ctd_data = [] for f in file_list: df = pd.read_csv(f, header=12, skiprows=[13], skipfooter=1, engine="python") df["SSSCC"] = f.strip( "/Users/mkovatch/Documents/ctdcal/data/pressure/")[:5] ctd_data.append(df) ctd_data = pd.concat(ctd_data, axis=0, sort=False) # load bottle trip file file_list = sorted( glob.glob("/Users/mkovatch/Documents/ctdcal/data/bottle/*.pkl")) ssscc_list = [ ssscc.strip("/Users/mkovatch/Documents/ctdcal/data/bottle/")[:5] for ssscc in file_list ] upcast_data = [] for f in file_list: with open(f, "rb") as x: df = pickle.load(x) df["SSSCC"] = f.strip( "/Users/mkovatch/Documents/ctdcal/data/bottle/")[:5] # change to secondary if that is what's used upcast_data.append(df[["SSSCC", "CTDCOND1", "CTDTMP1", "CTDPRS"]]) upcast_data = pd.concat(upcast_data, axis=0, sort=False) upcast_data["CTDSAL"] = gsw.SP_from_C(upcast_data["CTDCOND1"], upcast_data["CTDTMP1"], upcast_data["CTDPRS"]) # load salt file (adapted from compare_salinities.ipynb) file_list = sorted( glob.glob("/Users/mkovatch/Documents/ctdcal/data/salt/*.csv")) ssscc_list = [ ssscc.strip("/Users/mkovatch/Documents/ctdcal/data/salt/")[:5] for ssscc in file_list ] salt_data = [] for f in file_list: df = pd.read_csv(f, usecols=["STNNBR", "CASTNO", "SAMPNO", "SALNTY"]) df["SSSCC"] = f.strip( "/Users/mkovatch/Documents/ctdcal/data/salt/")[:5] salt_data.append(df) salt_data = pd.concat(salt_data, axis=0, sort=False) salt_data["SALNTY"] = salt_data["SALNTY"].round(4) if "SALNTY_FLAG_W" not in salt_data.columns: salt_data["SALNTY_FLAG_W"] = 2 # load ctd btl data df_ctd_btl = pd.read_csv( "/Users/mkovatch/Documents/ctdcal/data/scratch_folder/ctd_to_bottle.csv", skiprows=[1], skipfooter=1, engine="python", ) df_btl_all = pd.merge(df_ctd_btl, salt_data, on=["STNNBR", "CASTNO", "SAMPNO"]) btl_data = df_btl_all.loc[:, [ "SSSCC", "SAMPNO", "CTDPRS", "CTDTMP", "REFTMP", "CTDSAL", "SALNTY", "SALNTY_FLAG_W", ], ] btl_data["Residual"] = btl_data["SALNTY"] - btl_data["CTDSAL"] btl_data[["CTDPRS", "Residual"]] = btl_data[["CTDPRS", "Residual"]].round(4) btl_data["Comments"] = "" btl_data["New Flag"] = btl_data["SALNTY_FLAG_W"].copy() # update with old handcoded flags if file exists handcoded_file = "salt_flags_handcoded.csv" if glob.glob(handcoded_file): handcodes = pd.read_csv(handcoded_file, dtype={"SSSCC": str}, keep_default_na=False) handcodes = handcodes.rename(columns={ "salinity_flag": "New Flag" }).drop(columns="diff") # there's gotta be a better way. but this is good enough for now btl_data = btl_data.merge(handcodes, on=["SSSCC", "SAMPNO"], how="left") merge_rows = ~btl_data["New Flag_y"].isnull( ) | ~btl_data["Comments_y"].isnull() btl_data.loc[merge_rows, "New Flag_x"] = btl_data.loc[merge_rows, "New Flag_y"] btl_data.loc[merge_rows, "Comments_x"] = btl_data.loc[merge_rows, "Comments_y"] btl_data = btl_data.rename(columns={ "New Flag_x": "New Flag", "Comments_x": "Comments" }).drop(columns=["New Flag_y", "Comments_y"]) # intialize widgets save_button = Button(label="Save flagged data", button_type="success") parameter = Select(title="Parameter", options=["CTDSAL", "CTDTMP"], value="CTDSAL") ref_param = Select(title="Reference", options=["SALNTY"], value="SALNTY") # ref_param.options = ["foo","bar"] # can dynamically change dropdowns station = Select(title="Station", options=ssscc_list, value=ssscc_list[0]) # explanation of flags: # https://cchdo.github.io/hdo-assets/documentation/manuals/pdf/90_1/chap4.pdf flag_list = MultiSelect( title="Plot data flagged as:", value=["1", "2", "3"], options=cfg.flag_options, ) # returns list of select options, e.g., ['2'] or ['1','2'] flag_input = Select( title="Flag:", options=cfg.flag_options, value="3", ) comment_box = TextInput(value="", title="Comment:") # button_type: default, primary, success, warning or danger flag_button = Button(label="Apply to selected", button_type="primary") comment_button = Button(label="Apply to selected", button_type="warning") vspace = Div(text=""" """, width=200, height=65) bulk_flag_text = Div( text="""<br><br> <b>Bulk Bottle Flagging:</b><br> Select multiple bottles using the table (with shift/control) or the 'Box Select' tool on the plot.""", width=150, height=135, ) # set up plot datasources src_plot_trace = ColumnDataSource(data=dict(x=[], y=[])) src_plot_ctd = ColumnDataSource(data=dict(x=[], y=[])) src_plot_upcast = ColumnDataSource(data=dict(x=[], y=[])) src_plot_btl = ColumnDataSource(data=dict(x=[], y=[])) # set up plots fig = figure( title="{} vs CTDPRS [Station {}]".format(parameter.value, station.value), tools="pan,box_zoom,wheel_zoom,box_select,reset", y_axis_label="Pressure (dbar)", ) fig.select(BoxSelectTool).select_every_mousemove = False fig.y_range.flipped = True # invert y-axis fig.line( "x", "y", line_color="#000000", line_width=2, source=src_plot_trace, legend_label="CTD Trace", ) btl_sal = fig.asterisk( "x", "y", size=12, line_width=1.5, color="#0033CC", source=src_plot_btl, legend_label="Bottle sample", ) ctd_sal = fig.circle( "x", "y", size=7, color="#BB0000", source=src_plot_ctd, legend_label="Downcast CTD sample", ) upcast_sal = fig.triangle( "x", "y", size=7, color="#00BB00", source=src_plot_upcast, legend_label="Upcast CTD sample", ) fig.legend.location = "bottom_left" fig.legend.border_line_width = 3 fig.legend.border_line_alpha = 1 btl_sal.nonselection_glyph.line_alpha = 0.2 ctd_sal.nonselection_glyph.fill_alpha = 1 # makes CTDSAL *not* change on select upcast_sal.nonselection_glyph.fill_alpha = 1 # makes CTDSAL *not* change on select # define callback functions def update_selectors(): print("exec update_selectors()") ctd_rows = ctd_data["SSSCC"] == station.value table_rows = btl_data["SSSCC"] == station.value btl_rows = (btl_data["New Flag"].isin( flag_list.value)) & (btl_data["SSSCC"] == station.value) # update table data current_table = btl_data[table_rows].reset_index() src_table.data = { # this causes edit_flag() to execute "SSSCC": current_table["SSSCC"], "SAMPNO": current_table["SAMPNO"], "CTDPRS": current_table["CTDPRS"], "CTDSAL": current_table["CTDSAL"], "SALNTY": current_table["SALNTY"], "diff": current_table["Residual"], "flag": current_table["New Flag"], "Comments": current_table["Comments"], } # update plot data src_plot_trace.data = { "x": ctd_data.loc[ctd_rows, parameter.value], "y": ctd_data.loc[ctd_rows, "CTDPRS"], } src_plot_ctd.data = { "x": btl_data.loc[table_rows, parameter.value], "y": btl_data.loc[table_rows, "CTDPRS"], } src_plot_upcast.data = { "x": upcast_data.loc[upcast_data["SSSCC"] == station.value, "CTDSAL"], "y": upcast_data.loc[upcast_data["SSSCC"] == station.value, "CTDPRS"], } src_plot_btl.data = { "x": btl_data.loc[btl_rows, "SALNTY"], "y": btl_data.loc[btl_rows, "CTDPRS"], } # update plot labels/axlims fig.title.text = "{} vs CTDPRS [Station {}]".format( parameter.value, station.value) fig.xaxis.axis_label = parameter.value # deselect all datapoints btl_sal.data_source.selected.indices = [] src_table.selected.indices = [] def edit_flag(): print("exec edit_flag()") btl_data.loc[btl_data["SSSCC"] == src_table.data["SSSCC"].values[0], "New Flag", ] = src_table.data["flag"].values btl_data.loc[btl_data["SSSCC"] == src_table.data["SSSCC"].values[0], "Comments", ] = src_table.data["Comments"].values edited_rows = (btl_data["New Flag"].isin( [3, 4])) | (btl_data["Comments"] != "") src_table_changed.data = { "SSSCC": btl_data.loc[edited_rows, "SSSCC"], "SAMPNO": btl_data.loc[edited_rows, "SAMPNO"], "diff": btl_data.loc[edited_rows, "Residual"], "flag_old": btl_data.loc[edited_rows, "SALNTY_FLAG_W"], "flag_new": btl_data.loc[edited_rows, "New Flag"], "Comments": btl_data.loc[edited_rows, "Comments"], } def apply_flag(): print("Applying flags") table_rows = btl_data["SSSCC"] == station.value selected_rows = src_table.selected.indices # update table data current_table = btl_data[table_rows].reset_index() current_table.loc[selected_rows, "New Flag"] = int(flag_input.value) src_table.data = { # this causes edit_flag() to execute "SSSCC": current_table["SSSCC"], "SAMPNO": current_table["SAMPNO"], "CTDPRS": current_table["CTDPRS"], "CTDSAL": current_table["CTDSAL"], "SALNTY": current_table["SALNTY"], "diff": current_table["Residual"], "flag": current_table["New Flag"], "Comments": current_table["Comments"], } def apply_comment(): print("Applying Comments") table_rows = btl_data["SSSCC"] == station.value selected_rows = src_table.selected.indices # update table data current_table = btl_data[table_rows].reset_index() current_table.loc[selected_rows, "Comments"] = comment_box.value src_table.data = { # this causes edit_flag() to execute "SSSCC": current_table["SSSCC"], "SAMPNO": current_table["SAMPNO"], "CTDPRS": current_table["CTDPRS"], "CTDSAL": current_table["CTDSAL"], "SALNTY": current_table["SALNTY"], "diff": current_table["Residual"], "flag": current_table["New Flag"], "Comments": current_table["Comments"], } def save_data(): print("Saving flagged data...") # get data from table df_out = pd.DataFrame.from_dict(src_table_changed.data) # minor changes to columns/names/etc. df_out = df_out.rename(columns={ "flag_new": "salinity_flag" }).drop(columns="flag_old") # save it df_out.to_csv("salt_flags_handcoded.csv", index=None) def selected_from_plot(attr, old, new): src_table.selected.indices = new def selected_from_table(attr, old, new): btl_sal.data_source.selected.indices = new # set up DataTables src_table = ColumnDataSource(data=dict()) src_table_changed = ColumnDataSource(data=dict()) columns = bk.build_columns( cfg.cast_columns["fields"], cfg.cast_columns["titles"], cfg.cast_columns["widths"], ) columns_changed = bk.build_columns( cfg.changes_columns["fields"], cfg.changes_columns["titles"], cfg.changes_columns["widths"], ) data_table = DataTable( source=src_table, columns=columns, index_width=20, width=480 + 20, # sum of col widths + idx width height=600, editable=True, fit_columns=True, sortable=False, ) data_table_changed = DataTable( source=src_table_changed, columns=columns_changed, index_width=20, width=480 + 20, # sum of col widths + idx width height=200, editable=False, fit_columns=True, sortable=False, ) data_table_title = Div(text="""<b>All Station Data:</b>""", width=200, height=15) data_table_changed_title = Div(text="""<b>Flagged Data:</b>""", width=200, height=15) # set up change callbacks parameter.on_change("value", lambda attr, old, new: update_selectors()) station.on_change("value", lambda attr, old, new: update_selectors()) flag_list.on_change("value", lambda attr, old, new: update_selectors()) flag_button.on_click(apply_flag) comment_button.on_click(apply_comment) save_button.on_click(save_data) src_table.on_change("data", lambda attr, old, new: edit_flag()) src_table.selected.on_change("indices", selected_from_table) btl_sal.data_source.selected.on_change("indices", selected_from_plot) # format document controls = column( parameter, ref_param, station, flag_list, bulk_flag_text, flag_input, flag_button, comment_box, comment_button, vspace, save_button, width=170, ) tables = column(data_table_title, data_table, data_table_changed_title, data_table_changed) doc.add_root(row(controls, tables, fig)) doc.theme = Theme(filename="theme.yaml") update_selectors()
# sports['sport'] = sport # sports['sport'] = sports['sport'].str.lower() # sports['count'] = count.astype(int) # sports = sports.sort_values(by='count',ascending=False) # In[32]: def update(attr, old, new): table, m, div0 = create_plot() layout.children[2].children[0] = table layout.children[2].children[1] = m layout.children[0] = div0 div00 = Div(text="<i> Sort and Select</i>") # 1) Choose borough div1 = Div(text="<b> Choose Borough</b>") boros = ['No Preference'] + list(mid_stat.borough.unique()) select1 = Select(options=boros, value=boros[0]) select1.on_change('value', update) # 2) Mean Scores div2 = Div(text="<b> Test Score Intervals </b>") slider21 = RangeSlider(start=150, end=300, value=(150, 300), step=1, title="Math Score") slider21.on_change('value', update)
class Fit1DVisualizer(interactive.PrimitiveVisualizer): """ The generic class for interactive fitting of one or more 1D functions Attributes: reinit_panel: layout containing widgets that control the parameters affecting the initialization of the (x,y) array(s) reinit_button: the button to reconstruct the (x,y) array(s) tabs: layout containing all the stuff required for an interactive 1D fit submit_button: the button signifying a successful end to the interactive session config: the Config object describing the parameters are their constraints widgets: a dict of (param_name, widget) elements that allow the properties of the widgets to be set/accessed by the calling primitive. So far I'm only including the widgets in the reinit_panel fits: list of InteractiveModel instances, one per (x,y) array """ def __init__(self, data_source, fitting_parameters, config, reinit_params=None, reinit_extras=None, reinit_live=False, order_param="order", tab_name_fmt='{}', xlabel='x', ylabel='y', domains=None, function=None, title=None, **kwargs): """ Parameters ---------- data_source : array or function input data or the function to calculate the input data. The input data should be [x, y] or [x, y, weights] or [[x, y], [x, y],.. or [[x, y, weights], [x, y, weights].. or, if a function, it accepts (config, extras) where extras is a dict of values based on reinit_extras and returns [[x, y], [x, y].. or [[x, y, weights], [x, y, weights], ... fitting_parameters : list of :class:`~geminidr.interactive.fit.fit1d.FittingParameters` or :class:`~geminidr.interactive.fit.fit1d.FittingParameters` Description of parameters to use for `fit_1d` config : Config instance describing primitive parameters and limitations reinit_params : list of str list of parameter names in config related to reinitializing fit arrays. These cause the `data_source` function to be run to get the updated coordinates/weights. Should not be passed if `data_source` is not a function. reinit_extras : Extra parameters to show on the left side that can affect the output of `data_source` but are not part of the primitive configuration. Should not be passed if `data_source` is not a function. reinit_live : If False, supplies a button to call the `data_source` function and doesn't do so automatically when inputs are adjusted. If `data_source` is known to be inexpensive, you can set this to `True` order_param : str Name of the parameter this primitive uses for `order`, to infer the min/max suggested values tab_name_fmt : str Format string for naming the tabs xlabel : str String label for X axis ylabel : str String label for Y axis domains : list List of domains for the inputs function : str ID of fit_1d function to use, if not a configuration option title : str Title for UI (Interactive <Title>) """ super().__init__(config=config, title=title) # title_div = None # if title is not None: # title_div = Div(text='<h2>%s</h2>' % title) # Make the widgets accessible from external code so we can update # their properties if the default setup isn't great self.widgets = {} # Make the panel with widgets to control the creation of (x, y) arrays # Function - either a dropdown or a label for the single option if 'function' in config._fields: fn = config.function fn_allowed = [k for k in config._fields['function'].allowed.keys()] # Dropdown for selecting fit_1D function self.function = Select(title="Fitting Function:", value=fn, options=fn_allowed) def fn_select_change(attr, old, new): def refit(): for fit in self.fits: fit.set_function(new) fit.perform_fit() self.do_later(refit) self.function.on_change('value', fn_select_change) else: if function is None: function = 'chebyshev' self.function = Div(text='Function: %s' % function) if reinit_params is not None or reinit_extras is not None: # Create left panel reinit_widgets = self.make_widgets_from_config( reinit_params, reinit_extras, reinit_live) # This should really go in the parent class, like submit_button if not reinit_live: self.reinit_button = bm.Button(label="Reconstruct points") self.reinit_button.on_click(self.reconstruct_points) self.make_modal( self.reinit_button, "<b>Recalculating Points</b><br/>This may take 20 seconds") reinit_widgets.append(self.reinit_button) self.reinit_panel = column(self.function, *reinit_widgets) else: # left panel with just the function selector (Chebyshev, etc.) self.reinit_panel = column(self.function) # Grab input coordinates or calculate if we were given a callable # TODO revisit the raging debate on `callable` for Python 3 if callable(data_source): self.reconstruct_points_fn = data_source data = data_source(config, self.extras) # For this, we need to remap from # [[x1, y1, weights1], [x2, y2, weights2], ...] # to allx=[x1,x2..] ally=[y1,y2..] all_weights=[weights1,weights2..] allx = list() ally = list() all_weights = list() for dat in data: allx.append(dat[0]) ally.append(dat[1]) if len(dat) >= 3: all_weights.append(dat[2]) if len(all_weights) == 0: all_weights = None else: self.reconstruct_points_fn = None if reinit_params: raise ValueError( "Saw reinit_params but data_source is not a callable") if reinit_extras: raise ValueError( "Saw reinit_extras but data_source is not a callable") allx = data_source[0] ally = data_source[1] if len(data_source) >= 3: all_weights = data_source[2] else: all_weights = None # Some sanity checks now if isinstance(fitting_parameters, list): if not (len(fitting_parameters) == len(allx) == len(ally)): raise ValueError("Different numbers of models and coordinates") self.nfits = len(fitting_parameters) else: if allx.size != ally.size: raise ValueError("Different (x, y) array sizes") self.nfits = 1 self.reinit_extras = [] if reinit_extras is None else reinit_extras kwargs.update({'xlabel': xlabel, 'ylabel': ylabel}) if order_param and order_param in self.config._fields: field = self.config._fields[order_param] if hasattr(field, 'min') and field.min: kwargs['min_order'] = field.min else: kwargs['min_order'] = 1 if hasattr(field, 'max') and field.max: kwargs['max_order'] = field.max else: kwargs['max_order'] = field.default * 2 else: kwargs['min_order'] = 1 kwargs['max_order'] = 10 self.tabs = bm.Tabs(tabs=[], name="tabs") self.tabs.sizing_mode = 'scale_width' self.fits = [] if self.nfits > 1: if domains is None: domains = [None] * len(fitting_parameters) if all_weights is None: all_weights = [None] * len(fitting_parameters) for i, (fitting_parms, domain, x, y, weights) in \ enumerate(zip(fitting_parameters, domains, allx, ally, all_weights), start=1): tui = Fit1DPanel(self, fitting_parms, domain, x, y, weights, **kwargs) tab = bm.Panel(child=tui.component, title=tab_name_fmt.format(i)) self.tabs.tabs.append(tab) self.fits.append(tui.fit) else: tui = Fit1DPanel(self, fitting_parameters[0], domains, allx[0], ally[0], all_weights[0], **kwargs) tab = bm.Panel(child=tui.component, title=tab_name_fmt.format(1)) self.tabs.tabs.append(tab) self.fits.append(tui.fit) def visualize(self, doc): """ Start the bokeh document using this visualizer. This call is responsible for filling in the bokeh document with the user interface. Parameters ---------- doc : :class:`~bokeh.document.Document` bokeh document to draw the UI in """ super().visualize(doc) col = column(self.tabs, ) col.sizing_mode = 'scale_width' layout = column(row(self.reinit_panel, col), self.submit_button, sizing_mode="stretch_width") doc.add_root(layout) def reconstruct_points(self): """ Reconstruct the initial points to work with. This is expected to be expensive. The core inputs are separated out in the UI as they are too slow to be interactive. When a user is ready and submits updated core config parameters, this is what gets executed. The configuration is updated with the new values form the user. The UI is disabled and the expensive function is wrapped in the bokeh Tornado event look so the modal dialog can display. """ if hasattr(self, 'reinit_button'): self.reinit_button.disabled = True def fn(): """Top-level code to update the Config with the values from the widgets""" config_update = {k: v.value for k, v in self.widgets.items()} for extra in self.reinit_extras: del config_update[extra] for k, v in config_update.items(): print(f'{k} = {v}') self.config.update(**config_update) self.do_later(fn) if self.reconstruct_points_fn is not None: def rfn(): all_coords = self.reconstruct_points_fn( self.config, self.extras) for fit, coords in zip(self.fits, all_coords): if len(coords) > 2: fit.weights = coords[2] else: fit.weights = None fit.weights = fit.populate_bokeh_objects(coords[0], coords[1], fit.weights, mask=None) fit.perform_fit() if hasattr(self, 'reinit_button'): self.reinit_button.disabled = False self.do_later(rfn) def results(self): """ Get the results of the interactive fit. This gets the list of `~gempy.library.fitting.fit_1D` fits of the data to be used by the caller. Returns ------- list of `~gempy.library.fitting.fit_1D` """ return [fit.model.fit for fit in self.fits]
code=""" color_mapper.low = Number(this.value) """)) map_range_widgets.append(text_input) # %% Make heading for the whole thing """ # %% Make heading for the whole thing """ heading = Div(text=""" <h1> Animated COVID-19 Data Mapped For US Counties - NYT Styled</h1> <p>Shows the continental US heatmapped to the previous weeks average number of COVID-19 cases per 100k people in each county.</p> <ul> <li>Higher color number corresponds to faster spread of the virus.</li> <li>On the left of each graph thera are tools to zoom/pan/reset/save.</li> <li>Double tap the map to reset zoom/pan.</li> <li>On Mobile: Use two finger to scroll the page.</li> <li>Data last updated on: {data_update} </li> </ul> """.format( data_update=pd.to_datetime(latest_data_date).strftime('%Y-%m-%d'), graph_update=pd.Timestamp.now().strftime('%Y-%m-%d'), )) footer = Div(text=""" <h3> Sources </h3> <ul> <li>GitHub repository for this project: <a href="https://github.com/thedrdos/covid-map"> https://github.com/thedrdos/covid-map </a>. </li> <li>Produced using Python with Bokeh and other modules.</li> <li>Data sourced from <a href="https://github.com/nytimes/covid-19-data"> The New York Times COVID Data GitHub Repository</a>. </li> </ul> <h4> Data Defintions: </h4>
def _get_title_div(self, key, default_fontsize='15pt', width=450): title_div = None title = self._format_title(key) if self.show_title else '' if not title: return title_div title_json = theme_attr_json(self.renderer.theme, 'Title') color = title_json.get('text_color', None) font = title_json.get('text_font', 'Arial') fontstyle = title_json.get('text_font_style', 'bold') fontsize = self._fontsize('title').get('fontsize', default_fontsize) if fontsize == default_fontsize: # if default fontsize = title_json.get('text_font_size', default_fontsize) if 'em' in fontsize: # it's smaller than it shosuld be so add 0.25 fontsize = str(float(fontsize[:-2]) + 0.25) + 'em' title_tags = self._title_template.format( color=color, font=font, fontstyle=fontstyle, fontsize=fontsize, title=title) if 'title' in self.handles: title_div = self.handles['title'] else: title_div = Div(width=width, style={"white-space": "nowrap"}) # so it won't wrap long titles easily title_div.text = title_tags return title_div
def _get_title(self, key): title_div = None title = self._format_title(key) if self.show_title else '' if title: fontsize = self._fontsize('title') title_tags = self._title_template.format(title=title, **fontsize) if 'title' in self.handles: title_div = self.handles['title'] else: title_div = Div() title_div.text = title_tags return title_div
from bokeh.models import ColumnDataSource, Div from bokeh.models.widgets import Slider, Select, TextInput from bokeh.io import curdoc from bokeh.sampledata.movies_data import movie_path import bokeh import netCDF4 #from collections import Dict varoptions = ["None"] dimoptions = ["None"] desc = Div(text=open(join(dirname(__file__), "description.html")).read(), width=800) # Create Input controls #reviews = Slider(title="Minimum number of reviews", value=80, start=10, end=300, step=10) x_axis = Select(title="X Axis", options=varoptions, value="None") y_axis = Select(title="Y Axis", options=varoptions, value="None") variable_axis = Select(title="Color", options=varoptions, value="None") # Create Column Data Source that will be used by the plot source = ColumnDataSource(data=dict(x=[], y=[], color=[])) p = figure(plot_height=600, plot_width=700, title="", toolbar_location=None) p.circle(x="x", y="y", color="color", source=source, size=7, line_color=None)
widgetbox(X_sampling,width=350), widgetbox(Y_sampling,width=350), widgetbox(Xselect,width=350), widgetbox(Yselect,width=350), widgetbox(Zselect,width=350), widgetbox(text_input,width=350), widgetbox(bt,width=350), widgetbox(radio_button_group,width=350), width=400), column(p,width=800), ) """ div = Div(text='Tooltips (Double Click on a point to view)', width=200, height=100) ldict = dict(c(dfs['threshold'])) ldictkeys = list(ldict.keys()) ldictvalues = list(ldict.values()) ldictlist = [ '<b>' + str(ldictkeys[f]) + '</b>' + ': ' + str(ldictvalues[f]) for f in range(len(ldictvalues)) ] ldictfinal = '\n'.join(ldictlist) plot_text = Div( text= '<b style="color:Gray;"></b><br><b style="color:MediumSeaGreen;">Points displayed : Total points in the dataset: </b>' + str(len(dfs)) + ':' + str(len(df)) + '\n' +
heimdall_source = ColumnDataSource(data=dict(x=[], y=[])) sigproc_source = ColumnDataSource(data=dict( disp=[], dedisp=[], conv=[])) #This will change depending upon the input from sigproc ##################### Creating the interface for the candidate viewer ##################### #UTC input text box utc_input = TextInput(value="Enter UTC here", title="UTC (YYYY-MM-DD-HH:SS:SS)") SAMPLE_UTC = "2018-04-08-11:08:23" print SAMPLE_UTC # Error text box errbox = Div(text="", width=800) errtext = open(os.path.join(os.path.dirname(__file__), "errbox.html")).read() #Candidate viewer plot x_axis = Select(title="X-axis", options=sorted(HeimdallHeader), value="snr") y_axis = Select(title="Y-axis", options=sorted(HeimdallHeader), value="dm") candview = figure(plot_height=600, plot_width=800, title="Candidate Viewer", tools=['tap', 'pan', 'wheel_zoom', 'reset']) candview_plot = candview.circle(x='x', y='y', source=heimdall_source, size=6) #Create range sliders for filtering the candidates in the candview plot - (can add more eventually) snr_range = RangeSlider(title="SNR", start=0, end=10, value=(0, 10), step=1) dm_range = RangeSlider(title="DM", start=0, end=10, value=(0, 10), step=1)
TableColumn(field="recentVol_emaAtr_diff_Atr", title="Volatility (ATR) Spread"), TableColumn(field="ExcessFwdRets", title="Excess Fwd Rets"), TableColumn(field="SpearmanCorr", title="Spearman Rank Correlation"), TableColumn(field="PearsonCorr", title="Pearson Correlation"), TableColumn(field="intercept", title="Line Regress Intercept"), TableColumn(field="slope", title="Line Regress Slope"), TableColumn(field="AbsValExcessFwdRets", title="Magnitude Rets"), TableColumn(field="StockFwdRets", title="Target Fwd Rets"), TableColumn(field="BenchmarkFwdRets", title="Benchmark Fwd Rets"), TableColumn(field="StockAdjClose", title="Target Px. (Adj Close)"), TableColumn(field="BenchmarkAdjClose", title="Benchmark Px (Adj Close)") ] agg_stats_title_div = Div( text="""<b>Aggregated Statistics, Selected Data</b> """, width=1000, height=20, background="yellow") data_table = DataTable(source=source, columns=columns, width=1000) ts_data_corrAnalysis_title_div = Div( text="""<b>Correlation Analysis - Time Series Data</b> """, width=1000, height=20, background="yellow") stats_data_table = DataTable(source=stats_source, columns=stats_columns, height=250, width=1000) period_cum_returns_title_div = Div( text="""<b>Periodic & Cummulative Returns, Selected Data</b> """, width=1000,
def view(a): return Div(text='%d' % a)
def create_cws_map(df, suffix): """Reads in a data-frame and exports a html file, containing a bokeh map, placed within the 'maps' folder. Parameters ---------- df : dataframe A dataframe that must contain the following columns: - geometry - p_id - lon - lat - ta_int suffix : str A string that will be appended to the title of the plots as well as the html file-names. """ tile_provider = get_provider( "CARTODBPOSITRON_RETINA" ) # More Providers https://docs.bokeh.org/en/latest/docs/reference/tile_providers.html # Range bounds supplied in web mercator coordinates p = figure( x_range=(825000, 833000), y_range=(5933000, 5935000), x_axis_type="mercator", y_axis_type="mercator", # Changes axis to a more legible input x_axis_label="Longitude", y_axis_label="Latitude", sizing_mode="stretch_both") p.add_tile(tile_provider) # Filter point sto be added by color p = filter_points_by_color(df, p) # Add hover tools as a means for interactivity my_hover = HoverTool( ) # https://automating-gis-processes.github.io/2016/Lesson5-interactive-map-bokeh.html#adding-interactivity-to-the-map # Specify what parameters should be displayed when hovering my_hover.tooltips = [('Id', '@p_id'), ('Temperature [C]', '@ta_int'), ('Longitude', '@lon'), ('Latitude', '@lat')] p.add_tools(my_hover) # Creating divs to serve as additional information div_title = Div(align="center", text="<h1>Citizen Weather Stations: " + suffix + ":00</h1>", sizing_mode="stretch_both") div_subtitle = Div( align="center", text= "Blue: Below 22 °C. <br> Orange: Between 22 °C and 28 °C. <br> Red: Above 28 °C.", sizing_mode="stretch_both") # Arrange all the bokeh elements in a layout layout_plot = layout([[div_title], [div_subtitle], [p]]) # Specify output location and name output_file("../maps/Bern-CWS-Map_" + suffix + ".html") # Shows the result in the default browser and saves the file show(layout_plot)
def startserver(doc): file_input = FileInput(accept=".ulg, .csv") file_input.on_change('value', upload_new_data_sim) file_input2 = FileInput(accept=".ulg, .csv") file_input2.on_change('value', upload_new_data_real) intro_text = Div(text="""<H2>Sim/Real Thiel Coefficient Calculator</H2>""", width=500, height=100, align="center") sim_upload_text = Paragraph(text="Upload a simulator datalog:", width=500, height=15) real_upload_text = Paragraph( text="Upload a corresponding real-world datalog:", width=500, height=15) #checkbox_group = CheckboxGroup(labels=["x", "y", "vx","vy","lat","lon"], active=[0, 1]) sim_reverse_button = RadioButtonGroup(labels=["Sim Default", "Reversed"], active=0) sim_reverse_button.on_change('active', lambda attr, old, new: reverse_sim()) real_reverse_button = RadioButtonGroup(labels=["Real Default", "Reversed"], active=0) real_reverse_button.on_change('active', lambda attr, old, new: reverse_real()) simsource_static.selected.on_change('indices', simselection_change) # The below are in case you want to see the x axis range change as you pan. Poorly documented elsewhere! #ts1.x_range.on_change('end', lambda attr, old, new: print ("TS1 X range = ", ts1.x_range.start, ts1.x_range.end)) #ts2.x_range.on_change('end', lambda attr, old, new: print ("TS2 X range = ", ts2.x_range.start, ts2.x_range.end)) ts1.x_range.on_change( 'end', lambda attr, old, new: change_sim_scale(ts1.x_range.start)) ts2.x_range.on_change( 'end', lambda attr, old, new: change_real_scale(ts2.x_range.start)) # set up layout widgets = column(datatype, stats) sim_button = column(sim_reverse_button) real_button = column(real_reverse_button) main_row = row(widgets) series = column(ts1, sim_button, ts2, real_button) layout = column(main_row, series) # initialize update() doc.add_root(intro_text) doc.add_root(sim_upload_text) doc.add_root(file_input) doc.add_root(real_upload_text) doc.add_root(file_input2) doc.add_root(layout) doc.title = "Flight data" # horizonal marker line at 1 data_span = Span(location=1, dimension='width', line_color='black', line_alpha=0.5, line_width=1.5) p.add_layout(data_span) data_plot.set_use_time_formatter(False) data_plot.finalize()
def view(self): return Div(text='%d' % self.a)
def kafka_spark_streamer(doc): try: div = Div(text='Just close this window please') doc.add_root(div) except Exception: logger.error("TABS:", exc_info=True)
sv_hist.upper_spinner, sv_hist.nbins_spinner, ), ) layout_utility = column( gridplot( sv_streamgraph.plots, ncols=1, toolbar_location="left", toolbar_options=dict(logo=None) ), row( sv_streamgraph.moving_average_spinner, column(Spacer(height=19), sv_streamgraph.reset_button), ), ) show_overlays_div = Div(text="Show Overlays:") layout_controls = row( column( row(sv_colormapper.select, sv_colormapper.high_color, sv_colormapper.mask_color), row(sv_colormapper.display_min_spinner, sv_colormapper.display_max_spinner), row(sv_colormapper.auto_toggle, sv_colormapper.scale_radiobuttongroup), show_overlays_div, row(sv_resolrings.toggle, sv_main.proj_toggle), row(sv_intensity_roi.toggle, sv_saturated_pixels.toggle), ), Spacer(width=30), column( row(sv_streamctrl.datatype_select, sv_streamctrl.rotate_image), sv_streamctrl.prev_image_slider, row(sv_streamctrl.conv_opts, sv_streamctrl.double_pixels),
def lorenz_tab2(plot_dict, data): def make_plot(src, src_raw): p = figure( plot_width=800, plot_height=400, tooltips="$name: $y{0.00%} ", ) lines = [ "deciles", "total_income_share", "net_income_share", "net_income_share_simulated", ] labels = [ "Perfect equality", "Total income (pre tax)", "Total income (after tax status quo)", "Total income (after tax simulated reform)", ] colors = Category10[len(lines)] for i in range(len(lines)): p.line( "deciles", lines[i], source=src, line_color=colors[i], legend_label=labels[i], alpha=0.8, muted_color=colors[i], muted_alpha=0.2, name=labels[i], ) p.circle( "deciles", lines[i], source=src, fill_color=colors[i], legend_label=labels[i], line_color=None, name=labels[i], alpha=0.8, muted_color=colors[i], muted_alpha=0.2, ) p.xaxis.tags = ["numeric"] plot = plotstyle(p, plot_dict) # Table to display source data columns = [ TableColumn(field="deciles", title="Deciles"), TableColumn(field="total_income", title="Total income (before tax)"), TableColumn(field="net_income", title="Total income (after tax status quo)"), TableColumn(field="net_income_simulated", title="Total income (after tax reform)"), TableColumn(field="weights", title="Decile weights"), ] data_table = DataTable( source=src_raw, columns=columns, width=800, height=350, selectable=False, autosize_mode="fit_columns", ) return plot, data_table src, src_raw = ( ColumnDataSource(data["income_share_dict"]), ColumnDataSource(data["raw_dict"]), ) plot, table = make_plot(src, src_raw) description = Div( text=plot_dict["description"], width=1000, ) table_title = Div( text= """<b>Source data: Average (taxable) income per decile (in €)</b>""", width=800, height=20, ) reference = Div( text= """Data from <a href="http://hdl.handle.net/10419/172793">Bach and Buslei 2017</a> table 3-2 and own calculations. Columns show average taxable income per decile in Euro. Capital income calculated as avg. capital tax / 0.26375.""", width=800, height=80, ) layout = column(description, plot, table_title, table, reference) tab = Panel(child=layout, title="Lorenz curves (Reform)") return tab
# This data source is just used to communicate / trigger the real callback Slider_watershed.on_change('value', Slider_watershed_update) Slider_threshold = Slider( start=0, end=100, value=0, step=1, title="threshold", width=config_main['plot_config']['tab_XCorr']['widgetbox_wdth'], callback_policy='mouseup') Slider_threshold.on_change('value', Slider_threshold_update) Div_exit = Div( text="""<p><b>Warning</b>: Click <b>Exit</b> first before closing the tab</p></b>""", width=config_main['plot_config']['tab_FSview_base']['widgetbox_wdth']) BUT_exit = Button( label='Exit FSview', width=config_main['plot_config']['tab_FSview_base']['widgetbox_wdth'], button_type='danger') BUT_exit.on_click(exit_update) lout = column( row(gridplot([[p_dspec, p_dspecfit]], toolbar_location='right'), p_dspec_profile), row(gridplot([[p_CCmax, p_CCpeak]], toolbar_location='right'), column(Slider_watershed, Slider_threshold, BUT_exit, Div_exit))) curdoc().add_root(lout)
def __init__(self, data_source, fitting_parameters, config, reinit_params=None, reinit_extras=None, reinit_live=False, order_param="order", tab_name_fmt='{}', xlabel='x', ylabel='y', domains=None, function=None, title=None, **kwargs): """ Parameters ---------- data_source : array or function input data or the function to calculate the input data. The input data should be [x, y] or [x, y, weights] or [[x, y], [x, y],.. or [[x, y, weights], [x, y, weights].. or, if a function, it accepts (config, extras) where extras is a dict of values based on reinit_extras and returns [[x, y], [x, y].. or [[x, y, weights], [x, y, weights], ... fitting_parameters : list of :class:`~geminidr.interactive.fit.fit1d.FittingParameters` or :class:`~geminidr.interactive.fit.fit1d.FittingParameters` Description of parameters to use for `fit_1d` config : Config instance describing primitive parameters and limitations reinit_params : list of str list of parameter names in config related to reinitializing fit arrays. These cause the `data_source` function to be run to get the updated coordinates/weights. Should not be passed if `data_source` is not a function. reinit_extras : Extra parameters to show on the left side that can affect the output of `data_source` but are not part of the primitive configuration. Should not be passed if `data_source` is not a function. reinit_live : If False, supplies a button to call the `data_source` function and doesn't do so automatically when inputs are adjusted. If `data_source` is known to be inexpensive, you can set this to `True` order_param : str Name of the parameter this primitive uses for `order`, to infer the min/max suggested values tab_name_fmt : str Format string for naming the tabs xlabel : str String label for X axis ylabel : str String label for Y axis domains : list List of domains for the inputs function : str ID of fit_1d function to use, if not a configuration option title : str Title for UI (Interactive <Title>) """ super().__init__(config=config, title=title) # title_div = None # if title is not None: # title_div = Div(text='<h2>%s</h2>' % title) # Make the widgets accessible from external code so we can update # their properties if the default setup isn't great self.widgets = {} # Make the panel with widgets to control the creation of (x, y) arrays # Function - either a dropdown or a label for the single option if 'function' in config._fields: fn = config.function fn_allowed = [k for k in config._fields['function'].allowed.keys()] # Dropdown for selecting fit_1D function self.function = Select(title="Fitting Function:", value=fn, options=fn_allowed) def fn_select_change(attr, old, new): def refit(): for fit in self.fits: fit.set_function(new) fit.perform_fit() self.do_later(refit) self.function.on_change('value', fn_select_change) else: if function is None: function = 'chebyshev' self.function = Div(text='Function: %s' % function) if reinit_params is not None or reinit_extras is not None: # Create left panel reinit_widgets = self.make_widgets_from_config( reinit_params, reinit_extras, reinit_live) # This should really go in the parent class, like submit_button if not reinit_live: self.reinit_button = bm.Button(label="Reconstruct points") self.reinit_button.on_click(self.reconstruct_points) self.make_modal( self.reinit_button, "<b>Recalculating Points</b><br/>This may take 20 seconds") reinit_widgets.append(self.reinit_button) self.reinit_panel = column(self.function, *reinit_widgets) else: # left panel with just the function selector (Chebyshev, etc.) self.reinit_panel = column(self.function) # Grab input coordinates or calculate if we were given a callable # TODO revisit the raging debate on `callable` for Python 3 if callable(data_source): self.reconstruct_points_fn = data_source data = data_source(config, self.extras) # For this, we need to remap from # [[x1, y1, weights1], [x2, y2, weights2], ...] # to allx=[x1,x2..] ally=[y1,y2..] all_weights=[weights1,weights2..] allx = list() ally = list() all_weights = list() for dat in data: allx.append(dat[0]) ally.append(dat[1]) if len(dat) >= 3: all_weights.append(dat[2]) if len(all_weights) == 0: all_weights = None else: self.reconstruct_points_fn = None if reinit_params: raise ValueError( "Saw reinit_params but data_source is not a callable") if reinit_extras: raise ValueError( "Saw reinit_extras but data_source is not a callable") allx = data_source[0] ally = data_source[1] if len(data_source) >= 3: all_weights = data_source[2] else: all_weights = None # Some sanity checks now if isinstance(fitting_parameters, list): if not (len(fitting_parameters) == len(allx) == len(ally)): raise ValueError("Different numbers of models and coordinates") self.nfits = len(fitting_parameters) else: if allx.size != ally.size: raise ValueError("Different (x, y) array sizes") self.nfits = 1 self.reinit_extras = [] if reinit_extras is None else reinit_extras kwargs.update({'xlabel': xlabel, 'ylabel': ylabel}) if order_param and order_param in self.config._fields: field = self.config._fields[order_param] if hasattr(field, 'min') and field.min: kwargs['min_order'] = field.min else: kwargs['min_order'] = 1 if hasattr(field, 'max') and field.max: kwargs['max_order'] = field.max else: kwargs['max_order'] = field.default * 2 else: kwargs['min_order'] = 1 kwargs['max_order'] = 10 self.tabs = bm.Tabs(tabs=[], name="tabs") self.tabs.sizing_mode = 'scale_width' self.fits = [] if self.nfits > 1: if domains is None: domains = [None] * len(fitting_parameters) if all_weights is None: all_weights = [None] * len(fitting_parameters) for i, (fitting_parms, domain, x, y, weights) in \ enumerate(zip(fitting_parameters, domains, allx, ally, all_weights), start=1): tui = Fit1DPanel(self, fitting_parms, domain, x, y, weights, **kwargs) tab = bm.Panel(child=tui.component, title=tab_name_fmt.format(i)) self.tabs.tabs.append(tab) self.fits.append(tui.fit) else: tui = Fit1DPanel(self, fitting_parameters[0], domains, allx[0], ally[0], all_weights[0], **kwargs) tab = bm.Panel(child=tui.component, title=tab_name_fmt.format(1)) self.tabs.tabs.append(tab) self.fits.append(tui.fit)
def xrayvis_app(doc): def load_wav_cb(attr, old, new): '''Handle selection of audio file to be loaded.''' if new == '': return global wavname global snd spkr, fname = os.path.split(new) wavname = get_cached_fname( fname, f'https://linguistics.berkeley.edu/phonapps/xray_microbeam_database/{spkr}', spkr) # wavname = new if not wavname.endswith('.wav'): return snd = parselmouth.Sound(wavname) srcdf = pd.DataFrame( dict( seconds=snd.ts().astype(np.float32), ch0=snd.values[0, :].astype(np.float32), )) #! TODO: do file caching phdf = allphdf.loc[allphdf.wavpath == new, :].copy() phdf['t1'] = phdf['t1'].astype(np.float32) wddf = allwddf.loc[allwddf.wavpath == new, :].copy() wddf['t1'] = wddf['t1'].astype(np.float32) uttdiv.text = '<b>Utterance:</b> ' + ' '.join( wddf.word.str.replace('sp', '')).strip() phwddf = pd.merge_asof(phdf[['t1', 'phone']], wddf[['t1', 'word']], on='t1', suffixes=['_ph', '_wd']) # TODO: separate t1_ph and t1_wd columns srcdf = pd.merge_asof(srcdf, phwddf, left_on='seconds', right_on='t1') srcdf[['phone', 'word']] = srcdf[['phone', 'word']].fillna('') srcdf = srcdf.drop('t1', axis='columns') dfs['srcdf'] = srcdf source.data = srcdf tngsource.data = {'x': [], 'y': []} othsource.data = {'x': [], 'y': []} timesource.data = {k: [] for k in timesource.data.keys()} lasttngtimesource.data = {'x': [], 'y': []} lastothtimesource.data = {'x': [], 'y': []} playvisbtn.channels = channels playvisbtn.disabled = False playselbtn.channels = channels playselbtn.disabled = False playvisbtn.fs = snd.sampling_frequency playvisbtn.start = snd.start_time playvisbtn.end = snd.end_time playselbtn.fs = snd.sampling_frequency playselbtn.start = 0.0 playselbtn.end = 0.0 selbox.left = 0.0 selbox.right = 0.0 selbox.visible = False cursor.location = 0.0 cursor.visible = False ch0.visible = True update_sgram() load_artic() set_limits(0.0, srcdf['seconds'].max()) def load_artic(): '''Load articulation data.''' trace.title.text = 'Static trace' traj.title.text = 'Trajectories' tngfile = os.path.splitext(wavname)[0] + '.txy' palfile = os.path.join(os.path.dirname(wavname), 'PAL.DAT') phafile = os.path.join(os.path.dirname(wavname), 'PHA.DAT') tngdf = pd.read_csv(tngfile, sep='\t', names=[ 'sec', 'ULx', 'ULy', 'LLx', 'LLy', 'T1x', 'T1y', 'T2x', 'T2y', 'T3x', 'T3y', 'T4x', 'T4y', 'MIx', 'MIy', 'MMx', 'MMy' ]) # Convert to seconds tngdf['sec'] = tngdf['sec'] / 1e6 tngdf = tngdf.set_index(['sec']) # Convert to mm tngdf[[ 'ULx', 'ULy', 'LLx', 'LLy', 'T1x', 'T1y', 'T2x', 'T2y', 'T3x', 'T3y', 'T4x', 'T4y', 'MIx', 'MIy', 'MMx', 'MMy' ]] = tngdf[[ 'ULx', 'ULy', 'LLx', 'LLy', 'T1x', 'T1y', 'T2x', 'T2y', 'T3x', 'T3y', 'T4x', 'T4y', 'MIx', 'MIy', 'MMx', 'MMy' ]] * 1e-3 # Find global x/y max/min in this recording to set axis limits. # Exclude bad values (1000000 in data file; 1000 mm in scaled dataframe). cmpdf = tngdf[tngdf < badval] xmax = np.max( np.max( cmpdf[['ULx', 'LLx', 'T1x', 'T2x', 'T3x', 'T4x', 'MIx', 'MMx']])) xmin = np.min( np.min( cmpdf[['ULx', 'LLx', 'T1x', 'T2x', 'T3x', 'T4x', 'MIx', 'MMx']])) ymax = np.max( np.max( cmpdf[['ULy', 'LLy', 'T1y', 'T2y', 'T3y', 'T4y', 'MIy', 'MMy']])) ymin = np.min( np.min( cmpdf[['ULy', 'LLy', 'T1y', 'T2y', 'T3y', 'T4y', 'MIy', 'MMy']])) paldf = pd.read_csv(palfile, sep='\s+', header=None, names=['x', 'y']) paldf = paldf * 1e-3 palsource.data = {'x': paldf['x'], 'y': paldf['y']} phadf = pd.read_csv(phafile, sep='\s+', header=None, names=['x', 'y']) phadf = phadf * 1e-3 phasource.data = {'x': phadf['x'], 'y': phadf['y']} xmin = np.min([xmin, np.min(paldf['x']), np.min(phadf['x'])]) xmax = np.max([xmax, np.max(paldf['x']), np.max(phadf['x'])]) ymin = np.min([ymin, np.min(paldf['y']), np.min(phadf['y'])]) ymax = np.max([ymax, np.max(paldf['y']), np.max(phadf['y'])]) xsz = xmax - xmin ysz = ymax - ymin xrng = [xmin - (xsz * 0.05), xmax + (xsz * 0.05)] yrng = [ymin - (ysz * 0.05), ymax + (ysz * 0.05)] dfs['tngdf'] = tngdf dfs['paldf'] = paldf dfs['phadf'] = phadf def update_sgram(): '''Update spectrogram based on current values.''' if snd.end_time < 15: sgrams[0] = snd2specgram(snd, 0.005) specsource.data = dict( sgram0=[sgrams[0].values.astype(np.float32)]) spec0img.glyph.dw = sgrams[0].x_grid().max() spec0img.glyph.dh = sgrams[0].y_grid().max() spec0cmap.low = _low_thresh() spec0.visible = True else: specsource.data = dict(sgram0=[]) spec0.visible = False def update_trace(): '''Update the static trace at the cursor time.''' trace.title.text = f'Static trace ({cursor.location:0.4f})' tidx = dfs['tngdf'].index.get_loc(cursor.location, method='nearest') row = dfs['tngdf'].iloc[tidx] tngsource.data = { 'x': [row.T1x, row.T2x, row.T3x, row.T4x], 'y': [row.T1y, row.T2y, row.T3y, row.T4y] } othsource.data = { 'x': [row.ULx, row.LLx, row.MIx, row.MMx], 'y': [row.ULy, row.LLy, row.MIy, row.MMy] } def update_traj(): '''Update the trajectories during the selected time range.''' traj.title.text = f'Trajectories ({selbox.left:0.4f} - {selbox.right:0.4f})' seldf = dfs['tngdf'].loc[(dfs['tngdf'].index >= selbox.left) & (dfs['tngdf'].index <= selbox.right)] dfs['seldf'] = seldf pts = ('T1x', 'T1y', 'T2x', 'T2y', 'T3x', 'T3y', 'T4x', 'T4y', 'ULx', 'ULy', 'LLx', 'LLy', 'MIx', 'MIy', 'MMx', 'MMy') # Create a list of line segments for each tracked element. newdata = { pt: list(np.squeeze(np.dstack((seldf[pt].iloc[:-1], seldf[pt].iloc[1:])))) \ for pt in pts } newdata['color'] = np.arange(1, len(seldf)) newdata['sec'] = seldf.index[1:] timesource.data = newdata anim_slider.start = seldf.index[0] anim_slider.end = seldf.index[-1] anim_slider.step = np.diff(newdata['sec']).mean() anim_slider.value = anim_slider.end anim_slider.disabled = False anim_btn.disabled = False lastrow = seldf.iloc[-1] lasttngtimesource.data = { 'x': [lastrow.T1x, lastrow.T2x, lastrow.T3x, lastrow.T4x], 'y': [lastrow.T1y, lastrow.T2y, lastrow.T3y, lastrow.T4y] } lastothtimesource.data = { 'x': [lastrow.ULx, lastrow.LLx, lastrow.MIx, lastrow.MMx], 'y': [lastrow.ULy, lastrow.LLy, lastrow.MIy, lastrow.MMy] } # TODO: this is a workaround until we can set x_range, y_range directly # See https://github.com/bokeh/bokeh/issues/4014 def set_limits(xstart, xend): '''Set axis limits.''' ch0.x_range.start = xstart ch0.x_range.end = xend ch0.axis[0].bounds = (xstart, xend) def update_select_widgets(clicked_x=None): '''Update widgets based on current selection. Use the clicked_x param to designate the cursor location if this function is called as the result of a Tap event. If clicked_x is None, then use the existing cursor location to set the center of the selection.''' mode = selmodebtn.labels[selmodebtn.active] if clicked_x is None and cursor.visible: x_loc = cursor.location elif clicked_x is not None: x_loc = clicked_x else: return if mode == '200ms': start = x_loc - 0.100 end = x_loc + 0.100 cursor.location = x_loc else: # 'word' or 'phone' idx = np.abs(source.data['seconds'] - x_loc).argmin() # TODO: clean up the redundancy fld = {'word': 'word', 'phone': 'phone'}[mode] label = source.data[fld][idx] indexes = nonzero_groups(source.data[fld] == label, include_any=idx) secs = source.data['seconds'][indexes] start = secs.min() end = secs.max() cursor.location = secs.mean() playselbtn.start = start playselbtn.end = end selbox.left = start selbox.right = end selbox.visible = True cursor.visible = True def spkr_select_cb(attr, old, new): '''Respond to changes in speaker multiselect.''' try: spkrs = demo[ (demo.sex.isin(sex_select.value) \ & demo.dialect_base_state.isin(state_select.value) \ & (demo.dialect_base_city.isin(city_select.value))) ].subject.unique() new_opts = [''] + [(f.value, f.label) for f in fileoptsdf[ fileoptsdf.speaker.isin(spkrs)].itertuples()] fselect.options = new_opts fselect.value = '' except NameError as e: pass # Values not set yet, so ignore def cursor_cb(e): '''Handle cursor mouse click in the waveform.''' update_select_widgets(clicked_x=e.x) update_trace() update_traj() def x_range_cb(attr, old, new): '''Handle change of x range in waveform/spectrogram.''' if attr == 'start': playvisbtn.start = new elif attr == 'end': playvisbtn.end = new def selection_cb(e): '''Handle data range selection event.''' #! TODO: handle situation in which selection is too short, i.e. len(seldf) <= 1 cursor.location = (e.geometry['x0'] + e.geometry['x1']) / 2 cursor.visible = True playselbtn.start = e.geometry['x0'] playselbtn.end = e.geometry['x1'] selbox.left = e.geometry['x0'] selbox.right = e.geometry['x1'] selbox.visible = True update_trace() update_traj() def selmode_cb(attr, old, new): '''Handle change in click selection value.''' update_select_widgets(clicked_x=None) def anim_cb(attr, old, new): '''Handle change in the animation slider.''' idx = np.argmin(np.abs(timesource.data['sec'] - new)) n = len(timesource.data['color']) active = np.arange(n - idx, n + 1) timesource.data['color'] = np.pad(active, (0, n - len(active)), constant_values=0) anim_cmap = LinearColorMapper(palette=r_Greys256, low=1, high=n + 1, low_color='white') for tag, palette in (('anim_tng', r_Reds9), ('anim_oth', r_Greens9)): for a in find(traj.references(), {'tags': tag}): a.line_color = linear_cmap('color', palette, low=1, high=n + 1, low_color='white') lasttngtimesource.data = { 'x': [ timesource.data[pt][idx][1] for pt in ('T1x', 'T2x', 'T3x', 'T4x') ], 'y': [ timesource.data[pt][idx][1] for pt in ('T1y', 'T2y', 'T3y', 'T4y') ] } lastothtimesource.data = { 'x': [ timesource.data[pt][idx][1] for pt in ('ULx', 'LLx', 'MIx', 'MMx') ], 'y': [ timesource.data[pt][idx][1] for pt in ('ULy', 'LLy', 'MIy', 'MMy') ] } def anim_btn_cb(): '''Handle click of anim_btn animate trajectories of selected audio.''' values = np.linspace(anim_slider.start, anim_slider.end, len(timesource.data['T1x'])) for v in values: anim_slider.value = v def low_thresh_cb(attr, old, new): '''Handle change in threshold slider to fade out low spectrogram values.''' params['low_thresh_power'] = new lt = _low_thresh() spec0cmap.low = lt def _low_thresh(): return sgrams[0].values.min() \ + sgrams[0].values.std()**params['low_thresh_power'] step = None rate = orig_rate = None # dfs = {} xrng = [] yrng = [] width = 1000 height = 200 cutoff = 50 order = 3 tngcolor = 'DarkRed' othcolor = 'Indigo' fselect = Select(options=[], value='') fselect.on_change('value', load_wav_cb) sex_select = MultiSelect(options=[('F', 'female'), ('M', 'male')], value=['F', 'M']) state_select = MultiSelect( options=list(demo.dialect_base_state.cat.categories), value=list(demo.dialect_base_state.cat.categories)) city_select = MultiSelect( options=list(demo.dialect_base_city.cat.categories), value=list(demo.dialect_base_city.cat.categories)) sex_select.on_change('value', spkr_select_cb) state_select.on_change('value', spkr_select_cb) city_select.on_change('value', spkr_select_cb) spkr_select_cb('', '', '') source = ColumnDataSource(data=dict(seconds=[], ch0=[])) channels = ['ch0'] playvisbtn = AudioButton(label='Play visible signal', source=source, channels=channels, width=120, disabled=True) playselbtn = AudioButton(label='Play selected signal', source=source, channels=channels, width=120, disabled=True) selmodebtn = RadioButtonGroup(labels=['200ms', 'word', 'phone'], active=1) selmodebtn.on_change('active', selmode_cb) # Instantiate and share specific select/zoom tools so that # highlighting is synchronized on all plots. boxsel = BoxSelectTool(dimensions='width') spboxsel = BoxSelectTool(dimensions='width') boxzoom = BoxZoomTool(dimensions='width') zoomin = ZoomInTool(dimensions='width') zoomout = ZoomOutTool(dimensions='width') crosshair = CrosshairTool(dimensions='height') shared_tools = [ 'xpan', boxzoom, boxsel, crosshair, zoomin, zoomout, 'reset' ] uttdiv = Div(text='') figargs = dict(tools=shared_tools, ) cursor = Span(dimension='height', line_color='red', line_dash='dashed', line_width=1) wavspec_height = 280 ch0 = figure(name='ch0', tooltips=[('time', '$x{0.0000}'), ('word', '@word'), ('phone', '@phone')], height=wavspec_height, **figargs) ch0.toolbar.logo = None ch0.line(x='seconds', y='ch0', source=source, nonselection_line_alpha=0.6) # Link pan, zoom events for plots with x_range. ch0.x_range.on_change('start', x_range_cb) ch0.x_range.on_change('end', x_range_cb) ch0.on_event(SelectionGeometry, selection_cb) ch0.on_event(Tap, cursor_cb) ch0.add_layout(cursor) wavtab = Panel(child=ch0, title='Waveform') selbox = BoxAnnotation(name='selbox', left=None, right=None, fill_color='green', fill_alpha=0.1, line_color='green', line_width=1.5, line_dash='dashed', visible=False) ch0.add_layout(selbox) sgrams = [np.ones((1, 1))] specsource = ColumnDataSource(data=dict(sgram0=[sgrams[0]])) spec0 = figure( name='spec0', x_range=ch0.x_range, # Keep times synchronized tooltips=[("time", "$x{0.0000}"), ("freq", "$y{0.0000}"), ("value", "@sgram0{0.000000}")], height=wavspec_height, **figargs) spec0.toolbar.logo = None spec0.x_range.on_change('start', x_range_cb) spec0.x_range.on_change('end', x_range_cb) spec0.on_event(SelectionGeometry, selection_cb) spec0.on_event(Tap, cursor_cb) spec0.add_layout(cursor) spec0.x_range.range_padding = spec0.y_range.range_padding = 0 spec0cmap = LogColorMapper(palette=r_Greys256, low_color=params['low_thresh_color']) low_thresh_slider = Slider(start=1.0, end=12.0, step=0.03125, value=params['low_thresh_power'], title='Spectrogram threshold') low_thresh_slider.on_change('value', low_thresh_cb) spec0img = spec0.image(image='sgram0', x=0, y=0, color_mapper=spec0cmap, level='image', source=specsource) spec0.grid.grid_line_width = 0.0 spec0.add_layout(selbox) sgramtab = Panel(child=spec0, title='Spectrogram') tngsource = ColumnDataSource(data={'x': [], 'y': []}) othsource = ColumnDataSource(data={'x': [], 'y': []}) timesource = ColumnDataSource({ 'T1x': [], 'T1y': [], 'T2x': [], 'T2y': [], 'T3x': [], 'T3y': [], 'T4x': [], 'T4y': [], 'ULx': [], 'ULy': [], 'LLx': [], 'LLy': [], 'MIx': [], 'MIy': [], 'MMx': [], 'MMy': [], 'color': [], 'sec': [] }) lasttngtimesource = ColumnDataSource(data={'x': [], 'y': []}) lastothtimesource = ColumnDataSource(data={'x': [], 'y': []}) palsource = ColumnDataSource(pd.DataFrame({'x': [], 'y': []})) phasource = ColumnDataSource(pd.DataFrame({'x': [], 'y': []})) trace = figure(width=500, height=300, title='Static trace', x_range=(-100.0, 25.0), y_range=(-37.650, 37.650), tools=[], tags=['xray', 'static_fig']) trace.toolbar.logo = None trace.circle('x', 'y', source=tngsource, size=3, color=tngcolor, tags=['update_xray']) trace.circle('x', 'y', source=othsource, size=3, color=othcolor, tags=['update_xray']) trace.line('x', 'y', source=tngsource, color=tngcolor, tags=['update_xray']) trace.line('x', 'y', source=palsource, color='black') trace.line('x', 'y', source=phasource, color='black') traj = figure(width=500, height=300, title='Trajectories', x_range=(-100.0, 25.0), y_range=(-37.650, 37.650), tools=[], tags=['xray', 'trajectory_fig']) traj.toolbar.logo = None traj.multi_line('T1x', 'T1y', source=timesource, tags=['anim_tng']) traj.multi_line('T2x', 'T2y', source=timesource, tags=['anim_tng']) traj.multi_line('T3x', 'T3y', source=timesource, tags=['anim_tng']) traj.multi_line('T4x', 'T4y', source=timesource, tags=['anim_tng']) traj.multi_line('ULx', 'ULy', source=timesource, tags=['anim_oth']) traj.multi_line('LLx', 'LLy', source=timesource, tags=['anim_oth']) traj.multi_line('MIx', 'MIy', source=timesource, tags=['anim_oth']) traj.multi_line('MMx', 'MMy', source=timesource, tags=['anim_oth']) traj.circle('x', 'y', source=lasttngtimesource, color=tngcolor) traj.circle('x', 'y', source=lastothtimesource, color=othcolor) traj.line('x', 'y', source=lasttngtimesource, color='lightgray') traj.line('x', 'y', source=palsource, color='black') traj.line('x', 'y', source=phasource, color='black') anim_slider = Slider(start=0, end=100, step=1, value=0, width=240, format='0.000f', title='Selected trajectory', orientation='horizontal', disabled=True) anim_slider.on_change('value', anim_cb) anim_btn = Button(label='Animate', width=120, disabled=True) anim_btn.on_click(anim_btn_cb) audtabs = Tabs(tabs=[wavtab, sgramtab]) mainLayout = column( row(sex_select, state_select, city_select), row(fselect), row( column(uttdiv, audtabs), column( #! row(anim_slider, anim_btn), column(Div(text='Click selection mode:'), selmodebtn, low_thresh_slider), row(playvisbtn, playselbtn))), row(trace, traj), name='mainLayout') doc.add_root(mainLayout) return doc
def plot_pathway_all_levels(pathway, out_path="../../figures/pathways/", graphs_path="../../reports/pathways/", coloring=Coloring.ENTITY_TYPE, graphs=None, **kwargs): """ Plot the interaction networks generated for a single pathway at the 3 levels; genes, proteins and proteoforms and using the 3 methods of constructing the interaction network. It locates the entities in the same coordinates as their translation products. Ex. Gene, protein and proteoform in the same relative location in its own plot. :param pathway: string id for the pathway :param out_path: :param graphs_path: :param coloring: :param graphs: [list of graphs one for each level]} :param v: :return: """ name = get_pathway_name(pathway)['Name'][0] if len(name) == 0: return graphs = { config.no_sm: list(graphs[no_sm].values()), config.with_sm: list(graphs[config.with_sm].values()), config.with_unique_sm: list(graphs[config.with_unique_sm].values()) } titles = { config.no_sm: [ 'A) Genes without SM', 'B) Proteins without SM', 'C) Proteoforms without SM' ], config.with_sm: [ 'D) Proteins with SM', 'E) Proteins with SM', 'F) Proteoforms with SM' ], config.with_unique_sm: [ 'G) Proteins with unique SM', 'H) Proteins with unique SM', 'I) Proteoforms with unique SM' ] } inner_plot_size = kwargs[ 'inner_plot_size'] if 'inner_plot_size' in kwargs else 300 legend_location_all = [None, None, 'right'] plot_widths = [inner_plot_size, inner_plot_size, inner_plot_size + 160] outline_line_width = kwargs[ 'outline_line_width'] if 'outline_line_width' in kwargs else 1 node_size = kwargs['node_size'] if 'node_size' in kwargs else 2 if coloring == Coloring.ENTITY_TYPE: legend_location_all = ['top_right', 'top_right', 'top_right'] plot_widths = [inner_plot_size, inner_plot_size, inner_plot_size] toolbar_location = kwargs[ 'toolbar_location'] if 'toolbar_location' in kwargs else None pos = get_positions(graphs) figures = { method: [ plot_interaction_network( graphs[method][i], coloring=coloring, pos=pos[method][i], plot_width=plot_widths[i], plot_height=inner_plot_size, outline_line_width=outline_line_width, outline_line_color='#e5e5e5', node_size=node_size, toolbar_location=toolbar_location, title=titles[method][i], legend_location=legend_location_all[i], highlight_articulations=(kwargs['highlight_articulations'] if 'highlight_articulations' in kwargs else False), highlight_bridges=(kwargs['highlight_bridges'] if 'highlight_bridges' in kwargs else False)) for i in range(3) ] for method in config.METHODS } if kwargs["v"] if "v" in kwargs else False: import os print("In function create_graph: ", os.getcwd()) print(f"Output path is: {out_path}{pathway}_network.html") output_file = f"{out_path}{pathway}_{coloring.name}_network.html" title = f"<p style=\"font-weight:bold;text-align:left;font-size:22px;width:1800px;\">" \ f"<span style=\"color:black;\">{name} ({pathway})</span>" \ f"</p>" notes = f""" <style type="text/css"> table {{ border: 0px; }} .color_td {{ border: inset 1px black; width: 50px }} table td#SimpleEntity {{ background-color: {get_entity_color("SimpleEntity", "")}; }} table td#EntityWithAccessionedSequence {{ background-color: {get_entity_color("", "proteins")}; }} table td#IO {{ background-color: {COLOR_IO}; }} table td#CO {{ background-color: {COLOR_CO}; }} table td#RO {{ background-color: {COLOR_RO}; }} table td#C {{ background-color: {COLOR_CC}; }} </style> <table> <tr> <td id="SimpleEntity" class="color_td"></td> <td>Small molecules</td> </tr> <tr> <td id="EntityWithAccessionedSequence" class="color_td"></td> <td>Genes, Proteins, Proteoforms</td> </tr> """ # <tr> # <td id="IO" class="color_td"></td> # <td>Input -- Output</td> # </tr> # <tr> # <td id="CO" class="color_td"></td> # <td>Catalyst -- Output</td> # </tr> # <tr> # <td id="RO" class="color_td"></td> # <td>Regulator -- Output</td> # </tr> # <tr> # <td id="C" class="color_td"></td> # <td>Component -- Component</td> # </tr> notes += """ </table> """ l = layout([ [Div(text=f"{title}")], # [Div(text=notes)], figures[config.no_sm], figures[config.with_sm], figures[config.with_unique_sm] ]) show(l) print(f"Generated figure: {output_file}") return l
duration1 = Slider(title=DUR1_LABEL, value=DUR1_START, start=DUR_MIN, end=DUR1_MAX, step=1) duration2 = Slider(title=DUR2_LABEL, value=DUR2_START, start=DUR_MIN, end=DUR2_MAX, step=1) transition1 = Slider(title=TRA1_LABEL, value=TRA1_START, start=TRA_MIN, end=TRA1_MAX, step=1) transition2 = Slider(title=TRA2_LABEL, value=TRA2_START, start=TRA_MIN, end=TRA2_MAX, step=1) beta1 = Slider(title=BETA1_LABEL, value=BETA1_START, start=BETA_MIN, end=BETA1_MAX, step=BETA1_STEP) beta2 = Slider(title=BETA2_LABEL, value=BETA2_START, start=BETA_MIN, end=BETA2_MAX, step=BETA2_STEP) beta3 = Slider(title=BETA3_LABEL, value=BETA3_START, start=BETA_MIN, end=BETA3_MAX, step=BETA3_STEP) drate = Slider(title=DRATE_LABEL, value=DRATE_START, start=DRATE_MIN, end=DRATE_MAX, step=DRATE_STEP) button = Button(label="Reset", button_type="default") # text widgets intro = Div(text='', width=TEXT_WIDTH) summary = Div(text='', width=TEXT_WIDTH) stats = Div(text='', width=TEXT_WIDTH) notes = Div(text='', width=TEXT_WIDTH) # Assign widgets to the call back function # updates are on value_throtled because this is too slow for realtime updates for w in [population, iinfections, period, period_stdev, latent, duration1, duration2, transition1, transition2, beta1, beta2, beta3, drate ]: w.on_change('value_throttled', update_data) # reset button call back button.on_click(reset_data) # initial plot x = np.linspace(1, DAYS, DAYS) y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, ar_stats = get_data(x, population.value, iinfections.value, period.value, period_stdev.value, latent.value, duration1.value, duration2.value, transition1.value, transition2.value, beta1.value, beta2.value, beta3.value, DAYS, drate.value, True )
{{ plot_div|indent(8) }} {{ plot_script|indent(8) }} </body> </html> """ ) p = Paragraph(text="The divs below were configured with additional css_classes:") div1 = Div( text=""" <p> This Bokeh Div adds the style classes:<p> <pre> .custom { border-radius: 0.5em; padding: 1em; } .custom-1 { border: 3px solid #2397D8; } </pre> """ ) div1.css_classes = ["custom", "custom-1"] div2 = Div( text=""" <p> This Bokeh Div adds the style classes:<p> <pre> .custom { border-radius: 0.5em; padding: 1em;
def subobject_view(self): return Div(text='%d' % self.b.a)
def fill_data_source(deconvolution_data): p.text = "Visualizations are being produced..." img_width = deconvolution_data[0][0].shape[0] img_height = deconvolution_data[0][0].shape[1] # get original image try: images_folder = join(UPLOAD_FOLDER, user, file, 'images') image_name = listdir(images_folder)[-1] orig_img = np.array( Image.open(join(images_folder, image_name)).resize( (img_width, img_height))) except FileNotFoundError: raise FileNotFoundError( str(e) + '. No visualization input image found in the image folder') # create plot for the original image orig_img_fig = figure(title="Original Image", plot_width=250, plot_height=250, tools="reset, save, pan", x_range=Range1d(0, img_width, bounds=(0, img_width)), y_range=Range1d(0, img_height, bounds=(0, img_height)), outline_line_color="black", outline_line_width=3) orig_img_fig.add_tools(BoxZoomTool(match_aspect=True)) orig_img_fig.axis.visible = False orig_img_fig.toolbar.logo = None add_image_from_array(orig_img_fig, orig_img) layout.children.append(orig_img_fig) figures = [] # loop through deconvolution data for array, layer_name, feat_map_no in deconvolution_data: name = "{}_{}".format(layer_name, feat_map_no) title = "#{} in {}".format(feat_map_no, layer_name) fig = figure(title=title, tools="reset, save, pan", plot_width=250, plot_height=250, outline_line_color="black", outline_line_width=3, x_range=orig_img_fig.x_range, y_range=orig_img_fig.y_range) fig.add_tools(BoxZoomTool(match_aspect=True)) fig.axis.visible = False fig.toolbar.logo = None fig.min_border_left = 20 add_image_from_source(fig, deconvolution_source, array, name) figures.append(fig) # make a grid of the feature maps grid = gridplot(figures, ncols=4, toolbar_options=dict(logo=None)) layout.children.append( Div(text="<div align='center'><b>Feature Map Visualizations</b></div>", width=1000)) layout.children.append(grid) p.text = ""
def prepare_server( doc, input_data, cell_stack, cell_markers=None, default_umap_marker=None, default_cell_marker=None, ): @lru_cache() def get_data(m=None): d = input_data if m is not None: m_v = d[m] if np.issubdtype(m_v.dtype, np.number): d["marker_val_num"] = m_v else: d["marker_val_cat"] = m_v if "marker_val_num" not in d: d["marker_val_num"] = np.arange(d.shape[0]) if "marker_val_cat" not in d: d["marker_val_cat"] = np.full(d.shape[0], "a") return d @lru_cache() def get_cat_colors(n): return Colorblind[max(3, n)][:n] @lru_cache() def marker_cols(lower=False): markers = list(sorted(input_data.columns, key=lambda x: x.lower())) if lower: return {x.lower(): x for x in markers} return markers @lru_cache() def image_markers(lower=False, mapping=False): if mapping: return { y: j for j, y in sorted( ( (i, x) for i, x in enumerate(image_markers(lower=lower, mapping=False)) ), key=lambda x: x[1].lower(), ) } if lower: return [x.lower() for x in image_markers(lower=False, mapping=False)] return ( cell_markers if cell_markers is not None else [f"Marker {i + 1}" for i in range(cell_stack.shape[1])] ) input_data = input_data.copy() # Marker selection for UMAP plots ########################################################################### if default_umap_marker is None: default_umap_marker = marker_cols()[0] marker_select = Select( value=default_umap_marker, options=marker_cols(), title="Color UMAP by" ) marker_input = AutocompleteInput( completions=marker_cols() + list(marker_cols(lower=True).keys()), min_characters=1, placeholder="Search for marker", ) marker_slider = RangeSlider( start=0, end=1, value=(0, 1), step=0.1, orientation="vertical", direction="rtl" ) # Data sources ########################################################################### source = ColumnDataSource(data=get_data(None)) image_source = ColumnDataSource(data=dict(image=[], dw=[], dh=[])) # UMAP scatter plot for numeric data ########################################################################### umap_figure = figure( plot_width=800, plot_height=500, tools="pan,wheel_zoom,lasso_select,box_select,tap,reset", active_scroll="wheel_zoom", active_drag="box_select", active_tap="tap", toolbar_location="left", ) marker_mapper = linear_cmap( field_name="marker_val_num", palette=inferno(10)[:-1], low=0, high=500, high_color=None, ) umap_scatter_renderer = umap_figure.circle( "d1", "d2", size=8, source=source, fill_alpha=0.5, line_alpha=0.9, fill_color=marker_mapper, line_color=marker_mapper, selection_fill_alpha=0.8, selection_line_alpha=1, selection_line_color="black", nonselection_alpha=0.2, hover_line_color="black", ) umap_color_bar = ColorBar( color_mapper=marker_mapper["transform"], width=12, location=(0, 0) ) umap_figure.add_layout(umap_color_bar, "right") umap_figure.add_tools( HoverTool(tooltips=None, renderers=[umap_scatter_renderer], mode="mouse") ) # UMAP scatter plot for categorical data ########################################################################### umap_figure_cat = figure( plot_width=800, plot_height=500, tools="pan,wheel_zoom,lasso_select,box_select,tap,reset", active_scroll="wheel_zoom", active_drag="box_select", active_tap="tap", x_range=umap_figure.x_range, y_range=umap_figure.y_range, toolbar_location="left", ) marker_mapper_cat = factor_cmap( field_name="marker_val_cat", palette=["#000000"], factors=["a"] ) umap_figure_cat.circle( "d1", "d2", size=8, source=source, legend_field="marker_val_cat", alpha=0.7, fill_color=marker_mapper_cat, line_color=None, selection_alpha=0.9, selection_line_color="black", nonselection_alpha=0.5, ) umap_figure_cat.legend.location = "top_right" umap_figure_cat.legend.orientation = "vertical" # Cell picture plot ########################################################################### default_cell_marker = ( 0 if default_cell_marker is None else image_markers(mapping=True)[default_cell_marker] ) cell_markers_select = Select( value=str(default_cell_marker), options=list((str(i), x) for x, i in image_markers(mapping=True).items()), title="Marker cell image", ) cell_marker_input = AutocompleteInput( completions=list(image_markers()) + list(image_markers(lower=True)), min_characters=1, placeholder="Search for marker", ) cell_slider = RangeSlider( start=0, end=1, value=(0, 1), orientation="vertical", direction="rtl" ) metric_select = RadioButtonGroup(active=0, labels=CELL_IMAGE_METRICS[0]) stats = PreText(text="", width=100) cell_mapper = bokeh.models.mappers.LinearColorMapper( viridis(20), low=0, high=1000, high_color=None ) cell_color_bar = ColorBar(color_mapper=cell_mapper, width=12, location=(0, 0)) cell_figure = figure( plot_width=450, plot_height=350, tools="pan,wheel_zoom,reset", toolbar_location="left", ) cell_image = cell_figure.image( image="image", color_mapper=cell_mapper, x=0, y=0, dw="dw", dh="dh", source=image_source, ) cell_figure.add_layout(cell_color_bar, "right") # Edit data of selected cells ########################################################################### edit_selection_col = TextInput(title="Column") edit_selection_val = TextInput(title="Value") edit_selection_submit = Button( label="Submit change", button_type="primary", align=("start", "end") ) edit_selecton_log = PreText(text="") download_button = Button( label="Download cell data", button_type="success", align=("start", "end") ) download_button.js_on_click(CustomJS(args=dict(source=source), code=DOWNLOAD_JS)) # Callbacks for buttons and widgets ########################################################################### def marker_change(attrname, old, new): update() def cell_slider_change(attrname, old, new): cell_mapper.low = new[0] cell_mapper.high = new[1] def marker_slider_change(attrname, old, new): marker_mapper["transform"].low = new[0] marker_mapper["transform"].high = new[1] def update(update_range=True): m = marker_select.value d = get_data(m) source.data = d numeric_marker = np.issubdtype(d[m].dtype, np.number) if not numeric_marker: levels = list(sorted(set(d["marker_val_cat"]))) marker_mapper_cat["transform"].palette = get_cat_colors(len(levels)) marker_mapper_cat["transform"].factors = levels elif update_range and numeric_marker: marker_max = round_signif(d["marker_val_num"].max()) marker_min = round_signif(d["marker_val_num"].min()) marker_slider.start = marker_min marker_slider.end = marker_max marker_slider.step = round_signif((marker_max - marker_min) / 50) marker_slider.value = tuple( map(round_signif, np.percentile(d["marker_val_num"], [5, 95])) ) umap_figure.visible = numeric_marker umap_figure_cat.visible = not numeric_marker marker_slider.visible = numeric_marker def selection_change(attrname, old, new): m = marker_select.value data = get_data(m) selected = source.selected.indices if not selected: return data = data.iloc[selected, :] mean_image = CELL_IMAGE_METRICS[1][metric_select.active]( cell_stack[selected, int(cell_markers_select.value), :, :], axis=0 ) image_source.data = { "image": [mean_image], "dw": [cell_stack.shape[1]], "dh": [cell_stack.shape[2]], } image_extr = round_signif(mean_image.min()), round_signif(mean_image.max()) cell_slider.start = image_extr[0] cell_slider.end = image_extr[1] cell_slider.step = round_signif((image_extr[1] - image_extr[0]) / 50) cell_slider.value = image_extr stats.text = "n cells: " + str(len(selected)) def mark_selection(): get_data.cache_clear() col = edit_selection_col.value if col is None or col == "": return if col not in input_data: input_data[col] = np.full(input_data.shape[0], "NA") col_type = input_data[col].dtype idx = source.selected.indices try: val = np.full(len(idx), edit_selection_val.value).astype(col_type) input_data.loc[input_data.index[idx], col] = val except Exception as e: edit_selecton_log.text = ( f'Failed to edit cells. Exception: "{e}"\n' + edit_selecton_log.text ) else: edit_selecton_log.text = ( f'Edited {len(source.selected.indices)} cells. {col}="{edit_selection_val.value}"\n' + edit_selecton_log.text ) update(update_range=False) old_marker_cols = set(marker_cols()) marker_cols.cache_clear() if old_marker_cols != set(marker_cols()): marker_select.options = marker_cols() marker_input.completions = marker_cols() + list( marker_cols(lower=True).keys() ) def autocomplete_change(attrname, old, new): if new not in marker_cols(): try: new = marker_cols(lower=True)[new] except KeyError: return marker_select.value = new marker_input.value = None def autocomplete_cell_change(attrname, old, new): try: idx = image_markers(mapping=True)[new] except KeyError: try: idx = image_markers(lower=True, mapping=True)[new] except KeyError: return cell_markers_select.value = str(idx) cell_marker_input.value = None source.selected.on_change("indices", selection_change) marker_select.on_change("value", marker_change) marker_slider.on_change("value", marker_slider_change) cell_slider.on_change("value", cell_slider_change) metric_select.on_change("active", selection_change) cell_markers_select.on_change("value", selection_change) edit_selection_submit.on_click(mark_selection) marker_input.on_change("value", autocomplete_change) cell_marker_input.on_change("value", autocomplete_cell_change) # set up layout layout = column( row( column( marker_select, marker_input, row(umap_figure, marker_slider), umap_figure_cat, ), column( cell_markers_select, cell_marker_input, metric_select, row(cell_figure, cell_slider), stats, ), ), Div(text="Change data for selected cells"), row( edit_selection_col, edit_selection_val, edit_selection_submit, download_button, ), edit_selecton_log, ) # initialize update() doc.add_root(layout) doc.title = "UMAP projection"
from numpy.random import random from sklearn.utils import resample from sklearn.neural_network import MLPClassifier from sklearn.preprocessing import StandardScaler from sklearn import tree from bokeh.layouts import column, row # from bokeh.charts import Bar axis_map = {"gini": "gini", "entropy": "entropy"} desc = Div(text="""<h1>An Interactive Explorer for Churn Data</h1> <p> The model allows user to work on random forest machine learning model where the user can change model's hyperparameter and select features to drop. The user can also change the test size. Based on the parameters user can see the changes in the graph in realtime </p> <p> Prepared by <b>Rajat Kabra</b>.<br/> Presented to <b>Prof. Kevin Smith</b>.<br/> Under <b>Assignment 4 of CS 235</b>.</p> <br/>""") df = pd.read_csv('C:\\Users\\rajat\\Desktop\\Master project\\churn.csv', names=[ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o' ]) div = Div( text= """Your <a href="https://en.wikipedia.org/wiki/HTML">HTML</a>-supported text is initialized with the <b>text</b> argument. The
def create_plot(): #Data data = mid_stat.copy() #Borough boro_val = select1.value boros = [ 'No Preference', 'Manhattan', 'Bronx', 'Brooklyn', 'Queens', 'Staten Island' ] if boro_val != boros[0]: data = data[data['borough'] == boro_val] #Mean Scores math_range = slider21.value ela_range = slider22.value data = data[(data['mean_score_math'] >= math_range[0]) & (data['mean_score_math'] <= math_range[1])] data = data[(data['mean_score_ela'] >= ela_range[0]) & (data['mean_score_ela'] <= ela_range[1])] #Total Enrollment enroll_range = slider3.value data = data[(data['total_enrollment'] >= enroll_range[0]) & (data['total_enrollment'] <= enroll_range[1])] #Class size class_range = slider4.value data = data[(data['pupil_teacher_ratio'] >= class_range[0]) & (data['pupil_teacher_ratio'] <= class_range[1])] #Sports s = select51.value sports = [ 'No Preference', 'Dance and Fitness', 'Outdoor', 'Water Sports ', 'Martial Arts ', 'Racquet Sports', 'Ball Teamsports' ] if s == sports[1]: data = data[data['sports'].str.lower().str.contains( 'salsa|zumba|step|weight|yoga|step|dance|fitness|cheer|gym')] elif s == sports[2]: data = data[data['sports'].str.lower().str.contains( 'track|run|board|climb')] elif s == sports[3]: data = data[data['sports'].str.lower().str.contains('row|swim')] elif s == sports[4]: data = data[data['sports'].str.lower().str.contains( 'martial|karate|wrest|judo')] elif s == sports[5]: data = data[data['sports'].str.lower().str.contains( 'tennis|squash|ping')] elif s == sports[6]: data = data[data['sports'].str.lower().str.contains( 'lacrosse|ball|rugby|soccer|frisbee')] #Electives e = select52.value elect = ['No Preference', 'Technology', 'Creativity', 'Society'] if e == elect[1]: data = data[data['electives'].str.lower().str.contains( 'tech|coding|computer|web|movie|program|stem')] elif e == elect[2]: data = data[data['electives'].str.lower().str.contains( 'guitar|band|vocal|music|drama|instrument|danc|art|theat|writ|choir' )] elif e == elect[3]: data = data[data['electives'].str.lower().str.contains( 'language|cult|social|leader|spanish')] #Cross off offer_idx = checkbox52.active offer = ['uniform', 'extendedday', 'summersession', 'weekendprogram'] offer_choice = [offer[idx] for idx in offer_idx] for off in offer_choice: data = data[data[off] == True] #Gender male_range = slider61.value female_range = slider62.value data = data[(data['male_rate'] >= male_range[0]) & (data['male_rate'] <= male_range[1])] data = data[(data['female_rate'] >= female_range[0]) & (data['female_rate'] <= female_range[1])] #Etnicities div_range = slider7.value data = data[(data['diversity_index'] >= div_range[0]) & (data['diversity_index'] <= div_range[1])] #Rental rent_idx = radio_button81.active if rent_idx == 1: data = data[data['rent_level'] <= 1] elif rent_idx == 2: data = data[data['rent_level'] <= 2] elif rent_idx == 3: data = data[data['rent_level'] >= 3] #Crime crime_idx = radio_button82.active if crime_idx == 1: data = data[data['crime_rate'] < 30] elif crime_idx == 2: data = data[(data['crime_rate'] >= 30) & (data['crime_rate'] < 60)] elif crime_idx == 3: data = data[data['crime_rate'] > 60] #Make data dict and columnsource data_dict = data.to_dict('list') source = ColumnDataSource(data_dict) w = 80 div0 = Div(text="<b> Schools matching Preferences: {} </b>".format( len(data)), style={'font-size': '150%'}) columns = [ TableColumn(field="dbn", title="School DBN", width=w), TableColumn(field="mean_score_math", title="Math Score", width=w), TableColumn(field="mean_score_ela", title="ELA Score", width=w), TableColumn(field="male_rate", title="% Male", width=w), TableColumn(field="female_rate", title="% Female", width=w), TableColumn(field="black_rate", title="% Black", width=w), TableColumn(field="white_rate", title="% White", width=w), TableColumn(field="asian_rate", title="% Asian", width=w), TableColumn(field="hispanic_rate", title="% Hispanic", width=w), TableColumn(field="avg_rent_per_sqft", title="Rent per sqft", width=w), TableColumn(field="crime_rate", title="Crime rate", width=w), TableColumn(field="sports", title="Sports", width=800), TableColumn(field="electives", title="Electives", width=800) ] data_table = DataTable(source=source, columns=columns, width=800, height=180, fit_columns=False) #Get map NY = [ -73.935242, 40.730610, ] x1, y1 = geographic_to_web_mercator(NY[0], NY[1]) tile_provider = get_provider(CARTODBPOSITRON) # range bounds supplied in web mercator coordinates w = 40000 m = figure(x_range=(x1 - w, x1 + w), y_range=(y1 - w, y1 + w), height=500, width=600, x_axis_location=None, y_axis_location=None, toolbar_location='below', tools="pan,wheel_zoom,reset", active_scroll='auto') m.add_tile(tile_provider) circles = m.circle(x="mercx", y="mercy", size=8, source=source, fill_color="midnightblue", fill_alpha=1) tooltips = [('Name', "@school_name"), ('Address', "@address")] m.add_tools(HoverTool(renderers=[circles], tooltips=tooltips)) return data_table, m, div0
def change_real_scale(shift): global realx_offset, new_data realx_offset = shift new_data = True update() file_input = FileInput(accept=".ulg, .csv") file_input.on_change('value', upload_new_data_sim) file_input2 = FileInput(accept=".ulg, .csv") file_input2.on_change('value', upload_new_data_real) intro_text = Div(text="""<H2>Sim/Real Thiel Coefficient Calculator</H2>""", width=500, height=100, align="center") sim_upload_text = Paragraph(text="Upload a simulator datalog:", width=500, height=15) real_upload_text = Paragraph(text="Upload a corresponding real-world datalog:", width=500, height=15) #checkbox_group = CheckboxGroup(labels=["x", "y", "vx","vy","lat","lon"], active=[0, 1]) sim_reverse_button = RadioButtonGroup(labels=["Sim Default", "Reversed"], active=0) sim_reverse_button.on_change('active', lambda attr, old, new: reverse_sim()) real_reverse_button = RadioButtonGroup(labels=["Real Default", "Reversed"], active=0) real_reverse_button.on_change('active', lambda attr, old, new: reverse_real())
def test_layout_constructor(panel): div1 = Div() div2 = Div() layout = panel(div1, div2) assert all(isinstance(p, Bokeh) for p in layout.objects)
def __init__(self, visualizer, fitting_parameters, domain, x, y, weights=None, min_order=1, max_order=10, xlabel='x', ylabel='y', plot_width=600, plot_height=400, plot_residuals=True, enable_user_masking=True): """ Panel for visualizing a 1-D fit, perhaps in a tab Parameters ---------- visualizer : :class:`~geminidr.interactive.fit.fit1d.Fit1DVisualizer` visualizer to associate with fitting_parameters : dict parameters for this fit domain : list of pixel coordinates Used for new fit_1D fitter x : :class:`~numpy.ndarray` X coordinate values y : :class:`~numpy.ndarray` Y coordinate values min_order : int minimum order in UI max_order : int maximum order in UI xlabel : str label for X axis ylabel : str label for Y axis plot_width : int width of plot area in pixels plot_height : int height of plot area in pixels plot_residuals : bool True if we want the lower plot showing the differential between the fit and the data grow_slider : bool True if we want the slider for modifying growth radius """ # Just to get the doc later self.visualizer = visualizer self.info_div = Div() # Make a listener to update the info panel with the RMS on a fit def update_info(info_div, f): info_div.update(text='<b>RMS:</b> {rms:.4f}'.format(rms=f.rms)) listeners = [ lambda f: update_info(self.info_div, f), ] self.fitting_parameters = fitting_parameters self.fit = InteractiveModel1D(fitting_parameters, domain, x, y, weights, listeners=listeners) fit = self.fit order_slider = interactive.build_text_slider("Order", fit.order, 1, min_order, max_order, fit, "order", fit.perform_fit, throttled=True) self.sigma_upper_slider = interactive.build_text_slider( "Sigma (Upper)", fitting_parameters["sigma_upper"], 0.01, 1, 10, fitting_parameters, "sigma_upper", self.sigma_slider_handler, throttled=True) self.sigma_lower_slider = interactive.build_text_slider( "Sigma (Lower)", fitting_parameters["sigma_lower"], 0.01, 1, 10, fitting_parameters, "sigma_lower", self.sigma_slider_handler, throttled=True) sigma_button = bm.CheckboxGroup( labels=['Sigma clip'], active=[0] if self.fit.sigma_clip else []) sigma_button.on_change('active', self.sigma_button_handler) controls_column = [ order_slider, row(self.sigma_upper_slider, sigma_button) ] controls_column.append(self.sigma_lower_slider) controls_column.append( interactive.build_text_slider("Max iterations", fitting_parameters["niter"], 1, 0, 10, fitting_parameters, "niter", fit.perform_fit)) controls_column.append( interactive.build_text_slider("Grow", fitting_parameters["grow"], 1, 0, 10, fitting_parameters, "grow", fit.perform_fit)) mask_button = bm.Button(label="Mask", align='center', button_type='primary', width_policy='min') mask_button.on_click(self.mask_button_handler) unmask_button = bm.Button(label="Unmask", align='center', button_type='primary', width_policy='min') unmask_button.on_click(self.unmask_button_handler) controller_div = Div() self.info_div = Div() if enable_user_masking: controls = column(*controls_column, row(mask_button, unmask_button), controller_div, self.info_div) else: controls = column(*controls_column, controller_div, self.info_div) # Now the figures x_range = None y_range = None try: if self.fit.data and 'x' in self.fit.data.data and len( self.fit.data.data['x']) >= 2: x_min = min(self.fit.data.data['x']) x_max = max(self.fit.data.data['x']) x_pad = (x_max - x_min) * 0.1 x_range = Range1d(x_min - x_pad, x_max + x_pad) if self.fit.data and 'y' in self.fit.data.data and len( self.fit.data.data['y']) >= 2: y_min = min(self.fit.data.data['y']) y_max = max(self.fit.data.data['y']) y_pad = (y_max - y_min) * 0.1 y_range = Range1d(y_min - y_pad, y_max + y_pad) except: pass # ok, we don't *need* ranges... if enable_user_masking: tools = "pan,wheel_zoom,box_zoom,reset,lasso_select,box_select,tap" else: tools = "pan,wheel_zoom,box_zoom,reset" p_main = figure(plot_width=plot_width, plot_height=plot_height, title='Fit', x_axis_label=xlabel, y_axis_label=ylabel, tools=tools, output_backend="webgl", x_range=x_range, y_range=y_range) p_main.height_policy = 'fixed' p_main.width_policy = 'fit' class Fit1DRegionListener(GIRegionListener): """ Wrapper class so we can just detect when a bands are finished. We don't want to do an expensive recalc as a user is dragging a band around. """ def __init__(self, fn): """ Create a band listener that just updates on `finished` Parameters ---------- fn : function function to call when band is finished. """ self.fn = fn def adjust_region(self, region_id, start, stop): pass def delete_region(self, region_id): self.fn() def finish_regions(self): self.fn() self.band_model = GIRegionModel() def update_regions(): self.fit.model.regions = self.band_model.build_regions() self.band_model.add_listener(Fit1DRegionListener(update_regions)) self.band_model.add_listener( Fit1DRegionListener(self.band_model_handler)) connect_figure_extras(p_main, None, self.band_model) Controller(p_main, None, self.band_model, controller_div, mask_handlers=(self.mask_button_handler, self.unmask_button_handler)) fig_column = [p_main] if plot_residuals: x_range = None try: if self.fit.data and 'x' in self.fit.data.data and len( self.fit.data.data['x']) >= 2: x_min = min(self.fit.data.data['x']) x_max = max(self.fit.data.data['x']) x_pad = (x_max - x_min) * 0.1 x_range = Range1d(x_min - x_pad, x_max + x_pad) except: pass # ok, we don't *need* ranges... p_resid = figure(plot_width=plot_width, plot_height=plot_height // 2, title='Fit Residuals', x_axis_label=xlabel, y_axis_label='delta' + ylabel, tools="pan,box_zoom,reset", output_backend="webgl", x_range=x_range, y_range=None) p_resid.height_policy = 'fixed' p_resid.width_policy = 'fit' connect_figure_extras(p_resid, None, self.band_model) fig_column.append(p_resid) # Initalizing this will cause the residuals to be calculated self.fit.data.data['residuals'] = np.zeros_like(self.fit.x) p_resid.scatter(x='x', y='residuals', source=self.fit.data, size=5, **self.fit.mask_rendering_kwargs()) # Initializing regions here ensures the listeners are notified of the region(s) if "regions" in fitting_parameters and fitting_parameters[ "regions"] is not None: region_tuples = cartesian_regions_to_slices( fitting_parameters["regions"]) self.band_model.load_from_tuples(region_tuples) self.scatter = p_main.scatter(x='x', y='y', source=self.fit.data, size=5, **self.fit.mask_rendering_kwargs()) self.fit.add_listener(self.model_change_handler) # TODO refactor? this is dupe from band_model_handler # hacking it in here so I can account for the initial # state of the band model (which used to be always empty) x_data = self.fit.data.data['x'] for i in np.arange(len(x_data)): if self.band_model.contains(x_data[i]): self.fit.band_mask[i] = 0 else: self.fit.band_mask[i] = 1 self.fit.perform_fit() self.line = p_main.line(x='xlinspace', y='model', source=self.fit.evaluation, line_width=3, color='black') region_editor = RegionEditor(self.band_model) fig_column.append(region_editor.get_widget()) col = column(*fig_column) col.sizing_mode = 'scale_width' self.component = row(controls, col)
def create_layout(self): hr = Div(text="<hr />", style={"width": "100%"}) return column(self.app_select, self.model_select, self.field_select, hr, self.field_info)
def bkapp(self, doc): basePath = self.basePath npyPath = self.npyPath covMapDict = self.covMapDict self.logger.debug('basePath: ' + str(basePath)) self.logger.debug('npyPath: ' + str(npyPath)) self.logger.debug('covMapDict: ' + str(covMapDict)) # Retrieving Data #----------------------------------------------------------------- # Loading in data curPath = os.getcwd() # Loading distance difference matrices self.logger.info('Reading npy matrices from: ' + str(npyPath)) npyNameList = [npyFile for npyFile in os.listdir(npyPath) \ if (npyFile[-3:] == 'npy') \ and ('Minus' in npyFile) \ and ('Scaled' not in npyFile)] self.logger.debug('npyNameList: ' + str(npyNameList)) npyList = [None] * len(npyNameList) for i, npyName in enumerate(npyNameList): npyList[i] = np.load(os.path.join(npyPath, npyName)) self.logger.debug('npyList: ' + str(npyList)) # Loading and defining dictionaries to map to and fro residue pairs to # the corresponding submatrices invCovMapDict = {str(value): key for key, value in covMapDict.items()} # Loading Covariance Matrix and helper class to split submatrices self.logger.info('Loading CovarianceMatrix.npy') covarianceMatrix = np.load(os.path.join(basePath, \ 'CovarianceMatrix.npy')) self.covSize = covarianceMatrix.shape[0] self.logger.info('Loaded CovarianceMatrix.npy') cSubmatrix = CovSubmatrix() #----------------------------------------------------------------- # Interactive Plot Tools TOOLS = 'hover,save,pan,box_zoom,reset,wheel_zoom' # Defining color values vmin = -5 vmax = 5 # New Color Map Bokeh blueRedColors = [ '#FF0000', '#FF1111', '#FF2222', '#FF3333', '#FF4444', '#FF5555', '#FF6666', '#FF7777', '#FF8888', '#FF9999', '#FFAAAA', '#FFBBBB', '#FFCCCC', '#FFDDDD', '#FFEEEE', '#FFFFFF', '#EEEEFF', '#DDDDFF', '#CCCCFF', '#BBBBFF', '#AAAAFF', '#9999FF', '#8888FF', '#7777FF', '#6666FF', '#5555FF', '#4444FF', '#3333FF', '#2222FF', '#1111FF', '#0000FF' ] # Creating list axesXMax = npyList[0].shape[0] if int(self.scale) != int(npyList[0].shape[0]): axesXMax = self.scale axesYMax = npyList[0].shape[1] if int(self.scale) != int(npyList[0].shape[1]): axesYMax = self.scale xyPairList = [None] * axesXMax * axesYMax for i in range(0, axesXMax): for j in range(0, axesYMax): xyPairList[i + j * axesXMax] = (i + 1, j + 1) self.logger.debug('xyPairList: ' + str(xyPairList)) self.logger.debug('type: xyPairList: ' + str(type(xyPairList))) # Reshaping source values in order to shift indices from starting # with 0 to starting with 1 xVals = np.transpose(xyPairList)[0] yVals = np.transpose(xyPairList)[1] covVals = npyList[0].flatten() self.logger.debug('npyList: ' + str(npyList)) self.logger.debug('covVals: ' + str(covVals)) # Checks to see if the specified scale matches axesLength = int(np.sqrt(len(covVals))) self.indexDict = None self.scaledRangeDict = None if axesLength != int(self.scale): axesLength = self.scale newMatrix, self.indexDict = self.rescaleMatrix(covVals, self.scale) covVals = newMatrix.flatten() # Creating a dictionary mapping the new indices to # strings describing the ranges of the original indices if self.indexDict is not None: self.scaledRangeDict = self.serializeIndexDict(self.indexDict) # Saving the scaled index mapping to file indexDictFilepath = os.path.join(basePath, 'scaledIndexMap.npy') np.save(indexDictFilepath, self.indexDict, allow_pickle=True) self.logger.info('Saving the scaled index mapping to: ' \ + str(indexDictFilepath)) self.logger.debug('scaledRangeDict: ' + str(self.scaledRangeDict)) # Defining fields to be displayed in hover tooltips source = ColumnDataSource( data={ 'x': xVals.flatten(), 'y': yVals.flatten(), 'covValues': covVals.flatten() }) tooltipList = [('xCoord', '@x'), ('yCoord', '@y'), ('Magnitude', '@covValues')] # Defining color map color_mapper = LinearColorMapper(palette=blueRedColors, low=vmin, high=vmax) color_bar = ColorBar(color_mapper=color_mapper, label_standoff=12, border_line_color=None, location=(0,0), ticker=BasicTicker(\ desired_num_ticks=len(blueRedColors))) # Plotting self.logger.info('Determining axis scaling.') if self.scaledRangeDict is not None: plotLabel = FactorRange( factors=[i for i in self.scaledRangeDict.values()], bounds=(0.5, len(self.scaledRangeDict.keys()) + 0.5), factor_padding=0.0, range_padding_units="percent", range_padding=0) else: plotLabel = FactorRange( factors=[str(int(i+1)) \ for i in range(axesLength)], bounds=(0.5, axesLength + 0.5)) self.logger.info('Creating initial figure') # Primary display for directly interacting with the matrices plot = figure(x_range=plotLabel, y_range=plotLabel, tools=TOOLS, toolbar_location='below', tooltips=tooltipList) plot.add_tools(EnhanceTool()) plot.xaxis.major_label_orientation = math.pi / 2 self.logger.info('Creating initial primary plot') plot.rect(x='x', y='y', width=1, height=1, source=source, fill_color={ 'field': 'covValues', 'transform': color_mapper }, line_color=None) plot.title = Title(text='Distance Difference Matrix: ' \ + npyNameList[0], \ align='center') plot.add_layout(color_bar, 'right') # Secondary display for interacting with queued covariance submatrices plot2 = figure(x_range=plotLabel, y_range=plotLabel, tools=TOOLS, toolbar_location='below', tooltips=tooltipList) plot2.add_tools(EnhanceTool()) plot2.xaxis.major_label_orientation = math.pi / 2 source2 = ColumnDataSource( data={ 'x': xVals.flatten(), 'y': yVals.flatten(), 'covValues': [0 for i in covVals.flatten()] }) self.logger.info('Creating initial secondary plot') plot2.rect(x='x', y='y', width=1, height=1, source=source2, fill_color={ 'field': 'covValues', 'transform': color_mapper }, line_color=None) plot2.title = Title(text='Queued Covariance Submatrices', align='center') plot2.add_layout(color_bar, 'right') # Creating a dictionary of distance difference matrices based off of # order they are loaded in self.logger.debug('Creating distance difference matrix mapping') matrixDict = {} for i, npy in enumerate(npyList): if i not in matrixDict.keys(): matrixDict[str(i)] = npyList[i].flatten() # Python Callbacks # ------------------------------------------------------------------ # Takes a flattened matrix and updates the plot to its values def patchMatrixValues(newMatrix, source=source): if (int(self.scale) \ != int(math.ceil(math.sqrt(newMatrix.shape[0])))): newMatrix, indexDict = self.rescaleMatrix( newMatrix, self.scale) newMatrix = newMatrix.flatten() patch_id = [i for i in range(len(source.data['covValues']))] patch = newMatrix source.patch({'covValues': list(zip(patch_id, patch))}) # Slider Callback # Changes the distance difference matrix displayed based off of the index # that the slider is set to def sliderCallback(attr, old, new): plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] f = str(new) covValues = source.data['covValues'] axesLength = math.sqrt(len(covValues)) patchMatrixValues(matrixDict[f]) plot.title.text = 'Distance Difference Matrix: ' + npyNameList[new] # Click callback for moving from distance difference matrices to # covariance submatrices def clickCallback(event): plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] start_time = time.time() axesLength = math.sqrt(len(source.data['covValues'])) xCoord = math.floor(event.x - 0.5) yCoord = math.floor(event.y - 0.5) # Only accessing covariance submatrix if the click is not along # the diagonal if ((xCoord != yCoord) and (xCoord >= 0) and (xCoord < axesLength + 1) and (yCoord >= 0) and (yCoord < axesLength + 1)): # Handles coordinates "mirrored" across the diagonal if (xCoord > yCoord): temp = xCoord xCoord = yCoord yCoord = temp coordString = '(' + str(xCoord) + ', ' + str(yCoord) + ')' # Handles submatrix access for non-scaled indices subMatrix = None if self.indexDict is None: covIndex = invCovMapDict[coordString] resPairString = '[' + coordString + ']' subMatrix = cSubmatrix.generateSubmatrix( covarianceMatrix, covMapDict, residuePairList=resPairString, allResidues=False, baseDirectory=None).flatten() self.logger.debug('Submatrix for x=' + str(xCoord) \ + ', y=' + str(yCoord) + ': ' \ + str(subMatrix)) # Handles submatrix access for scaled/mapped indices/ranges else: resPairString = '' for xIndex in self.indexDict[xCoord]: for yIndex in self.indexDict[yCoord]: if len(resPairString) > 0: resPairString += ',' resPairString += '(' + str(xIndex) \ + ', ' + str(yIndex) + ')' resPairString = '[' + resPairString + ']' if self.queueState == False: subMatrixList = cSubmatrix.generateSubmatrix( covarianceMatrix, covMapDict, residuePairList=resPairString, allResidues=False, baseDirectory=None, scale=self.scale) subMatrixArray = np.array(subMatrixList) # Multiple submatrices case, takes the average of # given submatrices if len(subMatrixArray.shape) >= 3: subMatrix = np.average(subMatrixArray, axis=0) else: subMatrix = subMatrixList else: self.logger.debug('Appending ' + str(resPairString) \ + ' to queueList') self.queueList.append([ int(xCoord + 1), int(yCoord + 1), str(resPairString) ]) toQueueDiv.text += ' (' + str(xCoord+1) + ','\ + str(yCoord+1)+'),' if self.queueState == False: patchMatrixValues(subMatrix) # Changing plot title name to reflect the covariance pair # with which the covariance submatrix is plotted in respect to xCoord += 1 yCoord += 1 displayString = '(' + str(xCoord) + ', ' + str( yCoord) + ')' plot.title.text = 'Covariance Submatrix: Residue Pair: ' \ + displayString # TODO: When speed comparisons are done, remove the time printouts print('Time to compute submatrix: ' + str(time.time() - start_time)) # Distance Difference Matrix Display Callback # Shows current distance difference matrix if not already shown def ddCallback(event): plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] f = str(slider.value) patchMatrixValues(matrixDict[f]) plot.title.text = 'Distance Difference Matrix: ' \ + npyNameList[int(f)] # Reset Button Callback # Resets display to the 0th index distance difference matrix def resetCallback(event): plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] slider.value = 0 f = str(slider.value) patchMatrixValues(matrixDict[f]) plot.title.text = 'Distance Difference Matrix: ' \ + npyNameList[0] # Forward Button Callback # Moves DD Index forward by 1 and displays DD matrix def forwardCallback(event): plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] if slider.value < len(matrixDict.keys()) - 1: slider.value = slider.value + 1 f = str(slider.value) patchMatrixValues(matrixDict[f]) plot.title.text = 'Distance Difference Matrix: ' \ + npyNameList[int(f)] # Backward Button Callback # Moves DD Index backward by 1 and displays DD matrix def backwardCallback(event): plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] if slider.value > 0: slider.value = slider.value - 1 f = str(slider.value) patchMatrixValues(matrixDict[f]) plot.title.text = 'Distance Difference Matrix: ' + npyNameList[ int(f)] # Forward Queue Callback # Moves down the queue to display the next covariance submatrix def forwardQCallback(event): plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] if ((self.curQueue is None) and (len(self.queueMatrices) == 0)): return elif ((self.curQueue is None) and (len(self.queueMatrices) >= 0)): self.curQueue = 0 patchMatrixValues(self.queueMatrices[self.curQueue], source2) plot2.title.text = 'Queued Covariance Submatrices: '\ + 'Residue Pair: ' \ + self.queueNameList[self.curQueue] indexDiv.text = 'Index: ' + str(self.curQueue) elif (self.curQueue >= len(self.queueMatrices)): return elif (self.curQueue < (len(self.queueMatrices) - 1)): self.curQueue += 1 print('Acessing curQueue: ' + str(self.curQueue)) print('len(self.queueMatrices): ' + str(len(self.queueMatrices))) patchMatrixValues(self.queueMatrices[self.curQueue], source2) plot2.title.text = 'Queued Covariance Submatrices: '\ + 'Residue Pair: ' \ + self.queueNameList[self.curQueue] indexDiv.text = 'Index: ' + str(self.curQueue) # Backward Queue Callback # Moves up the queue to display the previous covariance submatrix def backwardQCallback(event): plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] plot.x_range.factors = [ str(i) for i in self.scaledRangeDict.values() ] if ((self.curQueue is None) and (len(self.queueMatrices) == 0)): return elif ((self.curQueue is None) and (len(self.queueMatrices) >= 0)): self.curQueue = 0 patchMatrixValues(self.queueMatrices[self.curQueue], source2) plot2.title.text = 'Queued Covariance Submatrices: '\ + 'Residue Pair: ' \ + self.queueNameList[self.curQueue] indexDiv.text = 'Index: ' + str(self.curQueue) elif (self.curQueue >= len(self.queueMatrices)): return elif (self.curQueue > 0): self.curQueue -= 1 self.logger.debug('Accessing curQueue: ' + str(self.curQueue)) self.logger.debug('len(self.queueMatrices): ' \ + str(len(self.queueMatrices))) patchMatrixValues(self.queueMatrices[self.curQueue], source2) plot2.title.text = 'Queued Covariance Submatrices: '\ + 'Residue Pair: ' \ + self.queueNameList[self.curQueue] indexDiv.text = 'Index: ' + str(self.curQueue) # Queue Button Callback # Toggles queueing mode for residue pairs/ranges def queueCallback(event): # Turning on queuing if self.queueState == False: self.queueState = True toQueueDiv.text = 'Queued Covariance Submatrices:' statusDiv.text = 'Status: Queuing residue pairs' # Turning off queuing and then patching the covariance submatrices # to secondary plot else: self.queueState = False qList = self.queueList self.queueList = [] # TODO: Bokeh doesn't update display until after loop runs statusDiv.text = 'Status: Computing covariance submatrices' for matrixPak in qList: xCoord = int(matrixPak[0]) yCoord = int(matrixPak[1]) resPairString = str(matrixPak[2]) subMatrixArray = np.array( cSubmatrix.generateSubmatrix( covarianceMatrix, covMapDict, residuePairList=resPairString, allResidues=False, baseDirectory=None, scale=self.scale)) # Multiple submatrices case, takes the average of # given submatrices if len(subMatrixArray.shape) >= 3: subMatrix = np.average(subMatrixArray, axis=0) else: subMatrix = subMatrixList self.queueMatrices.append(subMatrix) patchMatrixValues(subMatrix, source2) # Changing plot title name to reflect the covariance pair # with which the covariance submatrix is plotted in respect # to xCoord += 1 yCoord += 1 displayString = '(' + str(xCoord) + ', ' + str( yCoord) + ')' self.queueNameList.append(displayString) plot2.title.text = 'Queued Covariance Submatrix: ' \ + 'Residue Pair: ' \ + displayString computedDiv.text = 'Computed Submatrices: ' \ + str(sorted(set(self.queueNameList))) totalNumberDiv.text = '/' + str(len(self.queueMatrices)) statusDiv.text = 'Status: Submatrix computation complete. Idling' # "Enhances" the selected region by taking the range of residues and # redisplays the plot so it shows only this range of residues at the # given resolution def zoomSelectCallback(event, matrixType="dd"): geometry = event.geometry f = str(slider.value) # Retrieving the boundaries of the rectangular selection # The -0.5 offset accounts for the offset of each square from # the original axis x0 = math.floor(geometry['x0'] - 0.5) x1 = math.floor(geometry['x1'] - 0.5) y0 = math.floor(geometry['y0'] - 0.5) y1 = math.floor(geometry['y1'] - 0.5) # Retrieving the boundaries of the current matrix # (in terms of currently displayed coordinates) sourceDF = source.to_df() xi = min(sourceDF['x']) xf = max(sourceDF['x']) yi = min(sourceDF['y']) yf = max(sourceDF['y']) width = x1 - x0 height = y1 - y0 # Use these values to get information about what scale # the matrix is and is going to be # self.scale # self.covSize -> need to find size for distance difference # matrices and make a separate case for them? # Also need to figure out how to deal with asymmetric boundaries # where width/height are not equal # binSize - the number of units in a given bin axesSize = int(math.sqrt(len(list(matrixDict.values())[0]))) if ((matrixType == "dd") or (matrixType is None)): matrix = matrixDict[str(slider.value)].reshape( axesSize, axesSize) elif (matrixType == "covMatrix"): indexDiv = int(self.curQueue) matrix = self.queueMatrices[indexDiv].reshape( axesSize, axesSize) binSize = int(math.ceil(axesSize / self.scale)) if ((x0 + max(width, height)) <= axesSize / binSize): xUpperBound = x0 + max(width, height) xLowerBound = x0 else: if ((x1 - max(width, height)) >= 0): xUpperBound = x1 xLowerBound = x1 - max(width, height) else: xUpperBound = int(axesSize / binSize) xLowerBound = int(axesSize / binSize - x1) if ((y0 + max(width, height)) <= axesSize / binSize): yUpperBound = y0 + max(width, height) yLowerBound = y0 else: if ((y1 - max(width, height)) >= 0): yUpperBound = y1 yLowerBound = y1 - max(width, height) else: yUpperBound = int(axesSize / binSize) yLowerBound = int(axesSize / binSize - y1) if ((xUpperBound - xLowerBound) > (yUpperBound - yLowerBound)): yUpperBound = xUpperBound yLowerBound = xLowerBound if ((xUpperBound - xLowerBound) < (yUpperBound - yLowerBound)): xUpperBound = yUpperBound xLowerBound = yLowerBound zoomedMatrix = matrix[xLowerBound * binSize:xUpperBound * binSize, yLowerBound * binSize:yUpperBound * binSize] # Modifying axes labels to reflect the zoomedMatrix # Parsing the boundaries to determine the raw index range xIndexMax = int(self.scaledRangeDict[xUpperBound].split('-')[1]) xIndexMin = int(self.scaledRangeDict[xLowerBound].split('-')[0]) yIndexMax = int(self.scaledRangeDict[yUpperBound].split('-')[1]) yIndexMin = int(self.scaledRangeDict[yLowerBound].split('-')[0]) # Partitioning the elements into self.scale number of bins numElements = xIndexMax - xIndexMin xIndexDict = self.partitionIndices(numElements, self.scale, offset=xIndexMin) yIndexDict = self.partitionIndices(numElements, self.scale, offset=yIndexMin) xRangeDict = self.serializeIndexDict(xIndexDict) yRangeDict = self.serializeIndexDict(yIndexDict) plot.x_range.factors = [i for i in xRangeDict.values()] plot.y_range.factors = [i for i in yRangeDict.values()] zoomedMatrix = zoomedMatrix.flatten() patchMatrixValues(zoomedMatrix, source) # ------------------------------------------------------------------ # Creating buttons and linking them to their corresponding callbacks # Buttons to navigate distance difference matrices buttonBack = Button(label="Back", button_type="success") buttonBack.on_event(ButtonClick, backwardCallback) buttonDD = Button(label="Show Distance Difference", button_type="success") buttonDD.on_event(ButtonClick, ddCallback) buttonForward = Button(label="Forward", button_type="success") buttonForward.on_event(ButtonClick, forwardCallback) buttonBar = row(buttonBack, buttonDD, buttonForward) buttonReset = Button(label="Reset", button_type="success") buttonReset.on_event(ButtonClick, resetCallback) # Slider to also navigate distance difference matrices slider = Slider(start=0, end=len(npyList) - 1, value=0, step=1, title="index") slider.on_change('value', sliderCallback) # Zoom button for distance difference matrices/non-queued # covariance submatrices plot.on_event(SelectionGeometry, zoomSelectCallback) plot2.on_event(SelectionGeometry, zoomSelectCallback) # Creating a layout from plot elements self.queueList = [] self.queueState = False self.curQueue = None self.queueMatrices = [] self.queueNameList = [] plot.on_event('tap', clickCallback) # Queue Buttons queueButton = Button(label="Queue", button_type="success") queueButton.on_event(ButtonClick, queueCallback) qBar = row(queueButton) # Buttons to navigate queued covariance submatrices qButtonBack = Button(label="Back", button_type="success") qButtonBack.on_event(ButtonClick, backwardQCallback) qButtonForward = Button(label="Forward", button_type="success") qButtonForward.on_event(ButtonClick, forwardQCallback) qNavBar = row(qButtonBack, qButtonForward) # Div Widgets to show which submatrix is displayed indexDiv = Div(text="""Index: N/A""", \ width=70, height=25) totalNumberDiv = Div(text="""/0""",\ width=100, height=25) indexDivBar = row(indexDiv, totalNumberDiv) # Div Widget to show which residue pairs are queued toQueueDiv = Div(text="""Queued Covariance Submatrices:""", \ width=600, height=50) # Div Widget to show which residue pairs are computed computedDiv = Div(text="""Computed Submatrices:""", \ width=600, height=50) # Div Widget to show statusDiv = Div(text="""Status: Nothing Queued""", \ width=600, height=25) testTitle = Title(text='Test Title', align='center') layout = row( column(plot, qBar, buttonBar, slider, buttonReset), column(plot2, qNavBar, statusDiv, indexDivBar, toQueueDiv, computedDiv)) # Adding the plot to the server's document server_doc = doc server_doc.add_root(layout) server_doc.title = "Distance Difference App"