def interactive_figure(self): """Add interactivity, ie. the option to show/hide lines to the figure.""" lines = self.plot_figure() # Generates a list of lines labels = [line for line in lines.keys()] # Prepare a list of labels for the tickboxes lineNames = ['l'+str(x) for x in range(len(lines))] # Prepare a list of names for the lines lines = {k: v for k, v in zip(lineNames, lines.values())} # Create a dictionary {name: line} activeL = list(range(len(lines))) # List of all line index to mark them as active in CheckboxGroup JScode = [self._visible_line_JS(k) for k in lines] # Generate JavaScript for each line JScode = '\n'.join(JScode) # From a list to a single string with open(osjoin(getcwd(), 'mLearning', 'JScodeAllLines.js'), 'r') as fileJS: buttonJS = fileJS.read() # Read JavaScript code from a file to toggle the visibility of all lines # with open(osjoin(getcwd(), 'mLearning', 'JScode.js'), 'w+') as codeFile: # codeFile.write(JScode) # Write whole CustomJS to a file for debugging purposes callback = CustomJS(code=JScode, args={}) # Args will be added once checkbox and button are added to lines checkbox = CheckboxGroup(labels=labels, active=activeL, # Labels to be ticked from the beginning callback=callback, name='checkbox') # JavaScript var name buttonCallback = CustomJS(code=buttonJS, args={}) # Same as for callback button = Button(label="Select/Unselect All", # Button HTML text button_type="default", callback=buttonCallback, name='button') # JavaScript var name lines['checkbox'], lines['button'] = checkbox, button # Adding widget to lines callback.args, buttonCallback.args = lines, lines # And then lines to callback layout = row(self.fig, widgetbox(children=[button, checkbox], width=200)) # One row, two columns logging.debug('Interaction implemented') return layout
def create(cls): """One-time creation of app's objects. This function is called once, and is responsible for creating all objects (plots, datasources, etc) """ obj = cls() obj.source = ColumnDataSource(data={'im': [im], 'xs': [xs[0]], 'ys': [ys[0]], 'w': [xs[-1] - xs[0]], 'h': [ys[-1] - ys[0]]}) obj.text = TextInput(title="title", name='title', value='wave') print(obj.text.__dict__) c = CustomJS() code="""console.log('x: '+((cb_data['geometry']['x1']+ cb_data['geometry']['x0'])/2) + ', y: '+((cb_data['geometry']['y1'] +cb_data['geometry']['y0'])/2))""" c.code = code + """;document.getElementById("{0}").value='new'; console.log(document.getElementById("{0}"))""".format(obj.text._id) # Generate a figure container plot = figure(x_range=(-2, 1), y_range=(-1, 1), tools=[BoxSelectTool(callback=c)], plot_width=450, plot_height=300, toolbar_location=None) # Plot the line by the x,y values in the source property plot.image("im", 'xs', 'ys', 'w', 'h', source=obj.source, palette="Spectral11", name='im') obj.plot = plot obj.children.append(obj.text) obj.children.append(obj.plot) return obj
def make_interactive(plot): plot = add_legend(plot) for year in years: fertility = fertility_df[year] fertility.name = 'fertility' life = life_expectancy_df[year] life.name = 'life' population = population_df_size[year] population.name = 'population' new_df = pd.concat([fertility, life, population, region_color], axis=1) sources['_' + str(year)] = ColumnDataSource(new_df) dictionary_of_sources = dict(zip([x for x in years], ['_%s' % x for x in years])) js_source_array = str(dictionary_of_sources).replace("'", "") # Add the slider code = """ var year = slider.get('value'), sources = %s, new_source_data = sources[year].get('data'); renderer_source.set('data', new_source_data); renderer_source.trigger('change'); text_source.set('data', {'year': [String(year)]}); text_source.trigger('change'); """ % js_source_array callback = CustomJS(args=sources, code=code) slider = Slider(start=years[0], end=years[-1], value=1, step=1, title="Year", callback=callback) callback.args["slider"] = slider callback.args["renderer_source"] = renderer_source callback.args["text_source"] = text_source return vplot(plot, slider)
def createMap(data, selectorColumn='MetricName'): # unique names ops = list(data[selectorColumn].unique()) # data msk = data[selectorColumn] == ops[0] source = ColumnDataSource(data=dict(lat=data['Latitude'][msk], lon=data['Longitude'][msk], disp=data['DisplayName'][msk], metric=data['MetricName'][msk], name=data['OrganisationName'][msk], value=data['Value'][msk])) all = {} for o in ops: msk = data[selectorColumn] == o all[o] = dict(lat=data['Latitude'][msk], lon=data['Longitude'][msk], disp=data['DisplayName'][msk], metric=data['MetricName'][msk], name=data['OrganisationName'][msk], value=data['Value'][msk]) all = ColumnDataSource(all) # create figure bk.output_file("MetricsMap.html", mode="cdn") fig = GMapPlot(plot_width=800, plot_height=700, logo=None, x_range=Range1d(), y_range=Range1d(), map_options=GMapOptions(lat=53.4808, lng=-1.2426, zoom=7), api_key='AIzaSyBQH3HGn6tpIrGxekGGRAVh-hISYAPsM78') fig.map_options.map_type = "roadmap" fig.title.text = "Performance Metrics" # hovering information hover = HoverTool(tooltips=[("Name", "@name"), ("Metrics", "@metric"), ("Value", "@value")]) # add tools fig.add_tools(PanTool(), BoxZoomTool(), WheelZoomTool(), hover) # add data circle = Circle(x="lon", y="lat", size=5, fill_color="blue", fill_alpha=0.8, line_color=None) fig.add_glyph(source, circle) # create callback callback = CustomJS(args=dict(source=source), code=""" var f = cb_obj.get('value'); var d = all.get('data')[f]; source.set('data', d); source.trigger('change'); """) callback.args["source"] = source callback.args["all"] = all # Set up widgets select = Select(title="Select", value=ops[0], options=ops, callback=callback) # show the map bk.show(row(select, fig))
def test_py_callback(): slider = Slider() foo = None # fool pyflakes def cb(x=slider): foo() cb = CustomJS.from_py_func(cb) assert 'foo()' in cb.code assert cb.args['x'] is slider with raises(ValueError): # not a plot object def cb(x=4): foo() CustomJS.from_py_func(cb)
def test_py_callback(): slider = Slider() foo = None # fool pyflakes def cb(x=slider): foo() cb = CustomJS.from_py_func(cb) assert 'foo()' in cb.code assert cb.args['x'] is slider def cb(x=4): foo() cb = CustomJS.from_py_func(cb) assert 'foo()' in cb.code assert cb.args['x'] is 4
def test_py_callback(): slider = Slider() foo = None # fool pyflakes def cb(x=slider): foo() cb = CustomJS.from_py_func(cb) assert cb.lang == "javascript" assert "foo()" in cb.code assert cb.args["x"] is slider with raises(ValueError): # not a plot object def cb(x=4): foo() CustomJS.from_py_func(cb)
def slider(): x = np.linspace(0, 10, 100) y = np.sin(x) source = ColumnDataSource(data=dict(x=x, y=y)) plot = figure(y_range=(-10, 10), tools="", toolbar_location=None, title="Sliders example", title_location="right") plot.line("x", "y", source=source, line_width=3, line_alpha=0.6) callback = CustomJS( args=dict(source=source), code=""" var data = source.get('data'); var A = amp.get('value') var k = freq.get('value') var phi = phase.get('value') var B = offset.get('value') x = data['x'] y = data['y'] for (i = 0; i < x.length; i++) { y[i] = B + A*Math.sin(k*x[i]+phi); } source.trigger('change'); """, ) amp_slider = Slider( start=0.1, end=10, value=1, step=0.1, title="Amplitude", callback=callback, callback_policy="mouseup" ) callback.args["amp"] = amp_slider freq_slider = Slider(start=0.1, end=10, value=1, step=0.1, title="Frequency", callback=callback) callback.args["freq"] = freq_slider phase_slider = Slider(start=0, end=6.4, value=0, step=0.1, title="Phase", callback=callback) callback.args["phase"] = phase_slider offset_slider = Slider(start=-5, end=5, value=0, step=0.1, title="Offset", callback=callback) callback.args["offset"] = offset_slider widgets = WidgetBox(amp_slider, freq_slider, phase_slider, offset_slider) return [widgets, plot]
def slider(): x = np.linspace(0, 10, 100) y = np.sin(x) source = ColumnDataSource(data=dict(x=x, y=y)) plot = figure( y_range=(-10, 10), tools='', toolbar_location=None, title="Sliders example") plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6) callback = CustomJS(args=dict(source=source), code=""" var data = source.data; var A = amp.value; var k = freq.value; var phi = phase.value; var B = offset.value; var x = data['x'] var y = data['y'] for (var i = 0; i < x.length; i++) { y[i] = B + A*Math.sin(k*x[i]+phi); } source.change.emit(); """) amp_slider = Slider(start=0.1, end=10, value=1, step=.1, title="Amplitude", callback=callback, callback_policy='mouseup') callback.args["amp"] = amp_slider freq_slider = Slider(start=0.1, end=10, value=1, step=.1, title="Frequency", callback=callback) callback.args["freq"] = freq_slider phase_slider = Slider(start=0, end=6.4, value=0, step=.1, title="Phase", callback=callback) callback.args["phase"] = phase_slider offset_slider = Slider(start=-5, end=5, value=0, step=.1, title="Offset", callback=callback) callback.args["offset"] = offset_slider widgets = column(amp_slider, freq_slider, phase_slider, offset_slider) return [widgets, plot]
def get_plot(raw, today): dfs, cats = get_sources_and_categories(raw) # Some times first_day = raw.loc[0, 'timestamp'] one_week_ago = today - datetime.timedelta(weeks=1) two_weeks_ago = today - datetime.timedelta(weeks=2) one_week_forward = today + datetime.timedelta(weeks=1) # The ranges all_range = Range1d(start=first_day, end=today) month_range = Range1d(start=two_weeks_ago, end=one_week_forward) week_range = Range1d(start=one_week_ago, end=today) # Selection indicators highlight = Quad( left='start', right='end', bottom=0, top=12, fill_color='white', line_color=COLOR_PRIMARY_CONTRAST, fill_alpha=0.2, ) lowlight = Quad( left='start', right='end', bottom=0, top=12, fill_color=COLOR_PRIMARY, line_color=COLOR_PRIMARY_CONTRAST, fill_alpha=0.5, ) # Make the complete timeline plot all_plot = _make_base_plot(dfs, cats, all_range) detail_selection_source = ColumnDataSource({ 'start': [all_range.start, month_range.end], 'end': [month_range.start, all_range.end] }) all_plot.add_glyph(detail_selection_source, lowlight) # add a second axis to all_layout plot for presentation year_ticker = DatetimeTicker(desired_num_ticks=4) year_ticks = DatetimeTickFormatter( formats={ 'years': ["%Y"], 'months': ["%Y"], 'days': ["%Y"], 'hours': ["%Y"] } ) all_plot.add_layout( DatetimeAxis(formatter=year_ticks, ticker=year_ticker, **AXIS_PROPERTIES), 'below' ) # Make the detail plot detail_plot = _make_base_plot(dfs, cats, month_range) detail_plot.add_tools(PanTool(dimensions=['width'])) detail_plot.add_tools(WheelZoomTool(dimensions=['width'])) detail_plot.add_tools(ResetTool()) week_selection_source = ColumnDataSource({'start': [week_range.start], 'end': [week_range.end]}) detail_plot.add_glyph(week_selection_source, highlight) detail_code = """ // Update the month selection box on the all_data plot when month pans var detail_selection_data = detail_selection_source.get('data'); var detail_start = cb_obj.get('frame').get('x_range').get('start'); var detail_end = cb_obj.get('frame').get('x_range').get('end'); new_detail_selection = { 'start': [detail_selection_data['start'][0], detail_end], 'end': [detail_start, detail_selection_data['end'][1]] }; detail_selection_source.set('data', new_detail_selection); // Always make sure the week highlight box on detail is visible and centered var x = moment.duration(detail_end - detail_start).asWeeks() / 2.4; var start = moment(detail_start); var week_end = start.add(x, 'weeks').format('x'); $("#one_week_before").text(start.format('ddd, DD MMM YYYY')); var newStart = start.format('YYYY-MM-DD'); var week_start = start.add(6, 'days').format('x'); $("#today").text(start.format('ddd, DD MMM YYYY')); new_week_selection = { 'start': [week_start, ], 'end': [week_end, ] }; week_selection_source.set('data', new_week_selection); var url = '/timesheet/?start=' + newStart; $("#timesheet_submit").attr('href', url).addClass("mdl-button--colored"); """ detail_xrange_callback = CustomJS(args={}, code=detail_code) detail_xrange_callback.args['detail_selection_source'] = detail_selection_source detail_xrange_callback.args['week_selection_source'] = week_selection_source detail_plot.x_range.callback = detail_xrange_callback return all_plot, detail_plot
def nb_view_patches3d(Y_r, A, C, dims, image_type='mean', Yr=None, max_projection=False, axis=0, thr=0.9, denoised_color=None, cmap='jet'): """ Interactive plotting utility for ipython notbook Parameters: ----------- Y_r: np.ndarray residual of each trace A,C,b,f: np.ndarrays outputs of matrix factorization algorithm dims: tuple of ints dimensions of movie (x, y and z) image_type: 'mean', 'max' or 'corr' image to be overlaid to neurons (average of shapes, maximum of shapes or nearest neigbor correlation of raw data) Yr: np.ndarray movie, only required if image_type=='corr' to calculate correlation image max_projection: boolean plot max projection along specified axis if True, plot layers if False axis: int (0, 1 or 2) axis along which max projection is performed or layers are shown thr: scalar between 0 and 1 Energy threshold for computing contours denoised_color: string or None color name (e.g. 'red') or hex color code (e.g. '#F0027F') cmap: string name of colormap (e.g. 'viridis') used to plot image_neurons Raise: ------ ValueError("image_type must be 'mean', 'max' or 'corr'") """ bokeh.io.curdoc().clear() # prune old orphaned models, otherwise filesize blows up d = A.shape[0] order = list(range(4)) order.insert(0, order.pop(axis)) Y_r = Y_r + C index_permut = np.reshape(np.arange(d), dims, order='F').transpose( order[:-1]).reshape(d, order='F') A = csc_matrix(A)[index_permut, :] dims = tuple(np.array(dims)[order[:3]]) d1, d2, d3 = dims colormap = cm.get_cmap(cmap) grayp = [mpl.colors.rgb2hex(m) for m in colormap(np.arange(colormap.N))] nr, T = C.shape x = np.arange(T) source = ColumnDataSource(data=dict(x=x, y=Y_r[0] / 100, y2=C[0] / 100)) source_ = ColumnDataSource(data=dict(z=Y_r / 100, z2=C / 100)) sourceN = ColumnDataSource(data=dict(N=[nr], nan=np.array([np.nan]))) if max_projection: if image_type == 'corr': tmp = [(local_correlations( Yr.reshape(dims + (-1,), order='F'))[:, ::-1]).max(i) for i in range(3)] elif image_type == 'mean': tmp = [(np.array(A.mean(axis=1)).reshape(dims, order='F')[:, ::-1]).max(i) for i in range(3)] elif image_type == 'max': tmp = [(A.max(axis=1).toarray().reshape(dims, order='F')[:, ::-1]).max(i) for i in range(3)] else: raise ValueError("image_type must be 'mean', 'max' or 'corr'") image_neurons = np.nan * \ np.ones((int(1.05 * (d1 + d2)), int(1.05 * (d1 + d3)))) image_neurons[:d2, -d3:] = tmp[0][::-1] image_neurons[:d2, :d1] = tmp[2].T[::-1] image_neurons[-d1:, -d3:] = tmp[1] offset1 = image_neurons.shape[1] - d3 offset2 = image_neurons.shape[0] - d1 proj_ = [coo_matrix([A[:, nnrr].toarray().reshape(dims, order='F').max( i).reshape(-1, order='F') for nnrr in range(A.shape[1])]) for i in range(3)] proj_ = [pproj_.T for pproj_ in proj_] coors = [get_contours(proj_[i], tmp[i].shape, thr=thr) for i in range(3)] pl.close() K = np.max([[len(cor['coordinates']) for cor in cc] for cc in coors]) cc1 = np.nan * np.zeros(np.shape(coors) + (K,)) cc2 = np.nan * np.zeros(np.shape(coors) + (K,)) for i, cor in enumerate(coors[0]): cc1[0, i, :len(cor['coordinates']) ] = cor['coordinates'][:, 0] + offset1 cc2[0, i, :len(cor['coordinates'])] = cor['coordinates'][:, 1] for i, cor in enumerate(coors[2]): cc1[1, i, :len(cor['coordinates'])] = cor['coordinates'][:, 1] cc2[1, i, :len(cor['coordinates'])] = cor['coordinates'][:, 0] for i, cor in enumerate(coors[1]): cc1[2, i, :len(cor['coordinates']) ] = cor['coordinates'][:, 0] + offset1 cc2[2, i, :len(cor['coordinates']) ] = cor['coordinates'][:, 1] + offset2 c1x = cc1[0][0] c2x = cc2[0][0] c1y = cc1[1][0] c2y = cc2[1][0] c1z = cc1[2][0] c2z = cc2[2][0] source2_ = ColumnDataSource(data=dict(cc1=cc1, cc2=cc2)) source2 = ColumnDataSource(data=dict(c1x=c1x, c1y=c1y, c1z=c1z, c2x=c2x, c2y=c2y, c2z=c2z)) callback = CustomJS(args=dict(source=source, source_=source_, sourceN=sourceN, source2=source2, source2_=source2_), code=""" var data = source.data; var data_ = source_.data; var f = cb_obj.value - 1 x = data['x'] y = data['y'] y2 = data['y2'] for (i = 0; i < x.length; i++) { y[i] = data_['z'][i+f*x.length] y2[i] = data_['z2'][i+f*x.length] } var data2_ = source2_.data; var data2 = source2.data; c1x = data2['c1x']; c2x = data2['c2x']; c1y = data2['c1y']; c2y = data2['c2y']; c1z = data2['c1z']; c2z = data2['c2z']; cc1 = data2_['cc1']; cc2 = data2_['cc2']; var N = sourceN.data['N'][0]; for (i = 0; i < c1x.length; i++) { c1x[i] = cc1[f*c1x.length + i] c2x[i] = cc2[f*c1x.length + i] } for (i = 0; i < c1x.length; i++) { c1y[i] = cc1[N*c1y.length + f*c1y.length + i] c2y[i] = cc2[N*c1y.length + f*c1y.length + i] } for (i = 0; i < c1x.length; i++) { c1z[i] = cc1[2*N*c1z.length + f*c1z.length + i] c2z[i] = cc2[2*N*c1z.length + f*c1z.length + i] } source2.change.emit(); source.change.emit(); """) else: if image_type == 'corr': image_neurons = local_correlations( Yr.reshape(dims + (-1,), order='F'))[:-1, ::-1] elif image_type == 'mean': image_neurons = np.array(A.mean(axis=1)).reshape( dims, order='F')[:, ::-1] elif image_type == 'max': image_neurons = A.max(axis=1).toarray().reshape( dims, order='F')[:, ::-1] else: raise ValueError('image_type must be mean, max or corr') cmap = bokeh.models.mappers.LinearColorMapper([mpl.colors.rgb2hex(m) for m in colormap(np.arange(colormap.N))]) cmap.high = image_neurons.max() coors = get_contours(A, dims, thr=thr) pl.close() cc1 = [[(l[:, 0]) for l in n['coordinates']] for n in coors] cc2 = [[(l[:, 1]) for l in n['coordinates']] for n in coors] length = np.ravel([list(map(len, cc)) for cc in cc1]) idx = np.cumsum(np.concatenate([[0], length[:-1]])) cc1 = np.concatenate(list(map(np.concatenate, cc1))) cc2 = np.concatenate(list(map(np.concatenate, cc2))) # pick initial layer in which first neuron lies linit = int(round(coors[0]['CoM'][0])) K = length.max() c1 = np.nan * np.zeros(K) c2 = np.nan * np.zeros(K) c1[:length[linit]] = cc1[idx[linit]:idx[linit] + length[linit]] c2[:length[linit]] = cc2[idx[linit]:idx[linit] + length[linit]] source2 = ColumnDataSource(data=dict(c1=c1, c2=c2)) source2_ = ColumnDataSource(data=dict(cc1=cc1, cc2=cc2)) source2_idx = ColumnDataSource(data=dict(idx=idx, length=length)) source3 = ColumnDataSource( data=dict(image=[image_neurons[linit]], im=[image_neurons], x=[0], y=[d2], dw=[d3], dh=[d2])) callback = CustomJS(args=dict(source=source, source_=source_, sourceN=sourceN, source2=source2, source2_=source2_, source2_idx=source2_idx), code=""" var data = source.data; var data_ = source_.data; var f = slider_neuron.value-1; var l = slider_layer.value-1; x = data['x'] y = data['y'] y2 = data['y2'] for (i = 0; i < x.length; i++) { y[i] = data_['z'][i+f*x.length] y2[i] = data_['z2'][i+f*x.length] } var data2 = source2.data; var data2_ = source2_.data; var data2_idx = source2_idx.data; var idx = data2_idx['idx']; c1 = data2['c1']; c2 = data2['c2']; var nz = idx.length / sourceN.data['N'][0]; var nan = sourceN.data['nan'][0]; for (i = 0; i < c1.length; i++) { c1[i] = nan; c2[i] = nan; } for (i = 0; i < data2_idx['length'][l+f*nz]; i++) { c1[i] = data2_['cc1'][idx[l+f*nz] + i]; c2[i] = data2_['cc2'][idx[l+f*nz] + i]; } source2.change.emit(); source.change.emit(); """) callback_layer = CustomJS(args=dict(source=source3, sourceN=sourceN, source2=source2, source2_=source2_, source2_idx=source2_idx), code=""" var f = slider_neuron.value-1; var l = slider_layer.value-1; var dh = source.data['dh'][0]; var dw = source.data['dw'][0]; var image = source.data['image'][0]; var images = source.data['im'][0]; for (var i = 0; i < x.length; i++) { for (var j = 0; j < dw; j++){ image[i*dh+j] = images[l*dh*dw + i*dh + j]; } } var data2 = source2.data; var data2_ = source2_.data; var data2_idx = source2_idx.data; var idx = data2_idx['idx'] c1 = data2['c1']; c2 = data2['c2']; var nz = idx.length / sourceN.data['N'][0]; var nan = sourceN.data['nan'][0]; for (i = 0; i < c1.length; i++) { c1[i] = nan; c2[i] = nan; } for (i = 0; i < data2_idx['length'][l+f*nz]; i++) { c1[i] = data2_['cc1'][idx[l+f*nz] + i]; c2[i] = data2_['cc2'][idx[l+f*nz] + i]; } source.change.emit() source2.change.emit(); """) plot = bpl.figure(plot_width=600, plot_height=300) plot.line('x', 'y', source=source, line_width=1, line_alpha=0.6) if denoised_color is not None: plot.line('x', 'y2', source=source, line_width=1, line_alpha=0.6, color=denoised_color) slider = bokeh.models.Slider(start=1, end=Y_r.shape[0], value=1, step=1, title="Neuron Number", callback=callback) xr = Range1d(start=0, end=image_neurons.shape[1] if max_projection else d3) yr = Range1d(start=image_neurons.shape[0] if max_projection else d2, end=0) plot1 = bpl.figure(x_range=xr, y_range=yr, plot_width=300, plot_height=300) if max_projection: plot1.image(image=[image_neurons[::-1, :]], x=0, y=image_neurons.shape[0], dw=image_neurons.shape[1], dh=image_neurons.shape[0], palette=grayp) plot1.patch('c1x', 'c2x', alpha=0.6, color='purple', line_width=2, source=source2) plot1.patch('c1y', 'c2y', alpha=0.6, color='purple', line_width=2, source=source2) plot1.patch('c1z', 'c2z', alpha=0.6, color='purple', line_width=2, source=source2) layout = bokeh.layouts.layout([[slider], [bokeh.layouts.row(plot1, plot)]], sizing_mode="scale_width") else: slider_layer = bokeh.models.Slider(start=1, end=d1, value=linit + 1, step=1, title="Layer", callback=callback_layer) callback.args['slider_neuron'] = slider callback.args['slider_layer'] = slider_layer callback_layer.args['slider_neuron'] = slider callback_layer.args['slider_layer'] = slider_layer plot1.image(image='image', x='x', y='y', dw='dw', dh='dh', color_mapper=cmap, source=source3) plot1.patch('c1', 'c2', alpha=0.6, color='purple', line_width=2, source=source2) layout = bokeh.layouts.layout([[slider], [slider_layer], [bokeh.layouts.row(plot1, plot)]], sizing_mode="scale_width") if Y_r.shape[0] == 1: layout = bokeh.layouts.row(plot1, plot) bpl.show(layout) return Y_r
def thresholding_hist(adata, key, categories, bases=['umap'], components=[1, 2], bins='auto', palette=None, legend_loc='top_right', plot_width=None, plot_height=None): """Histogram with the option to highlight categories based on thresholding binned values. Params -------- adata: AnnData object annotated data object key: str key in `adata.obs_keys()` where the data is stored categories: dict dictionary with keys corresponding to group names and values to starting boundaries `[min, max]` bases: list, optional (default: `['umap']`) bases in `adata.obsm_keys()` to visualize components: list(int); list(list(int)), optional (default: `[1, 2]`) components to use for each basis bins: int; str, optional (default: `auto`) number of bins used for initial binning or a string key used in from numpy.histogram palette: list(str), optional (default: `None`) palette to use for coloring categories legend_loc: str, default(`'top_right'`) position of the legend plot_width: int, optional (default: `None`) width of the plot plot_height: int, optional (default: `None`) height of the plot Returns -------- None """ if not isinstance(components[0], list): components = [components] if len(components) != len(bases): assert len(bases) % len(components) == 0 and len(bases) >= len(components) components = components * (len(bases) // len(components)) if not isinstance(components, np.ndarray): components = np.asarray(components) if not isinstance(bases, list): bases = [bases] palette = Set1[9] + Set2[8] + Set3[12] if palette is None else palette hist_fig = figure() _set_plot_wh(hist_fig, plot_width, plot_height) hist_fig.xaxis.axis_label = key hist_fig.yaxis.axis_label = 'normalized frequency' hist, edges = np.histogram(adata.obs[key], density=True, bins=bins) source = ColumnDataSource(data=dict(hist=hist, l_edges=edges[:-1], r_edges=edges[1:], category=['default'] * len(hist), indices=[[]] * len(hist))) df = pd.concat([pd.DataFrame(adata.obsm[f'X_{basis}'][:, comp - (basis != 'diffmap')], columns=[f'x_{basis}', f'y_{basis}']) for basis, comp in zip(bases, components)], axis=1) df['values'] = list(adata.obs[key]) df['category'] = 'default' df['visible_category'] = 'default' df['cat_stack'] = [['default']] * len(df) orig = ColumnDataSource(df) color = dict(field='category', transform=CategoricalColorMapper(palette=palette, factors=list(categories.keys()))) hist_fig.quad(source=source, top='hist', bottom=0, left='l_edges', right='r_edges', color=color, line_color="#555555", legend='category') if legend_loc is not None: hist_fig.legend.location = legend_loc emb_figs = [] for basis, comp in zip(bases, components): fig = figure(title=basis) fig.xaxis.axis_label = f'{basis}_{comp[0]}' fig.yaxis.axis_label = f'{basis}_{comp[1]}' _set_plot_wh(fig, plot_width, plot_height) fig.scatter(f'x_{basis}', f'y_{basis}', source=orig, size=10, color=color, legend='category') if legend_loc is not None: fig.legend.location = legend_loc emb_figs.append(fig) inputs, category_cbs = [], [] code_start, code_mid, code_thresh = [], [], [] args = {'source': source, 'orig': orig} for col, cat_item in zip(palette, categories.items()): cat, (start, end) = cat_item inp_min = TextInput(name='test', value=f'{start}', title=f'{cat}/min') inp_max = TextInput(name='test', value=f'{end}', title=f'{cat}/max') code_start.append(f''' var min_{cat} = parseFloat(inp_min_{cat}.value); var max_{cat} = parseFloat(inp_max_{cat}.value); ''') code_mid.append(f''' var mid_{cat} = (source.data['r_edges'][i] - source.data['l_edges'][i]) / 2; ''') code_thresh.append(f''' if (source.data['l_edges'][i] + mid_{cat} >= min_{cat} && source.data['r_edges'][i] - mid_{cat} <= max_{cat}) {{ source.data['category'][i] = '{cat}'; for (var j = 0; j < source.data['indices'][i].length; j++) {{ var ix = source.data['indices'][i][j]; orig.data['category'][ix] = '{cat}'; }} }} ''') args[f'inp_min_{cat}'] = inp_min args[f'inp_max_{cat}'] = inp_max min_ds = ColumnDataSource(dict(xs=[start] * 2)) max_ds = ColumnDataSource(dict(xs=[end] * 2)) inputs.extend([inp_min, inp_max]) code_thresh.append( ''' { source.data['category'][i] = 'default'; for (var j = 0; j < source.data['indices'][i].length; j++) { var ix = source.data['indices'][i][j]; orig.data['category'][ix] = 'default'; } } ''') callback = CustomJS(args=args, code=f''' {';'.join(code_start)} for (var i = 0; i < source.data['hist'].length; i++) {{ {';'.join(code_mid)} {' else '.join(code_thresh)} }} orig.change.emit(); source.change.emit(); ''') for input in inputs: input.js_on_change('value', callback) slider = Slider(start=1, end=100, value=len(hist), title='Bins') interactive_hist_cb = CustomJS(args={'source': source, 'orig': orig, 'bins': slider}, code=_inter_hist_js_code) slider.js_on_change('value', interactive_hist_cb, callback) show(column(row(hist_fig, column(slider, *inputs)), *emb_figs))
""" import numpy as np from bokeh.io import output_file, show from bokeh.layouts import row from bokeh.palettes import Viridis3 from bokeh.plotting import figure from bokeh.models import CheckboxGroup, CustomJS output_file("line_on_off.html", title="line_on_off.py example") p = figure() props = dict(line_width=4, line_alpha=0.7) x = np.linspace(0, 4 * np.pi, 100) l0 = p.line(x, np.sin(x), color=Viridis3[0], legend="Line 0", **props) l1 = p.line(x, 4 * np.cos(x), color=Viridis3[1], legend="Line 1", **props) l2 = p.line(x, np.tan(x), color=Viridis3[2], legend="Line 2", **props) checkbox = CheckboxGroup(labels=["Line 0", "Line 1", "Line 2"], active=[0, 1, 2], width=100) checkbox.callback = CustomJS.from_coffeescript(args=dict(l0=l0, l1=l1, l2=l2, checkbox=checkbox), code=""" l0.visible = 0 in checkbox.active; l1.visible = 1 in checkbox.active; l2.visible = 2 in checkbox.active; """) layout = row(checkbox, p) show(layout)
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"
def comnt_samp_change_button(datasets=None, position_source=None, key_mapper=None, data_source=None, comnt_obj=None): """Return a button.""" def callback_py(attr, old, new, comnt_obj=None): selected_indices = position_source.selected.indices if len(selected_indices) > 1: print('multi serie selection, no good! len(selected_position) = {}' ''.format(len(selected_indices))) return selected_key = position_source.data['KEY'][selected_indices[0]] selected_data_indices = data_source.selected.indices ds_key = key_mapper.get(selected_key) datasets[ds_key]['data']['COMNT_SAMP'].iloc[ selected_data_indices] = comnt_obj.value js_code = """ console.log('comnt_visit_change_button') // Get data from ColumnDataSource var position_data = position_source.data; var data = data_source.data; // Set variables attributes var selected_position_indices = position_source.selected.indices; if (selected_position_indices.length == 1) { var selected_water_indices = data_source.selected.indices; var selected_key = position_data['KEY'][selected_position_indices[0]]; for (var i = 0; i < selected_water_indices.length; i++) { data['COMNT_SAMP'][selected_water_indices[i]] = comnt_obj.value; } // Save changes to ColumnDataSource data_source.change.emit(); // Trigger python callback inorder to save changes to the actual datasets dummy_trigger.glyph.size = {'value': Math.random(), 'units': 'screen'}; dummy_trigger.glyph.change.emit(); } else { console.log('To many selected stations!! We can only work with one at a time', selected_indices.length) } """ # noqa: E501 dummy_figure = figure() dummy_trigger = dummy_figure.circle(x=[1], y=[2], alpha=0) dummy_trigger.glyph.on_change('size', partial(callback_py, comnt_obj=comnt_obj)) callback = CustomJS(args={ 'position_source': position_source, 'data_source': data_source, 'comnt_obj': comnt_obj, 'dummy_trigger': dummy_trigger }, code=js_code) button = Button(label="Commit sample comnt", width=30, button_type="success") button.js_on_event(ButtonClick, callback) return button
def show_hide_button_list(keyword_dict, checkbox_code, iterable, width=100, separator='-'): """ Return a number of button that check / uncheck boxes in a CheckBoxGroup based on a keyword list and the CheckBoxGroup labels - keyword_dict: an OrderedDict of groups of keywords, each group has keyword of a specific length {key1:['abc','def','ghi',...],key2:['ab','cd',...],...} - checkbox_code: callback code of the CheckBoxGroup - iterable: list of (key,value) tuples for the arguments of the CheckBoxGroup callback, must include the CheckBoxGroup itself as ('checkbox',CheckBoxGroup) - width: width of the buttons Output: - buttons that check/uncheck checkboxes in a CheckBoxGroup if they include a certain keyword in their label - button to uncheck all the checkboxes and switch all buttons to "show" - button to check all the checkboxes and switch all buttons to "hide" """ # create a button for each keyword in keyword_dict button_list = [] for keyword in list(flatten(keyword_dict)): button_list.append( Button(label='Hide ' + keyword, name=keyword, button_type='danger', width=width)) clear_button = Button(label='Clear all', width=width) # button to uncheck all checkboxes check_button = Button(label='Check all', width=width) # button to check all checkboxes # adds the buttons to the iterable list for the callback arguments new_iterable = iterable + [('button_' + button.name, button) for button in button_list] # a string of the form '[button_a,button_b,...]' for the callback codes button_str = str(['button_' + button.name for button in button_list]).replace("'", "") button_key_code = "" # code that goes over each keyword group and button status to reconstruct the label of checkboxes to be checked / unchecked show_full_code = "show_full = [];" # the array of labels with associated checkboxes that need to be checked show_full = [] it = 0 loopid = ['i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't'] for key in keyword_dict: # loop to generate the code based on the number of keyword groups button_key_code += ''' show_%s = []; for (i=0;i<show_name.length;i++){ if(show_name[i].length==%s){show_%s.push(show_name[i])}; }; ''' % (key, str(len(keyword_dict[key][0])), key) show_full_code += "for(%s=0;%s<show_%s.length;%s++){" % ( loopid[it], loopid[it], key, loopid[it]) show_full.append('show_%s[%s]' % (key, loopid[it])) it += 1 show_full_code += "show_full.push(" + ( "+'" + separator + "'+").join(show_full) + ")" + "};" * it button_key_code += show_full_code # initial code for the buttons button_switch_code = """ if (cb_obj.button_type.includes("danger")){ cb_obj.button_type = "success"; cb_obj.label = "Show "+cb_obj.name; } else { cb_obj.button_type = "danger"; cb_obj.label = "Hide "+cb_obj.name; } button_list = """ + button_str + """; """ # initial code for the "clear all" button clear_switch_code = """ button_list = """ + button_str + """; for (i=0;i<button_list.length;i++){ button_list[i].button_type = "success" button_list[i].label = "Show "+button_list[i].name } """ # initial code for the "check all" button check_switch_code = """ button_list = """ + button_str + """; for (i=0;i<button_list.length;i++){ button_list[i].button_type = "danger" button_list[i].label = "Hide "+button_list[i].name } """ button_code = button_switch_code + """ show_name = []; for(i=0;i<button_list.length;i++) { if(button_list[i].button_type.includes("danger")) {show_name.push(button_list[i].name)}; }; """ + button_key_code + """ new_active = []; for (i=0;i<show_full.length;i++){ for(j=0;j<checkbox.labels.length;j++){ if (checkbox.labels[j].includes(show_full[i])) {new_active.push(j);}; }; }; new_active.sort(); checkbox.active = new_active.slice(); """ + checkbox_code for button in button_list: button.callback = CustomJS( args={key: value for key, value in new_iterable}, code=button_code) clear_button_code = button_code.replace(button_switch_code, clear_switch_code) clear_button.callback = CustomJS( args={key: value for key, value in new_iterable}, code=clear_button_code) check_button_code = button_code.replace(button_switch_code, check_switch_code) check_button.callback = CustomJS( args={key: value for key, value in new_iterable}, code=check_button_code) return [clear_button, check_button] + button_list
from bokeh.io import output_file, show from bokeh.plotting import figure from bokeh.layouts import layout from bokeh.models import Toggle, BoxAnnotation, CustomJS # We set-up the same standard figure with two lines and now a box over top p = figure(plot_width=600, plot_height=200, tools='') visible_line = p.line([1, 2, 3], [1, 2, 1], line_color="blue") invisible_line = p.line([1, 2, 3], [2, 1, 2], line_color="pink") box = BoxAnnotation(left=1.5, right=2.5, fill_color='green', fill_alpha=0.1) p.add_layout(box) # We write JavaScript to link toggle with visible property of box and line code = '''\ object.visible = toggle.active ''' callback1 = CustomJS(code=code, args={}) toggle1 = Toggle(label="Green Box", button_type="success", callback=callback1) callback1.args = {'toggle': toggle1, 'object': box} callback2 = CustomJS(code=code, args={}) toggle2 = Toggle(label="Pink Line", button_type="success", callback=callback2) callback2.args = {'toggle': toggle2, 'object': invisible_line} output_file("styling_visible_annotation_with_interaction.html") show(layout([p], [toggle1, toggle2]))
# 'p_graph_glyphs': p_graph_glyphs, # 'p_graph': p_graph, # }, # code=callback_world_map) # taptool = p_map.select(type=TapTool) # taptool.callback = callbacktap # Explicitly initialize x range p_map.x_range = DataRange1d() # Reset on doubltap p_map.js_on_event( 'doubletap', CustomJS(args={ 'p': p_map, }, code=""" p.reset.emit() """)) """ # Map widgets ------------------------------------------------------------------------------------------------ """ # Get the callback script used for many of the widgets with open(javascript_path + 'callback_map_widgets.js', 'r') as f: callback_widgets = f.read() # Level radio buttons radio_labels = ["Play \u25B6", "Step \u23ef", "Pause \u23f8"] radioGroup_play_controls = RadioButtonGroup(labels=radio_labels, active=2, name='radioGroup_play_controls')
height=400) # each scatter glyph is associated with a name, the CheckboxGroup too iterable = [('p' + str(rend_list.index(rend)), rend) for rend in rend_list] + [('checkbox', checkbox)] # code to trigger glyph visibility with checkboxes checkbox_code = ''.join([ 'p' + str(rend_list.index(rend)) + '.visible=checkbox.active.includes(' + str(rend_list.index(rend)) + ');' for rend in rend_list ]) # CheckboxGroup callback checkbox.callback = CustomJS(args={key: value for key, value in iterable}, code=checkbox_code) # Dictionary of keyword groups for the button generating function keyword_dict = collections.OrderedDict([ ('date', sorted(column.keys())), ('window', sorted(column[date].keys())), ('ret', sorted(column[date][window].keys())) ]) # create all the buttons button_list = show_hide_button_list(keyword_dict, checkbox_code, iterable, width=120)
def plot_stack(dataset, palette="Viridis256"): """Plotting a stack of images Plotting a stack of images contained in a sidpy.Dataset. The images can be scrolled through with a slider widget. Parameters ---------- dataset: sidpy.Dataset sidpy dataset with data_type 'IMAGE_STACK' palette: bokeh palette palette is optional Returns ------- p: bokeh plot Example ------- >> import pyTEMlib >> from bokeh.plotting import figure, show, output_notebook >> output_notebook() >> p = pyTEMlib.viz(dataset) >> p.show(p) """ if not isinstance(dataset, sidpy.Dataset): raise TypeError('Need a sidpy dataset for plotting') if dataset.data_type.name != 'IMAGE_STACK': raise TypeError('Need an IMAGE_STACK for plotting a stack') stack = np.array(dataset - dataset.min()) stack = stack / stack.max() * 256 stack = np.array(stack, dtype=int) color_mapper = LinearColorMapper(palette=palette, low=0, high=256) p = figure(match_aspect=True, plot_width=600, plot_height=600) im_plot = p.image(image=[stack[0]], x=[0], y=[0], dw=[dataset.x[-1]], dh=[dataset.y[-1]], color_mapper=color_mapper) p.x_range.range_padding = 0 p.y_range.range_padding = 0 p.xaxis.axis_label = 'distance (nm)' p.yaxis.axis_label = 'distance (nm)' slider = Slider(start=0, end=stack.shape[0] - 1, value=0, step=1, title="frame") update_curve = CustomJS(args=dict(source=im_plot, slider=slider, stack=stack), code="""var f = slider.value; source.data_source.data['image'] = [stack[f]]; // necessary because we mutated source.data in-place source.data_source.change.emit(); """) slider.js_on_change('value', update_curve) return column(slider, p)
def plot_spectrum(dataset, selected_range, palette=Spectral11): """Plot spectrum""" if not isinstance(dataset, sidpy.Dataset): raise TypeError('Need a sidpy dataset for plotting') if dataset.data_type.name not in ['SPECTRUM']: raise TypeError( 'Need an sidpy.Dataset of data_type SPECTRUM for plotting a spectrum ' ) p = figure(x_axis_type="linear", plot_width=800, plot_height=400, tooltips=[("index", "$index"), ("(x,y)", "($x, $y)")], tools="pan,wheel_zoom,box_zoom,reset, hover, lasso_select") p.add_tools(BoxSelectTool(dimensions="width")) # first line is dataset spectrum = ColumnDataSource( data=dict(x=dataset.dim_0, y=np.array(dataset))) p.scatter('x', 'y', color='blue', size=1, alpha=0., source=spectrum, selection_color="firebrick", selection_alpha=0.) p.line(x='x', y='y', source=spectrum, legend_label=dataset.title, color=palette[0], line_width=2) # add other lines if available if 'add2plot' in dataset.metadata: data = dataset.metadata['add2plot'] for key, line in data.items(): p.line(dataset.dim_0.values, line['data'], legend_label=line['legend'], color=palette[key], line_width=2) p.legend.click_policy = "hide" p.xaxis.axis_label = dataset.labels[0] p.yaxis.axis_label = dataset.data_descriptor p.title.text = dataset.title my_span = Span(location=0, dimension='width', line_color='gray', line_width=1) p.add_layout(my_span) callback = CustomJS(args=dict(s1=spectrum), code=""" var inds = s1.selected.indices; if (inds.length == 0) return; var kernel = IPython.notebook.kernel; kernel.execute("selected_range = " + [inds[0], inds[inds.length-1]]);""" ) spectrum.selected.js_on_change('indices', callback) return p
def link_plot(adata, key, genes=None, bases=['umap', 'pca'], components=[1, 2], distance=2, cutoff=True, highlight_only=None, palette=None, show_legend=False, legend_loc='top_right', plot_width=None, plot_height=None): """ Display the distances of cells from currently highlighted cell. Params -------- adata: AnnData annotated data object key: str key in `adata.obs_keys()` to color the static plot genes: list(str), optional (default: `None`) list of genes in `adata.var_names`, which are used to compute the distance; if None, take all the genes bases: list(str), optional (default:`['umap', 'pca']`) list of bases to use when plotting; only the first plot is hoverable components: list(int); list(list(int)), optional (default: `[1, 2]`) list of components for each basis distance: int; str, optional (default: `2`) for integers, use p-norm, for strings, only `'dpt'` is available cutoff: bool, optional (default: `True`) if `True`, do not color cells whose distance is further away than the threshold specified by the slider highlight_only: 'str', optional (default: `None`) key in `adata.obs_keys()`, which makes highlighting work only on clusters specified by this parameter palette: matplotlib.colors.Colormap; list(str), optional (default: `None`) colormap to use, if None, use Viridis show_legend: bool, optional (default: `False`) display the legend also in the linked plot legend_loc: str, optional (default `'top_right'`) location of the legend plot_width: int, optional (default: `None`) width of the plot plot_height: int, optional (default: `None`) height of the plot Returns -------- None """ palette = cm.RdYlBu if palette is None else palette if isinstance(palette, matplotlib.colors.Colormap): palette = _cmap_to_colors(palette(range(palette.N), 1., bytes=True)) if not isinstance(components[0], list): components = [components] if len(components) != len(bases): assert len(bases) % len(components) == 0 and len(bases) >= len(components) components = components * (len(bases) // len(components)) if not isinstance(components, np.ndarray): components = np.asarray(components) if highlight_only is not None: assert highlight_only in adata.obs_keys(), f'`{highlight_only}` is not in adata.obs_keys().' genes = adata.var_names if genes is None else genes gene_subset = np.in1d(adata.var_names, genes) start_ix = str(adata.uns.get('iroot', 0)) if distance != 'dpt': dmat = distance_matrix(adata.X[:, gene_subset], adata.X[:, gene_subset], p=distance) else: if not all(gene_subset): warnings.warn('`genes` is not None, are you sure this is what you want when using `dpt` distance?') dmat = [] ad_tmp = adata.copy() ad_tmp = ad_tmp[:, gene_subset] for i in range(ad_tmp.n_obs): ad_tmp.uns['iroot'] = i sc.tl.dpt(ad_tmp) dmat.append(list(ad_tmp.obs['dpt_pseudotime'])) dmat = pd.DataFrame(dmat, columns=list(map(str, range(adata.n_obs)))) df = pd.concat([pd.DataFrame(adata.obsm[f'X_{basis}'][:, comp - (basis != 'diffmap')], columns=[f'x{i}', f'y{i}']) for i, (basis, comp) in enumerate(zip(bases, components))] + [dmat], axis=1) df['hl_color'] = np.nan df['index'] = range(len(df)) df['hl_key'] = list(adata.obs[highlight_only]) if highlight_only is not None else 0 df[key] = list(map(str, adata.obs[key])) ds = ColumnDataSource(df) mapper = linear_cmap(field_name='hl_color', palette=palette, low=df[start_ix].min(), high=df[start_ix].max()) static_fig_mapper = _create_mapper(adata, key) static_figs = [] figs, renderers = [], [] for i, basis in enumerate(bases): # linked plots fig = figure(tools='pan, reset, save, ' + ('zoom_in, zoom_out' if i == 0 else 'wheel_zoom'), title=basis, plot_width=400, plot_height=400) _set_plot_wh(fig, plot_width, plot_height) scatter = fig.scatter(f'x{i}', f'y{i}', source=ds, line_color=mapper, color=mapper, legend=('hl_key' if highlight_only is not None else key) if (show_legend and legend_loc is not None) else None, hover_color='black', size=8, line_width=8, line_alpha=0) if show_legend and legend_loc is not None: fig.legend.location = legend_loc figs.append(fig) renderers.append(scatter) # static plots fig = figure(title=basis, plot_width=400, plot_height=400) fig.scatter(f'x{i}', f'y{i}', source=ds, size=8, legend=key if legend_loc is not None else None, color={'field': key, 'transform': static_fig_mapper}) if legend_loc is not None: fig.legend.location = legend_loc static_figs.append(fig) fig = figs[0] end = dmat[~np.isinf(dmat)].max().max() if distance != 'dpt' else 1.0 slider = Slider(start=0, end=end, value=end / 2, step=end / 1000, title='Distance ' + '(dpt)' if distance == 'dpt' else f'({distance}-norm)') col_ds = ColumnDataSource(dict(value=[start_ix])) update_color_code = f''' source.data['hl_color'] = source.data[first].map( (x, i) => {{ return isNaN(x) || {'x > slider.value || ' if cutoff else ''} source.data['hl_key'][first] != source.data['hl_key'][i] ? NaN : x; }} ); ''' slider.callback = CustomJS(args={'slider': slider, 'mapper': mapper['transform'], 'source': ds, 'col': col_ds}, code=f''' mapper.high = slider.value; var first = col.data['value']; {update_color_code} source.change.emit(); ''') h_tool = HoverTool(renderers=renderers, tooltips=[], show_arrow=False) h_tool.callback = CustomJS(args=dict(source=ds, slider=slider, col=col_ds), code=f''' var indices = cb_data.index['1d'].indices; if (indices.length == 0) {{ source.data['hl_color'] = source.data['hl_color']; }} else {{ var first = indices[0]; source.data['hl_color'] = source.data[first]; {update_color_code} col.data['value'] = first; col.change.emit(); }} source.change.emit(); ''') fig.add_tools(h_tool) color_bar = ColorBar(color_mapper=mapper['transform'], width=12, location=(0,0)) fig.add_layout(color_bar, 'left') fig.add_tools(h_tool) show(column(slider, row(*static_figs), row(*figs)))
def __init__(self): widget_width = 200 # Create empty Bokeh data sources self.source_table = ColumnDataSource( data=dict(institutional_roi=[], physician_roi=[], variation=[])) self.categories = [ "Institutional ROI", "Physician", "Physician ROI", "Variation" ] self.operators = ["Add", "Delete", "Rename"] # Load ROI map self.db = DatabaseROIs() self.function_map = { 'Add Institutional ROI': self.add_institutional_roi, 'Add Physician': self.add_physician, 'Add Physician ROI': self.add_physician_roi, 'Add Variation': self.add_variation, 'Delete Institutional ROI': self.delete_institutional_roi, 'Delete Physician': self.delete_physician, 'Delete Physician ROI': self.delete_physician_roi, 'Delete Variation': self.delete_variation, 'Rename Institutional ROI': self.rename_institutional_roi, 'Rename Physician': self.rename_physician, 'Rename Physician ROI': self.rename_physician_roi, 'Rename Variation': self.rename_variation } # Selectors roi_options = self.db.get_institutional_rois() self.select_institutional_roi = Select(value=roi_options[0], options=roi_options, width=widget_width, title='All Institutional ROIs') physician_options = self.db.get_physicians() if len(physician_options) > 1: value = physician_options[1] else: value = physician_options[0] self.select_physician = Select(value=value, options=physician_options, width=widget_width, title='Physician') phys_roi_options = self.db.get_physician_rois( self.select_physician.value) self.select_physician_roi = Select(value=phys_roi_options[0], options=phys_roi_options, width=widget_width, title='Physician ROIs') variations_options = self.db.get_variations( self.select_physician.value, self.select_physician_roi.value) self.select_variation = Select(value=variations_options[0], options=variations_options, width=widget_width, title='Variations') unused_roi_options = self.db.get_unused_institutional_rois( self.select_physician.value) value = self.db.get_institutional_roi(self.select_physician.value, self.select_physician_roi.value) if value not in unused_roi_options: unused_roi_options.append(value) unused_roi_options.sort() self.select_unlinked_institutional_roi = Select( value=value, options=unused_roi_options, width=widget_width, title='Linked Institutional ROI') self.uncategorized_variations = self.get_uncategorized_variations( self.select_physician.value) try: uncat_var_options = list(self.uncategorized_variations) except: uncat_var_options = [''] uncat_var_options.sort() self.select_uncategorized_variation = Select( value=uncat_var_options[0], options=uncat_var_options, width=widget_width, title='Uncategorized Variations') ignored_variations = self.get_ignored_variations( self.select_physician.value) try: ignored_var_options = list(ignored_variations) except: ignored_var_options = [''] if not ignored_var_options: ignored_var_options = [''] else: ignored_var_options.sort() self.select_ignored_variation = Select(value=ignored_var_options[0], options=ignored_var_options, width=widget_width, title='Ignored Variations') self.div_action = Div(text="<b>No Action</b>", width=widget_width) self.input_text = TextInput(value='', title='Add Institutional ROI:', width=widget_width) # RadioButtonGroups self.category = RadioButtonGroup(labels=self.categories, active=0, width=400) self.operator = RadioButtonGroup(labels=self.operators, active=0, width=200) # Ticker calls self.select_institutional_roi.on_change( 'value', self.select_institutional_roi_change) self.select_physician.on_change('value', self.select_physician_change) self.select_physician_roi.on_change('value', self.select_physician_roi_change) self.select_variation.on_change('value', self.select_variation_change) self.category.on_change('active', self.category_change) self.operator.on_change('active', self.operator_change) self.input_text.on_change('value', self.input_text_change) self.select_unlinked_institutional_roi.on_change( 'value', self.unlinked_institutional_roi_change) self.select_uncategorized_variation.on_change( 'value', self.update_uncategorized_variation_change) # Button objects self.action_button = Button(label='Add Institutional ROI', button_type='primary', width=int(widget_width * (2. / 3))) self.reload_button_roi = Button(label='Reload Map', button_type='primary', width=widget_width - 5) self.save_button_roi = Button(label='Map Saved', button_type='primary', width=widget_width - 5) self.ignore_button_roi = Button(label='Ignore', button_type='primary', width=widget_width / 2 - 5) self.delete_uncategorized_button_roi = Button(label='Delete DVH', button_type='warning', width=widget_width / 2 - 5) self.unignore_button_roi = Button(label='UnIgnore', button_type='primary', width=widget_width / 2 - 5) self.delete_ignored_button_roi = Button(label='Delete DVH', button_type='warning', width=widget_width / 2 - 5) self.remap_rois_function_map = { 'Selected Physician': self.remap_all_rois_for_selected_physician, 'Selected Physician Uncategorized': self.remap_uncategorized_rois_for_selected_physician, 'Selected Physician Ignored': self.remap_ignored_rois_for_selected_physician, 'All Uncategorized': self.remap_uncategorized_rois, 'All Ignored': self.remap_ignored_rois, 'Entire Database': self.remap_all_rois_in_db } remap_options = [ 'Selected Physician', 'Selected Physician Uncategorized', 'Selected Physician Ignored', 'All Uncategorized', 'All Ignored', 'Entire Database' ] self.select_remap = Select(value=remap_options[0], options=remap_options, width=250, title='Remap ROIs in Database:') self.select_remap.on_change('value', self.select_remap_ticker) self.remap_button = Button(label='Remap', button_type='warning', width=widget_width) self.remap_checkbox_ignore = CheckboxGroup( labels=['Remap Ignored Variations'], active=[]) self.remap_checkbox_ignore.on_change('active', self.remap_checkbox_ignore_ticker) # Button calls self.action_button.on_click(self.execute_button_click) self.reload_button_roi.on_click(self.reload_db) self.save_button_roi.on_click(self.save_db) self.delete_uncategorized_button_roi.on_click( self.delete_uncategorized_dvh) self.ignore_button_roi.on_click(self.ignore_dvh) self.delete_ignored_button_roi.on_click(self.delete_ignored_dvh) self.unignore_button_roi.on_click(self.unignore_dvh) self.remap_button.on_click(self.remap_button_click) # Plot self.select_plot_display = Select( value='All', width=widget_width, title='Institutional Data to Display:', options=['All', 'Linked', 'Unlinked', 'Branched']) self.select_plot_display.on_change('value', self.select_plot_display_ticker) self.select_merge_physician_roi = { 'a': Select(value='', options=[''], width=widget_width, title='Merge Physician ROI A:'), 'b': Select(value='', options=[''], width=widget_width, title='Into Physician ROI B:'), 'button': Button(label='Merge', button_type='primary', width=widget_width / 2) } self.select_merge_physician_roi['button'].on_click(self.merge_click) self.roi_map_plot = figure( plot_width=800, plot_height=800, x_range=["Institutional ROI", "Physician ROI", "Variations"], x_axis_location="above", title="(Linked by Physician dropdowns)", tools="reset, ywheel_zoom, ywheel_pan", active_scroll='ywheel_pan') self.roi_map_plot.title.align = 'center' # self.roi_map_plot.title.text_font_style = "italic" self.roi_map_plot.title.text_font_size = "15pt" self.roi_map_plot.xaxis.axis_line_color = None self.roi_map_plot.xaxis.major_tick_line_color = None self.roi_map_plot.xaxis.minor_tick_line_color = None self.roi_map_plot.xaxis.major_label_text_font_size = "12pt" self.roi_map_plot.xgrid.grid_line_color = None self.roi_map_plot.ygrid.grid_line_color = None self.roi_map_plot.yaxis.visible = False self.roi_map_plot.outline_line_color = None self.roi_map_plot.y_range = Range1d(-25, 0) self.roi_map_plot.border_fill_color = "whitesmoke" self.roi_map_plot.min_border_left = 50 self.roi_map_plot.min_border_bottom = 30 self.select_plot_display.js_on_change( 'value', CustomJS(args=dict(p=self.roi_map_plot), code="p.reset.emit()")) self.select_physician.js_on_change( 'value', CustomJS(args=dict(p=self.roi_map_plot), code="p.reset.emit()")) # self.roi_map_plot.toolbar.autohide = True # bokeh > than 0.13? self.source_map = ColumnDataSource( data={ 'name': [], 'color': [], 'x': [], 'y': [], 'x0': [], 'y0': [], 'x1': [], 'y1': [] }) self.roi_map_plot.circle("x", "y", size=12, source=self.source_map, line_color="black", fill_alpha=0.8, color='color') labels = LabelSet(x="x", y="y", text="name", y_offset=8, text_color="#555555", source=self.source_map, text_align='center') self.roi_map_plot.add_layout(labels) self.roi_map_plot.segment(x0='x0', y0='y0', x1='x1', y1='y1', source=self.source_map, alpha=0.5) self.update_roi_map_source_data() self.category_map = { 0: self.select_institutional_roi, 1: self.select_physician, 2: self.select_physician_roi, 3: self.select_variation } self.layout = row( column( Div(text= "<b>WARNING:</b> Buttons in orange cannot be easily undone.", width=widget_width * 3 + 100), Div(text="<hr>", width=widget_width * 3), row(self.select_institutional_roi, self.select_physician), Div(text="<hr>", width=widget_width * 3), row(self.select_physician_roi, self.select_variation, self.select_unlinked_institutional_roi), Div(text="<hr>", width=widget_width * 3), row(self.operator, self.category), row(self.input_text, Spacer(width=30), self.action_button, Spacer(width=50), self.div_action), Div(text="<hr>", width=widget_width * 3), row(self.select_uncategorized_variation, Spacer(width=50), self.select_ignored_variation), row(self.ignore_button_roi, Spacer(width=10), self.delete_uncategorized_button_roi, Spacer(width=50), self.unignore_button_roi, Spacer(width=10), self.delete_ignored_button_roi), Div(text="<hr>", width=widget_width * 3), row(self.select_remap, self.remap_button), self.remap_checkbox_ignore, Div(text="<hr>", width=widget_width * 3), row(self.reload_button_roi, Spacer(width=10), self.save_button_roi)), column( row(self.select_plot_display, Spacer(width=75), self.select_merge_physician_roi['a'], self.select_merge_physician_roi['b'], self.select_merge_physician_roi['button']), self.roi_map_plot, Spacer(width=1000, height=100)))
def create_bokeh_choro(ff, prop=0): """Creates Interactive Bokeh Choropleth for US counties transportationdata. Arguments: ff {dict} -- Dictionary containing filled dataframes Keyword Arguments: prop {int} -- Select the property for which choropleth needs to be created (default: {0}) """ year = 0 # Very Important Function assert isinstance(prop, int) assert isinstance(year, int) assert len(ff['CA'][0].columns) > prop >= 0 assert len(ff['CA'][0].index) > year >= 0 try: # del states["HI"] del states["AK"] except: pass nyears = len(ff['CA'][0].index) state_xs = [states[code]["lons"] for code in states] state_ys = [states[code]["lats"] for code in states] county_xs = [] county_ys = [] district_name = [] for cs in bokeh_counties.values(): for dname in cs: county_xs.append([counties[code]["lons"] for code in counties if counties[code]["detailed name"] == dname][0]) county_ys.append([counties[code]["lats"] for code in counties if counties[code]["detailed name"] == dname][0]) district_name.append(dname) if isinstance(palette, dict): color_mapper = LogColorMapper( palette=palette[list(palette.keys())[-1]]) else: color_mapper = LogColorMapper(palette=palette) pvalues = [] for yx in range(nyears): yvalues = [] for state in ff.keys(): for cs in ff[state]: yvalues.append(cs.iloc[yx, prop]) pvalues.append(yvalues) alldat = {} syear = ff['CA'][0].index[0] for ix, yy in enumerate(range(syear, syear + nyears)): alldat[str(yy)] = pvalues[ix] # alldat = {str(i): v for i, v in enumerate(pvalues)} source = ColumnDataSource(data=dict( x=county_xs, y=county_ys, name=district_name, pvalue=pvalues[0], **alldat)) TOOLS = "pan,wheel_zoom,reset,hover,save" p = figure(title=f"{ff['CA'][0].columns[prop]} across Counties", tools=TOOLS, plot_width=1800, plot_height=700, x_axis_location=None, y_axis_location=None) p.toolbar.active_scroll = "auto" p.toolbar.active_drag = 'auto' p.background_fill_color = "#B0E0E6" p.patches(state_xs, state_ys, fill_alpha=1.0, fill_color='#FFFFE0', line_color="#884444", line_width=2, line_alpha=0.3) p.patches('x', 'y', source=source, fill_color={'field': 'pvalue', 'transform': color_mapper}, fill_alpha=0.8, line_color="white", line_width=0.3) hover = p.select_one(HoverTool) hover.point_policy = "follow_mouse" property = ff['CA'][0].columns[prop] hover.tooltips = [("County", "@name"), (property, "@pvalue"), ("(Long, Lat)", "($x, $y)")] output_file("US_transport.html", title="US Public Transport") slider = Slider(start=int(ff['CA'][0].index[0]), end=int(ff['CA'][0].index[-1]), value=int(ff['CA'][0].index[0]), step=1, title="Start Year") def update(source=source, slider=slider, window=None): """ Update the map: change the bike density measure according to slider will be translated to JavaScript and Called in Browser """ data = source.data v = cb_obj.getv('value') print(data[v]) data['pvalue'] = [x for x in data[v]] source.trigger('change') # source.change.emit() slider.js_on_change('value', CustomJS.from_py_func(update)) show(column(p, widgetbox(slider),))
normal = Jitter(width=0.2, distribution="normal") uniform = Jitter(width=0.2, distribution="uniform") p = figure(x_range=(0, 4), y_range=(0,10), toolbar_location=None, tools="", x_axis_location="above") p.circle(x='x', y='y', color='firebrick', source=source, size=5, alpha=0.5) p.circle(x='xn', y='y', color='olive', source=source, size=5, alpha=0.5) p.circle(x='xu', y='y', color='navy', source=source, size=5, alpha=0.5) label_data = ColumnDataSource(data=dict( x=[1,2,3], y=[0, 0, 0], t=['Original', 'Normal', 'Uniform'] )) label_set = LabelSet(x='x', y='y', text='t', y_offset=-4, source=label_data, render_mode='css', text_baseline="top", text_align='center') p.add_layout(label_set) callback=CustomJS.from_coffeescript(args=dict(source=source, normal=normal, uniform=uniform), code=""" data = source.get 'data' for i in [0...data['y'].length] data['xn'][i] = normal.compute(data['x'][i] + 1) for i in [0...data['y'].length] data['xu'][i] = uniform.compute(data['x'][i] + 2) source.change.emit() """) button = Button(label='Press to apply Jitter!', callback=callback) output_file("transform_jitter_coffee.html", title="Example Jitter Transform (CoffeeScript callback)") show(Column(WidgetBox(button,width=300), p))
upload.callback = CustomJS( args=dict(file_source=file_source), code=""" function read_file(filename) { var reader = new FileReader(); reader.onload = load_handler; reader.onerror = error_handler; // readAsDataURL represents the file's data as a base64 encoded string reader.readAsDataURL(filename); } function load_handler(event) { var b64string = event.target.result; file_source.data = {'file_contents' : [b64string], 'file_name':[input.files[0].name]}; file_source.trigger("change"); } function error_handler(evt) { if(evt.target.error.name == "NotReadableError") { alert("Can't read file!"); } } var input = document.createElement('input'); input.setAttribute('type', 'file'); input.setAttribute('accept', 'image/*'); input.onchange = function(){ if (window.FileReader) { read_file(input.files[0]); } else { alert('FileReader is not supported in this browser'); } } input.click(); """, )
def create_component_jwst(result_dict): """Generate front end plots JWST Function that is responsible for generating the front-end interactive plots for JWST. Parameters ---------- result_dict : dict the dictionary returned from a PandExo run Returns ------- tuple A tuple containing `(script, div)`, where the `script` is the front-end javascript required, and `div` is a dictionary of plot objects. """ noccultations = result_dict['timing']['Number of Transits'] # select the tools we want TOOLS = "pan,wheel_zoom,box_zoom,resize,reset,save" #Define units for x and y axis punit = result_dict['input']['Primary/Secondary'] p=1.0 if punit == 'fp/f*': p = -1.0 else: punit = '('+punit+')^2' if result_dict['input']['Calculation Type'] =='phase_spec': x_axis_label='Time (secs)' frac = 1.0 else: x_axis_label='Wavelength [microns]' frac = result_dict['timing']['Num Integrations Out of Transit']/result_dict['timing']['Num Integrations In Transit'] electrons_out = result_dict['RawData']['electrons_out'] electrons_in = result_dict['RawData']['electrons_in'] var_in = result_dict['RawData']['var_in'] var_out = result_dict['RawData']['var_out'] x = result_dict['FinalSpectrum']['wave'] y = result_dict['FinalSpectrum']['spectrum_w_rand'] err = result_dict['FinalSpectrum']['error_w_floor'] y_err = [] x_err = [] for px, py, yerr in zip(x, y, err): np.array(x_err.append((px, px))) np.array(y_err.append((py - yerr, py + yerr))) source = ColumnDataSource(data=dict(x=x, y=y, y_err=y_err, x_err=x_err, err=err, electrons_out=electrons_out, electrons_in=electrons_in, var_in=var_in, var_out=var_out, p=var_in*0+p,nocc=var_in*0+noccultations, frac = var_in*0+frac)) original = ColumnDataSource(data=dict(x=x, y=y, y_err=y_err, x_err=x_err, err=err, electrons_out=electrons_out, electrons_in=electrons_in, var_in=var_in, var_out=var_out)) ylims = [min(result_dict['OriginalInput']['model_spec'])- 0.1*min(result_dict['OriginalInput']['model_spec']), 0.1*max(result_dict['OriginalInput']['model_spec'])+max(result_dict['OriginalInput']['model_spec'])] xlims = [min(result_dict['FinalSpectrum']['wave']), max(result_dict['FinalSpectrum']['wave'])] plot_spectrum = Figure(plot_width=800, plot_height=300, x_range=xlims, y_range=ylims, tools=TOOLS,#responsive=True, x_axis_label=x_axis_label, y_axis_label=punit, title="Original Model with Observation") plot_spectrum.line(result_dict['OriginalInput']['model_wave'],result_dict['OriginalInput']['model_spec'], color= "black", alpha = 0.5, line_width = 4) plot_spectrum.circle('x', 'y', source=source, line_width=3, line_alpha=0.6) plot_spectrum.multi_line('x_err', 'y_err', source=source) callback = CustomJS(args=dict(source=source, original=original), code=""" // Grab some references to the data var sdata = source.get('data'); var odata = original.get('data'); // Create copies of the original data, store them as the source data sdata['x'] = odata['x'].slice(0); sdata['y'] = odata['y'].slice(0); sdata['y_err'] = odata['y_err'].slice(0); sdata['x_err'] = odata['x_err'].slice(0); sdata['err'] = odata['err'].slice(0); sdata['electrons_out'] = odata['electrons_out'].slice(0); sdata['electrons_in'] = odata['electrons_in'].slice(0); sdata['var_in'] = odata['var_in'].slice(0); sdata['var_out'] = odata['var_out'].slice(0); // Create some variables referencing the source data var x = sdata['x']; var y = sdata['y']; var y_err = sdata['y_err']; var x_err = sdata['x_err']; var err = sdata['err']; var p = sdata['p']; var frac = sdata['frac']; var og_ntran = sdata['nocc']; var electrons_out = sdata['electrons_out']; var electrons_in = sdata['electrons_in']; var var_in = sdata['var_in']; var var_out = sdata['var_out']; var f = wbin.get('value'); var ntran = ntran.get('value'); var wlength = Math.pow(10.0,f); var ind = []; ind.push(0); var start = 0; for (i = 0; i < x.length-1; i++) { if (x[i+1] - x[start] >= wlength) { ind.push(i+1); start = i; } } if (ind[ind.length-1] != x.length) { ind.push(x.length); } var xout = []; var foutout = []; var finout = []; var varinout = []; var varoutout = []; var xslice = []; var foutslice = []; var finslice = []; var varoutslice = []; var varinslice = []; function add(a, b) { return a+b; } for (i = 0; i < ind.length-1; i++) { xslice = x.slice(ind[i],ind[i+1]); foutslice = electrons_out.slice(ind[i],ind[i+1]); finslice = electrons_in.slice(ind[i],ind[i+1]); varinslice = var_in.slice(ind[i],ind[i+1]); varoutslice = var_out.slice(ind[i],ind[i+1]); xout.push(xslice.reduce(add, 0)/xslice.length); foutout.push(foutslice.reduce(add, 0)); finout.push(finslice.reduce(add, 0)); varinout.push(varinslice.reduce(add, 0)); varoutout.push(varoutslice.reduce(add, 0)); xslice = []; foutslice = []; finslice = []; varinslice = []; varoutslice = []; } var new_err = 1.0; var rand = 1.0; for (i = 0; i < x.length; i++) { new_err = Math.pow((frac[i]/foutout[i]),2)*varinout[i] + Math.pow((finout[i]*frac[i]/Math.pow(foutout[i],2)),2)*varoutout[i]; new_err = Math.sqrt(new_err)*Math.sqrt(og_ntran[i]/ntran); rand = new_err*(Math.random()-Math.random()); y[i] = p[i]*((1.0 - frac[i]*finout[i]/foutout[i]) + rand); x[i] = xout[i]; x_err[i][0] = xout[i]; x_err[i][1] = xout[i]; y_err[i][0] = y[i] + new_err; y_err[i][1] = y[i] - new_err; } source.trigger('change'); """) #var_tot = (frac/electrons_out)**2.0 * var_in + (electrons_in*frac/electrons_out**2.0)**2.0 * var_out sliderWbin = Slider(title="binning", value=np.log10(x[1]-x[0]), start=np.log10(x[1]-x[0]), end=np.log10(max(x)/2.0), step= .05, callback=callback) callback.args["wbin"] = sliderWbin sliderTrans = Slider(title="Num Trans", value=noccultations, start=1, end=50, step= 1, callback=callback) callback.args["ntran"] = sliderTrans layout = column(row(sliderWbin,sliderTrans), plot_spectrum) #out of transit 2d output out = result_dict['PandeiaOutTrans'] # Flux 1d x, y = out['1d']['extracted_flux'] x = x[~np.isnan(y)] y = y[~np.isnan(y)] plot_flux_1d1 = Figure(tools=TOOLS, x_axis_label='Wavelength [microns]', y_axis_label='Flux (e/s)', title="Out of Transit Flux Rate", plot_width=800, plot_height=300) plot_flux_1d1.line(x, y, line_width = 4, alpha = .7) tab1 = Panel(child=plot_flux_1d1, title="Total Flux") # BG 1d x, y = out['1d']['extracted_bg_only'] y = y[~np.isnan(y)] x = x[~np.isnan(y)] plot_bg_1d1 = Figure(tools=TOOLS, x_axis_label='Wavelength [microns]', y_axis_label='Flux (e/s)', title="Background", plot_width=800, plot_height=300) plot_bg_1d1.line(x, y, line_width = 4, alpha = .7) tab2 = Panel(child=plot_bg_1d1, title="Background Flux") # SNR 1d accounting for number of occultations x= out['1d']['sn'][0] y = out['1d']['sn'][1] x = x[~np.isnan(y)] y = y[~np.isnan(y)] y = y*np.sqrt(noccultations) plot_snr_1d1 = Figure(tools=TOOLS, x_axis_label=x_axis_label, y_axis_label='SNR', title="Pandeia SNR", plot_width=800, plot_height=300) plot_snr_1d1.line(x, y, line_width = 4, alpha = .7) tab3 = Panel(child=plot_snr_1d1, title="SNR") # Error bars (ppm) x = result_dict['FinalSpectrum']['wave'] y = result_dict['FinalSpectrum']['error_w_floor']*1e6 x = x[~np.isnan(y)] y = y[~np.isnan(y)] ymed = np.median(y) plot_noise_1d1 = Figure(tools=TOOLS,#responsive=True, x_axis_label=x_axis_label, y_axis_label='Error on Spectrum (PPM)', title="Error Curve", plot_width=800, plot_height=300, y_range = [0,2.0*ymed]) ymed = np.median(y) plot_noise_1d1.circle(x, y, line_width = 4, alpha = .7) tab4 = Panel(child=plot_noise_1d1, title="Error") #Not happy? Need help picking a different mode? plot_spectrum2 = Figure(plot_width=800, plot_height=300, x_range=xlims,y_range=ylims, tools=TOOLS, x_axis_label=x_axis_label, y_axis_label=punit, title="Original Model",y_axis_type="log") plot_spectrum2.line(result_dict['OriginalInput']['model_wave'],result_dict['OriginalInput']['model_spec'], line_width = 4,alpha = .7) tab5 = Panel(child=plot_spectrum2, title="Original Model") #create set of five tabs tabs1d = Tabs(tabs=[ tab1, tab2,tab3, tab4, tab5]) # Detector 2d data = out['2d']['detector'] xr, yr = data.shape plot_detector_2d = Figure(tools="pan,wheel_zoom,box_zoom,resize,reset,hover,save", x_range=[0, yr], y_range=[0, xr], x_axis_label='Pixel', y_axis_label='Spatial', title="2D Detector Image", plot_width=800, plot_height=300) plot_detector_2d.image(image=[data], x=[0], y=[0], dh=[xr], dw=[yr], palette="Spectral11") #2d tabs #2d snr data = out['2d']['snr'] data[np.isinf(data)] = 0.0 xr, yr = data.shape plot_snr_2d = Figure(tools=TOOLS, x_range=[0, yr], y_range=[0, xr], x_axis_label='Pixel', y_axis_label='Spatial', title="Signal-to-Noise Ratio", plot_width=800, plot_height=300) plot_snr_2d.image(image=[data], x=[0], y=[0], dh=[xr], dw=[yr], palette="Spectral11") tab1b = Panel(child=plot_snr_2d, title="SNR") #saturation data = out['2d']['saturation'] xr, yr = data.shape plot_sat_2d = Figure(tools=TOOLS, x_range=[0, yr], y_range=[0, xr], x_axis_label='Pixel', y_axis_label='Spatial', title="Saturation", plot_width=800, plot_height=300) plot_sat_2d.image(image=[data], x=[0], y=[0], dh=[xr], dw=[yr], palette="Spectral11") tab2b = Panel(child=plot_sat_2d, title="Saturation") tabs2d = Tabs(tabs=[ tab1b, tab2b]) result_comp = components({'plot_spectrum':layout, 'tabs1d': tabs1d, 'det_2d': plot_detector_2d, 'tabs2d': tabs2d}) return result_comp
text_input = TextInput(value="default", title="标题:") slider = Slider(start=0, end=10, value=1, step=.1, title="Slider") button_group = RadioButtonGroup(labels=["Option 1", "Option 2", "Option 3"], active=0) select = Select(title="Option:", value="foo", options=["foo", "bar", "baz", "quux"]) button_1 = Button(label="Button 1") ''' callback = CustomJS(args=dict(source=source), code=""" var data = source.data var province = cb_obj.label var index = data['provinces'].indexOf(province) var results = cb_obj.value.split("|") var newlegend = results[0] var newColor = results[1] colors = data['colors'] colors[index] = newColor legends = data['legends'] legends[index] = newlegend if (province == '河北') { colors[index+1] = newColor legends[index+1] = newlegend } source.trigger('change') """) dropdowns1 = [] dropdowns2 = [] dropdowns3 = [] menu = [("红色", "红色|crimson"), ("橙色", "橙色|coral"), ("黄色", "黄色|yellow"), ("绿色", "绿色|darkgreen"), ("青色", "青色|darkcyan"), ("蓝色", "蓝色|cornflowerblue"), ("紫色", "紫色|indigo"), ("灰色", "灰色|lightgrey")]
from bokeh.io import vform, output_file, show from bokeh.models import CustomJS, Slider, Paragraph, PreText # NOTE: the JS functions to forvide the format code for strings is found the answer # from the user fearphage at http://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format callback = CustomJS(code=""" var s1 = slider1.get('value') var s2 = slider2.get('value') var s3 = slider3.get('value') if (!String.prototype.format) { String.prototype.format = function() { var args = arguments; return this.replace(/{(\d+)}/g, function(match, number) { return typeof args[number] != 'undefined' ? args[number] : match ; }); }; } para.set('text', "Slider Values\\n\\n Slider 1: {0}\\n Slider 2: {1}\\n Slider 3: {2}".format(s1, s2, s3)) """) para = PreText(text = "Slider Values:\n\n Slider 1: 0\n Slider 2: 0\n Slider 3: 0", width = 200, height = 150) s1 = Slider(title="Slider 1 (Continuous)", start=0, end=1000, value=0, step=1, callback=callback, callback_policy="continuous") s2 = Slider(title="Slider 2 (Throttle)", start=0, end=1000, value=0, step=1, callback=callback, callback_policy="throttle", callback_throttle=2000) s3 = Slider(title="Slider 3 (Mouse Up)", start=0, end=1000, value=0, step=1, callback=callback, callback_policy="mouseup")
for (var i = 0; i < data['time'].length; i++){ updated_allele[i] = x_select(data['time'][i], x_init, s_select); } // update x_allele column entry in source data['x_allele'] = updated_allele // Emit data source for plot to be updated source.change.emit(); """ # Done! Not too bad. Now let's define the arguments for the callback function # Define arguments for JavaScript callback function cb_args = {'source': source, 'sSlider': s_select, 'xoSlider': x_init} # Asign arguments to function cb = CustomJS(args=cb_args, code=cb_script) # Now we must assign this callback function to each of the sliders. What this means is that we must indicate that every time the slider value is changed, the `JavaScript` callback function must be executed. # Assign callback function to widgets x_init.callback = cb s_select.callback = cb x_init.js_on_change('value', cb) s_select.js_on_change('value', cb) # Alright. Now everything is setup for our interactive plot! Now we just need to define the bokeh plot. # Define bokeh axis x_allele_ax = bokeh.plotting.figure(width=300, height=275, x_axis_label='time (a.u.)',
plot2.title='Hourly volume of trips ended in 1 day' def callback(source1=source1, source2=source2): data1 = source1.get('data') f = cb_obj.get('value') date = sorted(data1.keys())[f-1] r = data1[date] data1['radius'] = r source1.trigger('change') data2 = source2.get('data') r = data2[date] data2['radius'] = r source2.trigger('change') slider = Slider(start=1, end=len(sorted(source1.data.keys())[:-4]), value=1, step=1, title="hour", callback=CustomJS.from_py_func(callback), orientation='horizontal') layout = hplot(plot1, plot2) layout = vform(layout, slider) show(layout) save(layout, 'HourlyTripsOneDay.html') df_StartCount = df.loc[:, ['start station id', 'starttime']] df_StartCount['started trips'] = 1 df_StartCount = df_StartCount.groupby([pd.Grouper(freq='D', key='starttime'), 'start station id']).sum() df_StartCount = df_StartCount.unstack(level=0)['started trips'].reset_index() df_StartCount = pd.merge(lut_Start.reset_index(), df_StartCount.fillna(0)) df_StartCount['radius'] = df_StartCount.loc[:, pd.to_datetime(df_StartCount.columns[6])]
def js_link(self, attr, other, other_attr, attr_selector=None): ''' Link two Bokeh model properties using JavaScript. This is a convenience method that simplifies adding a CustomJS callback to update one Bokeh model property whenever another changes value. Args: attr (str) : The name of a Bokeh property on this model other (Model): A Bokeh model to link to self.attr other_attr (str) : The property on ``other`` to link together attr_selector (Union[int, str]) : The index to link an item in a subscriptable ``attr`` Added in version 1.1 Raises: ValueError Examples: This code with ``js_link``: .. code :: python select.js_link('value', plot, 'sizing_mode') is equivalent to the following: .. code:: python from bokeh.models import CustomJS select.js_on_change('value', CustomJS(args=dict(other=plot), code="other.sizing_mode = this.value" ) ) Additionally, to use attr_selector to attach the left side of a range slider to a plot's x_range: .. code :: python range_slider.js_link('value', plot.x_range, 'start', attr_selector=0) which is equivalent to: .. code :: python from bokeh.models import CustomJS range_slider.js_on_change('value', CustomJS(args=dict(other=plot.x_range), code="other.start = this.value[0]" ) ) ''' if attr not in self.properties(): raise ValueError("%r is not a property of self (%r)" % (attr, self)) if not isinstance(other, Model): raise ValueError("'other' is not a Bokeh model: %r" % other) if other_attr not in other.properties(): raise ValueError("%r is not a property of other (%r)" % (other_attr, other)) from bokeh.models import CustomJS selector = f"[{attr_selector!r}]" if attr_selector else "" cb = CustomJS(args=dict(other=other), code=f"other.{other_attr} = this.{attr}{selector}") self.js_on_change(attr, cb)
def highlight_indices(adata, key, basis='diffmap', components=[1, 2], cell_keys='', legend_loc='top_right', plot_width=None, plot_height=None, tools='pan, reset, wheel_zoom, save'): """ Plot cell indices. Useful when trying to set adata.uns['iroot']. Params -------- adata: AnnData Object annotated data object key: str key in `adata.obs_keys()` to color basis: str, optional (default: `'diffmap'`) basis to use cell_keys: str, list(str), optional (default: `''`) keys to display from `adata.obs_keys()` when hovering over cell components: list[int], optional (default: `[1, 2]`) which components of the basis to use legend_loc: str, optional (default `'top_right'`) location of the legend tools: str, optional (default: `'pan, reset, wheel_zoom, save'`) tools for the plot plot_width: int, optional (default: `None`) width of the plot plot_width: int, optional (default: `None`) height of the plot Returns -------- None """ if key not in adata.obs: raise ValueError(f'{key} not found in `adata.obs`') if f'X_{basis}' not in adata.obsm_keys(): raise ValueError(f'basis `X_{basis}` not found in `adata.obsm`') if not isinstance(components, type(np.array)): components = np.array(components) if isinstance(cell_keys, str): cell_keys = list(dict.fromkeys(map(str.strip, cell_keys.split(',')))) if cell_keys != ['']: assert all(map(lambda k: k in adata.obs.keys(), cell_keys)), 'Not all keys are in `adata.obs.keys()`.' else: cell_keys = [] df = pd.DataFrame(adata.obsm[f'X_{basis}'][:, components - (basis != 'diffmap')], columns=['x', 'y']) for k in cell_keys: df[k] = list(map(str, adata.obs[k])) df['index'] = range(len(df)) df[key] = list(adata.obs[key]) if hasattr(adata, 'obs_names'): cell_keys.insert(0, 'name') df['name'] = list(adata.obs_names) if 'index' not in cell_keys: cell_keys.insert(0, 'index') palette = adata.uns.get(f'{key}_colors', viridis(len(df[key].unique()))) p = figure(title=f'{key}', tools=tools) _set_plot_wh(p, plot_width, plot_height) key_col = adata.obs[key].astype('category') if adata.obs[key].dtype.name != 'category' else adata.obs[key] renderers = [] for c, color in zip(key_col.cat.categories, palette): data = ColumnDataSource(df[df[key] == c]) renderers.append([p.scatter(x='x', y='y', size=10, color=color, source=data, muted_alpha=0)]) hover_cell = HoverTool(renderers=list(np.ravel(renderers)), tooltips=[(f'{k}', f'@{k}') for k in cell_keys]) if legend_loc is not None: legend = Legend(items=list(zip(map(str, key_col.cat.categories), renderers)), location=legend_loc, click_policy='mute') p.add_layout(legend) p.legend.location = legend_loc p.xaxis.axis_label = f'{basis}_{components[0]}' p.yaxis.axis_label = f'{basis}_{components[1]}' source = ColumnDataSource(df) labels = LabelSet(x='x', y='y', text='index', x_offset=4, y_offset=4, level='glyph', source=source, render_mode='canvas') labels.visible = False p.add_tools(hover_cell) p.add_layout(labels) button = Button(label='Toggle Indices', button_type='primary') button.callback = CustomJS(args=dict(l=labels), code='l.visible = !l.visible;') show(column(button, p))
plot = curdoc().get_model_by_name(glyph) if plot: layouts.remove(plot) if new: p = figure(name=new) #exec(new + ' = p.' + new + '("x", "y", source = source)') layouts.append(p) select.on_change('value', callback) # Toggle button GUI toggle = Toggle(label="Button", button_type="success") toggle.js_on_click( CustomJS(code=""" console.log('toggle: active=' + this.active, this.toString()) """)) # choice menu GUI OPTIONS = [str(i) for i in range(20)] multi_choice = MultiChoice(value=["foo", "baz"], options=OPTIONS) multi_choice.js_on_change( "value", CustomJS(code=""" console.log('multi_choice: value=' + this.value, this.toString()) """)) # # SELECT menu GUI # selectoptions = ["Postive tested on Covid-19 virus", "Negative tested on Covid-19 virus", "Show both"] # resultSelect = Select(title="What to show", options=selectoptions)
from bokeh.io import vform from bokeh.models import CustomJS, ColumnDataSource, Slider from bokeh.plotting import Figure, output_file, show output_file("callback.html") x = [x * 0.005 for x in range(0, 200)] y = x source = ColumnDataSource(data=dict(x=x, y=y)) plot = Figure(plot_width=400, plot_height=400) plot.line("x", "y", source=source, line_width=3, line_alpha=0.6) def callback(source=source): data = source.get("data") f = cb_obj.get("value") x, y = data["x"], data["y"] for i in range(len(x)): y[i] = Math.pow(x[i], f) source.trigger("change") slider = Slider(start=0.1, end=4, value=1, step=0.1, title="power", callback=CustomJS.from_py_func(callback)) layout = vform(slider, plot) show(layout)
update_plot_callback = CustomJS(args=cb_dict, code=""" var data = source.data; data['p']= []; var off = p_off.value; var p1 = []; var p2 = []; console.log(off); for(var idx = 0; idx<num_pulses; idx++) { //off = off + offset; for(var jdx = 0; jdx<pri; jdx++) { if(jdx < offset || jdx > offset + pulse_width) { p1.push(0); } else { p1.push(1); } if(jdx < off || jdx > off + pulse_width) { p2.push(0); } else { p2.push(1); } } } data['p'].push(p1); data['p'].push(p2); source.change.emit(); """)
time_string[0] = ('0' + Math.floor(time_remaining[0] / 60)).slice(-2) + ':' + ('0' + Math.floor(time_remaining[0] % 60)).slice(-2); enable_button(start_button); disable_button(stop_button); disable_button(reset_button); source.trigger('change'); """) set_start_time_JS = CustomJS(args=dict(source=source), code=""" var data = source.get('data'); var input_mins = mins_slider.get('value'); var input_secs = secs_slider.get('value'); time_string = data['time_string']; time_remaining = data['time_remaining']; start_button_id = start_button.get('id'); start_button_element = document.querySelector('#modelid_' + start_button_id + '>button'); start_time = data['start_time']; start_time[0] = (input_mins * 60) + (input_secs); if (start_button_element.hasAttribute('disabled')) { } else { time_remaining[0] = start_time[0]; time_string[0] = ('0' + Math.floor(time_remaining[0] / 60)).slice(-2) + ':' + ('0' + Math.floor(time_remaining[0] % 60)).slice(-2); } source.trigger('change'); """) # Create plot: a color block, with text centered inside p1 = bkplt.figure(x_range=(-8, 8), y_range=(-5, 5), plot_width=900, plot_height=600, title=None, tools=tools) p1.rect(x=[0], y=[0], width=16, height=10,
def _init_callback(self, root_model, link, source, src_spec, target, tgt_spec, code): references = { k: v for k, v in link.param.get_param_values() if k not in ('source', 'target', 'name', 'code', 'args') } src_model = self._resolve_model(root_model, source, src_spec[0]) ref = root_model.ref['id'] link_id = id(link) if any(link_id in cb.tags for cbs in src_model.js_property_callbacks.values() for cb in cbs): # Skip registering callback if already registered return references['source'] = src_model tgt_model = None if link._requires_target: tgt_model = self._resolve_model(root_model, target, tgt_spec[0]) if tgt_model is not None: references['target'] = tgt_model for k, v in dict(link.args, **self.arg_overrides).items(): arg_model = self._resolve_model(root_model, v, None) if arg_model is not None: references[k] = arg_model elif not isinstance(v, param.Parameterized): references[k] = v if 'holoviews' in sys.modules: from .pane.holoviews import HoloViews, is_bokeh_element_plot if isinstance(source, HoloViews): src = source._plots[ref][0] else: src = source prefix = 'source_' if hasattr(link, 'target') else '' if is_bokeh_element_plot(src): for k, v in src.handles.items(): k = prefix + k if isinstance(v, BkModel) and k not in references: references[k] = v if isinstance(target, HoloViews): tgt = target._plots[ref][0] else: tgt = target if is_bokeh_element_plot(tgt): for k, v in tgt.handles.items(): k = 'target_' + k if isinstance(v, BkModel) and k not in references: references[k] = v self._initialize_models(link, source, src_model, src_spec[1], target, tgt_model, tgt_spec[1]) self._process_references(references) if code is None: code = self._get_code(link, source, src_spec[1], target, tgt_spec[1]) else: code = "try {{ {code} }} catch(err) {{ console.log(err) }}".format( code=code) src_cb = CustomJS(args=references, code=code, tags=[link_id]) changes, events = self._get_triggers(link, src_spec) for ch in changes: src_model.js_on_change(ch, src_cb) for ev in events: src_model.js_on_event(ev, src_cb) if getattr(link, 'bidirectional', False): code = self._get_code(link, target, tgt_spec[1], source, src_spec[1]) reverse_references = dict(references) reverse_references['source'] = tgt_model reverse_references['target'] = src_model tgt_cb = CustomJS(args=reverse_references, code=code, tags=[link_id]) changes, events = self._get_triggers(link, tgt_spec) for ch in changes: tgt_model.js_on_change(ch, tgt_cb) for ev in events: tgt_model.js_on_event(ev, tgt_cb)
def bsm_interactive(): x = [x/100 for x in range(1, 200)] y = [blsprice(1,X,0.05,0.20,1,0,"call") for X in x] source = ColumnDataSource(data=dict(x=x, y=y)) plot = Figure(plot_width=400, plot_height=400) plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6) callbackCall = CustomJS(args=dict(source=source), code=""" function ndist(z) { return (1.0/(Math.sqrt(2*Math.PI)))*Math.exp(-0.5*z); } function N(z) { b1 = 0.31938153; b2 = -0.356563782; b3 = 1.781477937; b4 = -1.821255978; b5 = 1.330274429; p = 0.2316419; c2 = 0.3989423; a=Math.abs(z); if (a>6.0) {return 1.0;} t = 1.0/(1.0+a*p); b = c2*Math.exp((-z)*(z/2.0)); n = ((((b5*t+b4)*t+b3)*t+b2)*t+b1)*t; n = 1.0-b*n; if (z < 0.0) {n = 1.0 - n;} return n; } function black_scholes(call,S,X,r,v,t) { // call = Boolean (to calc call, call=True, put: call=false) // S = stock prics, X = strike price, r = no-risk interest rate // v = volitility (1 std dev of S for (1 yr? 1 month?, you pick) // t = time to maturity // define some temp vars, to minimize function calls var sqt = Math.sqrt(t); var Nd2; //N(d2), used often var nd1; //n(d1), also used often var ert; //e(-rt), ditto var delta; //The delta of the option var price; //price of option d1 = (Math.log(S/X) + r*t)/(v*sqt) + 0.5*(v*sqt); d2 = d1 - (v*sqt); if (call) { delta = N(d1); Nd2 = N(d2); } else { //put delta = -N(-d1); Nd2 = -N(-d2); } ert = Math.exp(-r*t); nd1 = ndist(d1); gamma = nd1/(S*v*sqt); vega = S*sqt*nd1; theta = -(S*v*nd1)/(2*sqt) - r*X*ert*Nd2; rho = X*t*ert*Nd2; return ( S*delta-X*ert *Nd2 > 0) * ( S*delta-X*ert *Nd2) ; } var data = source.get('data'); var f_k = slider_k_call.get('value') var f_r = slider_r_call.get('value') var f_sigma = slider_sigma_call.get('value') var f_t = slider_t_call.get('value') x = data['x'] y = data['y'] for (i = 0; i < x.length; i++) { // black_scholes(call,S,X,r,v,t) y[i] = black_scholes(1,x[i],f_k,f_r,f_sigma,f_t) } source.trigger('change'); """) slider_k_call = Slider(start=0.1, end=1.9, value=1, step=.1, title="strike", callback=callbackCall) slider_r_call = Slider(start=0, end=0.99, value=0.05, step=.01, title="risk-free rate", callback=callbackCall) slider_sigma_call = Slider(start=0, end=0.99, value=0.20, step=.01, title="volatility", callback=callbackCall) slider_t_call = Slider(start=0.05, end=20, value=1, step=.05, title="time", callback=callbackCall) callbackCall.args['slider_k_call'] = slider_k_call callbackCall.args['slider_t_call'] = slider_t_call callbackCall.args['slider_sigma_call'] = slider_sigma_call callbackCall.args['slider_r_call'] = slider_r_call script_call, div_call = components({"p":plot, "slider_k_call":WidgetBox(slider_k_call), "slider_r_call":WidgetBox(slider_r_call), "slider_sigma_call":WidgetBox(slider_sigma_call),"slider_t_call":WidgetBox(slider_t_call)}) x_put = [x/100 for x in range(1, 200)] y_put = [blsprice(1,X,0.05,0.20,1,0,"put") for X in x_put] sourcePut = ColumnDataSource(data=dict(x=x_put, y=y_put)) plot_put = Figure(plot_width=400, plot_height=400) plot_put.line('x', 'y', source=sourcePut, line_width=3, line_alpha=0.6) # JavaScript: # No tools to calculate probability function and black-scholes # Calculate manually with approximation function: Not accurate result callbackPut = CustomJS(args=dict(source=sourcePut), code=""" function ndist(z) { return (1.0/(Math.sqrt(2*Math.PI)))*Math.exp(-0.5*z); } function N(z) { b1 = 0.31938153; b2 = -0.356563782; b3 = 1.781477937; b4 = -1.821255978; b5 = 1.330274429; p = 0.2316419; c2 = 0.3989423; a=Math.abs(z); if (a>6.0) {return 1.0;} // the probability is near 1 if (a<-6.0){return 0.0;} // the probability is near 0 t = 1.0/(1.0+a*p); b = c2*Math.exp((-z)*(z/2.0)); n = ((((b5*t+b4)*t+b3)*t+b2)*t+b1)*t; n = 1.0-b*n; if (z < 0.0) {n = 1.0 - n;} return n; } function black_scholes(call,S,X,r,v,t) { // call = Boolean (to calc call, call=True, put: call=false) // S = stock prics, X = strike price, r = no-risk interest rate // v = volitility (1 std dev of S for (1 yr? 1 month?, you pick) // t = time to maturity // define some temp vars, to minimize function calls var sqt = Math.sqrt(t); var Nd2; //N(d2), used often var nd1; //n(d1), also used often var ert; //e(-rt), ditto var delta; //The delta of the option var price; //price of option d1 = (Math.log(S/X) + r*t)/(v*sqt) + 0.5*(v*sqt); d2 = d1 - (v*sqt); if (call) { delta = N(d1); Nd2 = N(d2); } else { //put delta = -N(-d1); Nd2 = -N(-d2); } ert = Math.exp(-r*t); nd1 = ndist(d1); gamma = nd1/(S*v*sqt); vega = S*sqt*nd1; theta = -(S*v*nd1)/(2*sqt) - r*X*ert*Nd2; rho = X*t*ert*Nd2; return ( S*delta-X*ert *Nd2 > 0) * ( S*delta-X*ert *Nd2) ; } var data = source.get('data'); var f_k = slider_k_put.get('value') var f_r = slider_r_put.get('value') var f_sigma = slider_sigma_put.get('value') var f_t = slider_t_put.get('value') x = data['x'] y = data['y'] for (i = 0; i < x.length; i++) { // black_scholes(put,S,X,r,v,t) y[i] = black_scholes(0,x[i],f_k,f_r,f_sigma,f_t) } source.trigger('change'); """) slider_k_put = Slider(start=0.1, end=1.9, value=1, step=.1, title="strike", callback=callbackPut) slider_r_put = Slider(start=0.01, end=0.40, value=0.05, step=.01, title="risk-free rate", callback=callbackPut) slider_sigma_put = Slider(start=0.01, end=0.99, value=0.20, step=.01, title="volatility", callback=callbackPut) slider_t_put = Slider(start=0.05, end=20, value=1, step=.05, title="time", callback=callbackPut) callbackPut.args['slider_k_put'] = slider_k_put callbackPut.args['slider_t_put'] = slider_t_put callbackPut.args['slider_sigma_put'] = slider_sigma_put callbackPut.args['slider_r_put'] = slider_r_put #script output for graph and sliders of call option script_call, div_call = components({"p_call":plot, "slider_k_call":WidgetBox(slider_k_call), "slider_r_call":WidgetBox(slider_r_call), "slider_sigma_call":WidgetBox(slider_sigma_call),"slider_t_call":WidgetBox(slider_t_call)}) #script output for graph and sliders of put option script_put, div_put =components({"p_put":plot_put, #for put option "slider_k_put":WidgetBox(slider_k_put), "slider_r_put":WidgetBox(slider_r_put), "slider_sigma_put":WidgetBox(slider_sigma_put),"slider_t_put":WidgetBox(slider_t_put)}) return render_template("bsm_graph.html", div_call = div_call, script_call = script_call, div_put=div_put, script_put=script_put)
callback = CustomJS(code="""aline.visible = false; // aline and etc.. are bline.visible = false; // passed in from args cline.visible = false; ccline.visible = false; dline.visible = false; ddline.visible = false; eline.visible = false; fline.visible = false; gline.visible = false; ggline.visible = false; hline.visible = false; iline.visible = false; jline.visible = false; kline.visible = false; kkline.visible = false; // cb_obj is injected in thanks to the callback if (cb_obj.active.includes(0)){aline.visible = true;} // 0 index box is aline if (cb_obj.active.includes(1)){bline.visible = true;} // 1 index box is bline if (cb_obj.active.includes(2)){cline.visible = true;} if (cb_obj.active.includes(3)){ccline.visible = true;} // 1 index box is bline if (cb_obj.active.includes(4)){dline.visible = true;} if (cb_obj.active.includes(5)){ddline.visible = true;} // 1 index box is bline if (cb_obj.active.includes(6)){eline.visible = true;} // 1 index box is bline if (cb_obj.active.includes(7)){fline.visible = true;} // 1 index box is bline if (cb_obj.active.includes(8)){gline.visible = true;} if (cb_obj.active.includes(9)){ggline.visible = true;} // 1 index box is bline if (cb_obj.active.includes(10)){hline.visible = true;} // 1 index box is bline if (cb_obj.active.includes(11)){iline.visible = true;} // 1 index box is bline if (cb_obj.active.includes(12)){jline.visible = true;} // 1 index box is bline if (cb_obj.active.includes(13)){kline.visible = true;} if (cb_obj.active.includes(14)){kkline.visible = true;} // 1 index box is bline """, args={ 'aline': aline, 'bline': bline, 'cline': cline, 'ccline': ccline, 'dline': dline, 'ddline': ddline, 'eline': eline, 'fline': fline, 'gline': gline, 'ggline': ggline, 'hline': hline, 'iline': iline, 'jline': jline, 'kline': kline, 'kkline': kkline })
// set reform data source var tax = individual.active === 1 ? 'metr' : 'mettr'; var parts = [tax, rate.active.toString(), depreciation.active.toString(), deductibility.active.toString()]; var reform_sources = %s; ref_source.data = reform_sources[parts.join('_')].data; // set baseline data source var bs_source = individual.active === 1 ? base_metr : base_mettr; base_source.data = bs_source.data; """ % js_source_array callback = CustomJS(args=reform_sources, code=reform_source_change_code) # Create buttons rate_buttons = RadioButtonGroup( labels = ["39.6%", "35%", "30%", "25%", "20%", "15%", "0%"], active = 1, callback = callback, width = 500) depreciation_buttons = RadioButtonGroup( labels = ["Economic", "Current Law, No Bonus", "Current Law", "Full Expensing"], active = 2, callback = callback, width = 500) deductibility_buttons = RadioButtonGroup( labels = ["Fully Deductible", "Non-Deductible"], active = 0,
u2 = p.circle(x=field('xu', uniform), y='y', color='navy', source=source, size=5, alpha=0.5, visible=False) label_data = ColumnDataSource( data=dict(x=[1, 2, 3], y=[0, 0, 0], t=['Original', 'Normal', 'Uniform'])) label_set = LabelSet(x='x', y='y', text='t', y_offset=-4, source=label_data, text_baseline="top", text_align='center') p.add_layout(label_set) callback = CustomJS(args=dict(r1=r1, n1=n1, r2=r2, u2=u2), code=""" for (const r of [r1, n1, r2, u2]) { r.visible = !r.visible } """) button = Button(label='Press to toggle Jitter!', width=300) button.js_on_event("button_click", callback) show(Column(button, p))
y_range_name="percent") callbackLine = CustomJS(args={ 'rect': rc.data_source.data, 'line': lnData.data_source }, code=""" var rdataYear = rect.YEAR; var rdataAgeGroup = rect.AGE_GROUP; var rdataDeaths = rect.DEATHS; var data = {'x': [], 'y': [], 'x1': [], 'y1': []}; var deaths = []; var years = [1945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017 ] var indices = cb_data.index.indices; var newarr = rect.AGE_GROUP.map((e,i) => e === rdataAgeGroup[indices] ? i : undefined).filter(x => x); for (var i = 0; i < newarr.length; i++){ deaths.push(rdataDeaths[newarr[i]]) } line.data = {x: years, y: deaths} """) p2.x_range = Range1d(1945, 2017)
def plot_pca_space( x, y, beta, plot_type, target_name, classification_strings=None, plot_both=True, output_html=None, width=500, height=500, sizing_mode="stretch_both", ): """Plot regression predictions in a 2-component PCA space. This function has two plot modes, specified by the `plot_both` flag. If `plot_both` == True, this plots side-by-side scatter plots of the target variable in 2-D PCA space. The right plot is the post-SGL weighted feature matrix and the left plot is the pre-SGL original feature matrix. Otherwise this plots only the post-SGL weighted feature space and also plots a contour of the regression prediction. Parameters ---------- x : numpy.ndarray Feature matrix y : pandas.Series Binary classification target array beta : numpy.ndarray Regression coefficients plot_type : 'regression' or 'classification' Type of ML problem target_name : string The name of the target variable (used in hover tool) classification_strings : dict Dictionary mapping the categorical numerical target values onto their names. If `plot_type` == "regression", this parameter is not used. plot_both : boolean, default=True If True, plot the PCA in both the original feature space and the feature space projected onto the coefficient vector output_html : string or None, default=None Filename for bokeh html output. If None, figure will not be saved width : int, default=500 Width of each beta plot (in pixels) height : int, default=500 Height of each beta plot (in pixels) sizing_mode : string One of ("fixed", "stretch_both", "scale_width", "scale_height", "scale_both"). Specifies how will the items in the layout resize to fill the available space. Default is "stretch_both". For more information on the different modes see https://bokeh.pydata.org/en/latest/docs/reference/models/layouts.html#bokeh.models.layouts.LayoutDOM """ if plot_type not in ["regression", "classification"]: raise ValueError( '`plot_type` must be either "classification" or ' '"regression"' ) x_projection = np.outer(x.dot(beta), beta) / (np.linalg.norm(beta) ** 2.0) pca_orig = PCA(n_components=2) pca_sgl = PCA(n_components=2) x2_sgl = pca_sgl.fit_transform(x_projection) x2_orig = pca_orig.fit_transform(x) if plot_type == "classification": cmap = plt.get_cmap("RdBu") colors = [to_hex(c) for c in cmap(np.linspace(1, 0, 256))] else: colors = Cividis256 color_mapper = LinearColorMapper(palette=colors, low=np.min(y), high=np.max(y)) color_bar = ColorBar( color_mapper=color_mapper, ticker=FixedTicker(ticks=np.arange(np.min(y), np.max(y), 5)), label_standoff=8, border_line_color=None, location=(0, 0), ) if plot_type == "classification": target = y.copy() for k, v in classification_strings.items(): target[y == k] = v else: target = y.copy() pc_info = { "pc0_sgl": x2_sgl[:, 0], "pc1_sgl": x2_sgl[:, 1], "target": y.values, "target_string": target.values, "subject_id": target.index, } ps = [None] if plot_both: pc_info["pc0_orig"] = x2_orig[:, 0] pc_info["pc1_orig"] = x2_orig[:, 1] ps = [None] * 2 tooltips = [("Subject", "@subject_id"), (target_name, "@target_string")] source = ColumnDataSource(data=pc_info) code = "source.set('selected', cb_data.index);" callback = CustomJS(args={"source": source}, code=code) if not plot_both: ps[0] = figure( plot_width=int(width * 1.1), plot_height=height, toolbar_location="right" ) npoints = 200 dx = np.max(x2_sgl[:, 0]) - np.min(x2_sgl[:, 0]) xmid = 0.5 * (np.max(x2_sgl[:, 0]) + np.min(x2_sgl[:, 0])) xmin = xmid - (dx * 1.1 / 2.0) xmax = xmid + (dx * 1.1 / 2.0) dy = np.max(x2_sgl[:, 1]) - np.min(x2_sgl[:, 1]) ymid = 0.5 * (np.max(x2_sgl[:, 1]) + np.min(x2_sgl[:, 1])) ymin = ymid - (dy * 1.1 / 2.0) ymax = ymid + (dy * 1.1 / 2.0) x_subspace = np.linspace(xmin, xmax, npoints) y_subspace = np.linspace(ymin, ymax, npoints) subspace_pairs = np.array( [[p[0], p[1]] for p in itertools.product(x_subspace, y_subspace)] ) bigspace_pairs = ( pca_sgl.inverse_transform(subspace_pairs) * np.linalg.norm(beta) ** 2.0 ) predict_pairs = bigspace_pairs.dot( np.divide( np.ones_like(beta), beta, out=np.zeros_like(beta), where=beta != 0 ) ) x_grid, _ = np.meshgrid(x_subspace, y_subspace) p_grid = predict_pairs.reshape(x_grid.shape, order="F") ps[0].image( image=[p_grid], x=xmin, y=ymin, dw=dx * 1.1, dh=dy * 1.1, palette=colors ) ps[0].add_layout(color_bar, "right") ps[0].x_range = Range1d(xmin, xmax) ps[0].y_range = Range1d(ymin, ymax) else: ps[0] = figure(plot_width=width, plot_height=height, toolbar_location="right") if plot_type == "regression": ps[0].add_layout(color_bar, "right") if plot_type == "regression": ps[0].title.text = "Regression in Post-SGL PCA space" s0 = ps[0].scatter( "pc0_sgl", "pc1_sgl", source=source, size=20, fill_color={"field": "target", "transform": color_mapper}, line_color="white", line_width=2.5, ) else: ps[0].title.text = "Classification in Post-SGL PCA space" s0 = ps[0].scatter( "pc0_sgl", "pc1_sgl", source=source, size=20, fill_color={"field": "target", "transform": color_mapper}, line_color="white", line_width=2.5, legend="target_string", ) hover0 = HoverTool(tooltips=tooltips, callback=callback, renderers=[s0]) ps[0].add_tools(hover0) if plot_both: ps[1] = figure(plot_width=width, plot_height=height, toolbar_location="right") if plot_type == "regression": ps[1].title.text = "Regression in Original PCA space" s1 = ps[1].scatter( "pc0_orig", "pc1_orig", source=source, size=20, fill_color={"field": "target", "transform": color_mapper}, line_color="white", line_width=2.5, ) else: ps[1].title.text = "Classification in Original PCA space" s1 = ps[1].scatter( "pc0_orig", "pc1_orig", source=source, size=20, fill_color={"field": "target", "transform": color_mapper}, line_color="white", line_width=2.5, legend="target_string", ) hover1 = HoverTool(tooltips=tooltips, callback=callback, renderers=[s1]) ps[1].add_tools(hover1) for plot in ps: plot.xaxis.axis_label = "1st Principal Component" plot.yaxis.axis_label = "2nd Principal Component" if plot_both: layout = row(ps[::-1]) else: layout = ps[0] layout.sizing_mode = sizing_mode if output_html is not None: html = file_html(layout, CDN, "my plot") with open(op.abspath(output_html), "w") as fp: fp.write(html) else: show(layout)
def make_interactive_comparison_barchart(sources, bar, countries, years, title, default_year='2012', show_plot=True, legend_x=1, legend_x_padding=7.5, legend_y=[1.12, 1.05], legend_max_x_items=4): # define PlotObjects that are common for all years xdr = list(countries) xdr = FactorRange(factors=sorted(xdr)) ydr = Range1d(0,1.2) AXIS_FORMATS = dict( minor_tick_in=None, minor_tick_out=None, major_tick_in=None, major_label_text_font_size="10pt", major_label_text_font_style="normal", axis_label_text_font_size="10pt", axis_line_color='#AAAAAA', major_tick_line_color='#AAAAAA', major_label_text_color='#666666', major_tick_line_cap="round", axis_line_cap="round", axis_line_width=1, major_tick_line_width=1, ) plot = Plot(plot_width=800, plot_height=375, x_range = xdr, y_range=ydr, title = title + default_year, outline_line_color=None, toolbar_location=None, responsive=True) xaxis = CategoricalAxis(major_label_orientation = pi/4, axis_label="", **AXIS_FORMATS) yaxis = LinearAxis(SingleIntervalTicker(interval=0.2), axis_label="", **AXIS_FORMATS) plot.add_layout(xaxis, 'below') plot.add_layout(yaxis, 'left') # create 'reference' source data # 1. this is the ColumnDataSource that has all the glyph info from # our previously made BarCharts # 2. it should clone a data-source from `sources` otherwise an moving # the slider back to '2012' will fail to trigger an update since the # new and old `reference_source` ColumnDataSource objects will be the same! reference_source = sources['_' + default_year].clone() plot.add_glyph(reference_source, \ Rect(x='x', y='y', width='width', height='height',\ fill_color='color', fill_alpha='fill_alpha')) # --- add legend --- # # This is why we kept one barchart around. It's 'Legend' renderer has all # the coloring and text info we want. So we'll have to rip it out # and manually make our own legend with glyphs bar_legend = bar.select(dict(type=Legend))[0].clone() tmp_source = [] for index, legend in enumerate(bar_legend.legends): legend_text = legend[0] glyph = legend[1][0] x = legend_x + legend_x_padding*(index % legend_max_x_items) y = legend_y[0] if (index < legend_max_x_items) else legend_y[1] tmp_source.append(pd.DataFrame(dict( x=x, y=y, legend_text=legend_text, color=glyph.data_source.to_df().color ))) tmp_source = ColumnDataSource(pd.concat(tmp_source)) plot.add_glyph(tmp_source, Text(x='x', y='y', text='legend_text', text_baseline='bottom', x_offset=10, y_offset=8)) plot.add_glyph(tmp_source, Square(x='x', y='y', size=10, line_color=None, fill_color='color')) # --- add HoverTool --- # hover = HoverTool(point_policy = "snap_to_data") # options "follow_mouse", "snap_to_data") hover.tooltips = OrderedDict([ ("Country", "@x"), ("Share", "@height{0.000}") ]) plot.add_tools(hover) # --- JS callback ---- # dictionary_of_sources = dict(zip([x for x in years], ['_%s' % x for x in years])) js_source_array = str(dictionary_of_sources).replace("'", "") # Add the slider code = """ var year = slider.get('value'), sources = %s, new_source_data = sources[year].get('data'); plot.set('title', '%s' + year); renderer_source.set('data', new_source_data); renderer_source.trigger('change'); """ % (js_source_array, title) callback = CustomJS(args=sources, code=code) callback.args["plot"] = plot callback.args["renderer_source"] = reference_source slider = Slider(start=int(years[0]), end=int(years[-1]), value=int(default_year), step=1, orientation='horizontal', title="Year", callback=callback) callback.args["slider"] = slider # --- put it all together --- # layout = vplot(plot, slider) if show_plot: show(layout) return layout
def get_gapminder_plot(): fertility_df, life_expectancy_df, population_df_size, regions_df, years, regions = _process_gapminder_data() sources = {} region_color = regions_df['region_color'] region_color.name = 'region_color' for year in years: fertility = fertility_df[year] fertility.name = 'fertility' life = life_expectancy_df[year] life.name = 'life' population = population_df_size[year] population.name = 'population' new_df = pd.concat([fertility, life, population, region_color], axis=1) sources['_' + str(year)] = ColumnDataSource(new_df) dictionary_of_sources = dict(zip([x for x in years], ['_%s' % x for x in years])) js_source_array = str(dictionary_of_sources).replace("'", "") xdr = Range1d(1, 9) ydr = Range1d(20, 100) plot = Plot( x_range=xdr, y_range=ydr, title="", plot_width=800, plot_height=400, outline_line_color=None, toolbar_location=None, responsive=True, ) AXIS_FORMATS = dict( minor_tick_in=None, minor_tick_out=None, major_tick_in=None, major_label_text_font_size="10pt", major_label_text_font_style="normal", axis_label_text_font_size="10pt", axis_line_color='#AAAAAA', major_tick_line_color='#AAAAAA', major_label_text_color='#666666', major_tick_line_cap="round", axis_line_cap="round", axis_line_width=1, major_tick_line_width=1, ) xaxis = LinearAxis(SingleIntervalTicker(interval=1), axis_label="Children per woman (total fertility)", **AXIS_FORMATS) yaxis = LinearAxis(SingleIntervalTicker(interval=20), axis_label="Life expectancy at birth (years)", **AXIS_FORMATS) plot.add_layout(xaxis, 'below') plot.add_layout(yaxis, 'left') # ### Add the background year text # We add this first so it is below all the other glyphs text_source = ColumnDataSource({'year': ['%s' % years[0]]}) text = Text(x=2, y=35, text='year', text_font_size='150pt', text_color='#EEEEEE') plot.add_glyph(text_source, text) # Add the circle renderer_source = sources['_%s' % years[0]] circle_glyph = Circle( x='fertility', y='life', size='population', fill_color='region_color', fill_alpha=0.8, line_color='#7c7e71', line_width=0.5, line_alpha=0.5) circle_renderer = plot.add_glyph(renderer_source, circle_glyph) # Add the hover (only against the circle and not other plot elements) tooltips = "@index" plot.add_tools(HoverTool(tooltips=tooltips, renderers=[circle_renderer])) # Add the legend text_x = 7 text_y = 95 for i, region in enumerate(regions): plot.add_glyph(Text(x=text_x, y=text_y, text=[region], text_font_size='10pt', text_color='#666666')) plot.add_glyph(Circle(x=text_x - 0.1, y=text_y + 2, fill_color=Spectral6[i], size=10, line_color=None, fill_alpha=0.8)) text_y = text_y - 5 # Add the slider code = """ var year = slider.get('value'), sources = %s, new_source_data = sources[year].get('data'); renderer_source.set('data', new_source_data); text_source.set('data', {'year': [String(year)]}); """ % js_source_array callback = CustomJS(args=sources, code=code) slider = Slider(start=years[0], end=years[-1], value=1, step=1, title="Year", callback=callback, name='testy') callback.args["renderer_source"] = renderer_source callback.args["slider"] = slider callback.args["text_source"] = text_source # Lay it out return vplot(plot, slider)
# the callback function to update the color of the block and associated label text # NOTE: the JS functions for converting RGB to hex are taken from the excellent answer # by Tim Down at http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb callback = CustomJS(args=dict(source=source), code=""" function componentToHex(c) { var hex = c.toString(16); return hex.length == 1 ? "0" + hex : hex; } function rgbToHex(r, g, b) { return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); } function toInt(v) { return v | 0; } var data = source.data; var color = data['color']; var text_color = data['text_color']; var R = toInt(red_slider.value); var G = toInt(green_slider.value); var B = toInt(blue_slider.value); color[0] = rgbToHex(R, G, B); text_color[0] = '#ffffff'; if ((R > 127) || (G > 127) || (B > 127)) { text_color[0] = '#000000'; } source.change.emit(); """) # create slider tool objects with a callback to control the RGB levels for first plot SLIDER_ARGS = dict(start=0, end=255, value=255, step=1, callback=callback)
x = np.linspace(0, 10, 500) y = np.sin(x) source = ColumnDataSource(data=dict(x=x, y=y)) plot = figure(y_range=(-10, 10), plot_width=400, plot_height=400) plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6) callback = CustomJS(args=dict(source=source), code=""" var data = source.get('data'); var A = amp.get('value') var k = freq.get('value') var phi = phase.get('value') var B = offset.get('value') x = data['x'] y = data['y'] for (i = 0; i < x.length; i++) { y[i] = B + A*Math.sin(k*x[i]+phi); } source.trigger('change'); """) amp_slider = Slider(start=0.1, end=10, value=1, step=.1, title="Amplitude", callback=callback) callback.args["amp"] = amp_slider freq_slider = Slider(start=0.1, end=10, value=1, step=.1, title="Frequency", callback=callback) callback.args["freq"] = freq_slider
def station_callback(position_source=None, data_source=None, figures=None, seconds=None, pmap=None): """Return a CustomJS callback.""" # assert position_source, data_source code = """ //console.log('station_callback'); // Set column name to select similar glyphs var key = 'KEY'; var statn_key = 'STATION'; var sec = seconds.data; // Get data from ColumnDataSource var position_data = position_source.data; //var data = data_source.data; var parameter_mapping = parameter_mapping; var figures = figures; //console.log('parameter_mapping', parameter_mapping); // Get indices array of all selected items var selected = position_source.selected.indices; //console.log('data[y].length', data['y'].length) //console.log('selected', selected); // Update figure titles flag_color_mapping var station_name = position_data[statn_key][selected[0]]; var selected_key = position_data[key][selected[0]]; //console.log('station_name', station_name); //console.log('selected_key', selected_key); // Update active keys in data source if (selected.length == 1) { for (var fig_key in figures){ figures[fig_key].title.text = station_name + ' - ' + selected_key } data_source['main_source'].data = data_source[selected_key].data; // Save changes to ColumnDataSource data_source['main_source'].change.emit(); } else { data_source['main_source'].data = data_source['default_source'].data; console.log('We can only work with one serie at a time', selected.length) } var d = new Date(); var t = d.getTime(); var new_seconds = Math.round(t / 1000); sec.tap_time[0] = new_seconds; sec.reset_time[0] = new_seconds; seconds.change.emit(); for (var fig_key in figures){ figures[fig_key].reset.emit(); } //console.log('station_callback - DONE'); """ # Create a CustomJS callback with the code and the data return CustomJS(args={ 'position_source': position_source, 'data_source': data_source, 'figures': figures, 'seconds': seconds, 'parameter_mapping': pmap, }, code=code)
def get_flag_buttons_widget(position_source, data_source, datasets, key_mapper=None, flag_keys=None, color_keys=None, size_keys=None, figure_objs=None, select_button=None): """Return a list of buttons. Each button represents a QC-flag which will be applied when the button is pressed. """ code = """ //console.log('get_flag_buttons_widget'); var flag_color_mapping = {'A-flag': {'c':'navy', 'flag': '', 'size': 6}, 'B-flag': {'c':'red', 'flag': 'B', 'size': 12}, 'E-flag': {'c':'green', 'flag': 'E', 'size': 12}, 'S-flag': {'c':'orange', 'flag': 'S', 'size': 12}}; // Get data from ColumnDataSource var position_data = position_source.data; var data = data_source.data; var select_button_type = select_button.button_type; // Set variables attributes var color_columns = color_keys; var size_columns = size_keys; var flag_keys = flag_keys; var selected_flag = flag; var selected_position = position_source.selected.indices; var selected_key = position_data['KEY'][selected_position[0]]; // Get indices array of all selected items var selected_indices = data_source.selected.indices; var flag_value = flag_color_mapping[selected_flag]['flag']; var size_value = flag_color_mapping[selected_flag]['size']; var color_value = flag_color_mapping[selected_flag]['c']; if (selected_position.length == 1) { for (var i = 0; i < selected_indices.length; i++) { //console.log('selected_indices[i]', selected_indices[i]) //console.log('index_value', index_value) for (var j = 0; j < color_columns.length; j++) { data[color_columns[j]][selected_indices[i]] = color_value; data[size_columns[j]][selected_indices[i]] = size_value; //data[flag_keys[j]][selected_indices[i]] = flag_value; } } // Save changes to ColumnDataSource (only on the plotting side of ColumnDataSource) data_source.change.emit(); for (var key in figure_objs) { figure_objs[key].reset.emit(); } data_source.selected.indices = selected_indices; select_button.button_type = select_button_type; // Trigger python callback inorder to save changes to the actual datasets dummy_trigger.glyph.size = {'value': Math.random(), 'units': 'screen'}; dummy_trigger.glyph.change.emit(); } else { console.log('To many selected stations!! We can only work with one at a time', selected_position.length) } """ # noqa: E501 flag_color_mapping = { 'A-flag': { 'c': 'navy', 'flag': '' }, 'B-flag': { 'c': 'red', 'flag': 'B' }, 'E-flag': { 'c': 'green', 'flag': 'E' }, 'S-flag': { 'c': 'orange', 'flag': 'S' } } def callback_py(attr, old, new, flag=None): selected_position = position_source.selected.indices if len(selected_position) > 1: print('multi serie selection, no good! len(selected_position) = {}' ''.format(len(selected_position))) return selected_key = position_source.data['KEY'][selected_position[0]] ds_key = key_mapper.get(selected_key) selected_indices = data_source.selected.indices flag_value = flag_color_mapping[flag].get('flag') datasets[ds_key]['data'].loc[selected_indices, flag_keys] = flag_value # button_types = default, primary, success, warning or danger button_types = ['primary', 'danger', 'success', 'warning'] flag_list = ['A-flag', 'B-flag', 'E-flag', 'S-flag'] button_list = [Spacer(width=10, height=10)] dummy_figure = figure() for flag, b_type in zip(flag_list, button_types): dummy_trigger = dummy_figure.circle(x=[1], y=[1], alpha=0) dummy_trigger.glyph.on_change('size', partial(callback_py, flag=flag)) callback = CustomJS(args={ 'position_source': position_source, 'data_source': data_source, 'figure_objs': figure_objs, 'flag': flag, 'dummy_trigger': dummy_trigger, 'select_button': select_button }, code=code) callback.args["color_keys"] = color_keys callback.args["size_keys"] = size_keys callback.args["flag_keys"] = flag_keys button = Button(label=flag, width=30, button_type=b_type) button.js_on_event(ButtonClick, callback) button_list.append(button) button_list.append(Spacer(width=10, height=10)) return row(button_list, sizing_mode="stretch_width")
from bokeh.io import output_file, show from bokeh.models import CustomJS, Slider, Div, Column # NOTE: the JS functions to forvide the format code for strings is found the answer # from the user fearphage at http://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format callback = CustomJS( code=""" var s1 = slider1.get('value') var s2 = slider2.get('value') var s3 = slider3.get('value') if (!String.prototype.format) { String.prototype.format = function() { var args = arguments; return this.replace(/{(\d+)}/g, function(match, number) { return typeof args[number] != 'undefined' ? args[number] : match ; }); }; } para.set('text', "<h1>Slider Values</h1><p>Slider 1: {0}<p>Slider 2: {1}<p>Slider 3: {2}".format(s1, s2, s3)) """ ) para = Div(text="<h1>Slider Values:</h1><p>Slider 1: 0<p>Slider 2: 0<p>Slider 3: 0") s1 = Slider( title="Slider 1 (Continuous)", start=0, end=1000, value=0, step=1, callback=callback, callback_policy="continuous"
def nb_view_patches3d(Yr, A, C, b, f, dims, image_type='mean', max_projection=False, axis=0, thr=0.99, denoised_color=None): ''' Interactive plotting utility for ipython notbook Parameters ----------- Yr: np.ndarray movie A,C,b,f: np.ndarrays outputs of matrix factorization algorithm dims: tuple of ints dimensions of movie (x, y and z) image_type: 'mean', 'max' or 'corr' image to be overlaid to neurons (average, maximum or nearest neigbor correlation) max_projection: boolean plot max projection along specified axis if True, plot layers if False axis: int (0, 1 or 2) axis along which max projection is performed or layers are shown thr: double threshold regulating the extent of the displayed patches denoised_color: string or None color name (e.g. 'red') or hex color code (e.g. '#F0027F') ''' d, T = Yr.shape order = list(range(4)) order.insert(0, order.pop(axis)) Yr = Yr.reshape(dims + (-1,), order='F').transpose(order).reshape((d, T), order='F') A = A.reshape(dims + (-1,), order='F').transpose(order).reshape((d, -1), order='F') dims = tuple(np.array(dims)[order[:3]]) d1, d2, d3 = dims colormap = cm.get_cmap("jet") # choose any matplotlib colormap here grayp = [mpl.colors.rgb2hex(m) for m in colormap(np.arange(colormap.N))] nr, T = C.shape nA2 = np.sum(np.array(A)**2, axis=0) b = np.squeeze(b) f = np.squeeze(f) Y_r = np.array(spdiags(old_div(1, nA2), 0, nr, nr) * (A.T * np.matrix(Yr) - (A.T * np.matrix(b[:, np.newaxis])) * np.matrix(f[np.newaxis]) - (A.T.dot(A)) * np.matrix(C)) + C) bpl.output_notebook() x = np.arange(T) z = old_div(np.squeeze(np.array(Y_r[:, :].T)), 100) k = np.reshape(np.array(A), dims + (A.shape[1],), order='F') source = ColumnDataSource(data=dict(x=x, y=z[:, 0], y2=old_div(C[0], 100), z=z, z2=old_div(C.T, 100))) if max_projection: if image_type == 'corr': image_neurons = [(local_correlations( Yr.reshape(dims + (-1,), order='F'))[:, ::-1]).max(i) for i in range(3)] elif image_type in ['mean', 'max']: tmp = [({'mean': np.nanmean, 'max': np.nanmax}[image_type] (k, axis=3)[:, ::-1]).max(i) for i in range(3)] else: raise ValueError("image_type must be 'mean', 'max' or 'corr'") # tmp = [np.nanmean(k.max(i), axis=2) for i in range(3)] image_neurons = np.nan * np.ones((int(1.05 * (d1 + d2)), int(1.05 * (d1 + d3)))) image_neurons[:d2, -d3:] = tmp[0][::-1] image_neurons[:d2, :d1] = tmp[2].T[::-1] image_neurons[-d1:, -d3:] = tmp[1] offset1 = image_neurons.shape[1] - d3 offset2 = image_neurons.shape[0] - d1 coors = [plot_contours(coo_matrix(A.reshape(dims + (-1,), order='F').max(i) .reshape((old_div(np.prod(dims), dims[i]), -1), order='F')), tmp[i], thr=thr) for i in range(3)] pl.close() cc1 = [[cor['coordinates'][:, 0] + offset1 for cor in coors[0]], [cor['coordinates'][:, 1] for cor in coors[2]], [cor['coordinates'][:, 0] + offset1 for cor in coors[1]]] cc2 = [[cor['coordinates'][:, 1] for cor in coors[0]], [cor['coordinates'][:, 0] for cor in coors[2]], [cor['coordinates'][:, 1] + offset2 for cor in coors[1]]] c1x = cc1[0][0] c2x = cc2[0][0] c1y = cc1[1][0] c2y = cc2[1][0] c1z = cc1[2][0] c2z = cc2[2][0] source2 = ColumnDataSource(data=dict( # x=npointsx, y=npointsy, z=npointsz, c1x=c1x, c1y=c1y, c1z=c1z, c2x=c2x, c2y=c2y, c2z=c2z, cc1=cc1, cc2=cc2)) callback = CustomJS(args=dict(source=source, source2=source2), code=""" var data = source.get('data'); var f = cb_obj.get('value')-1 y = data['y'] y2 = data['y2'] for (i = 0; i < y.length; i++) { y[i] = data['z'][i][f]; y2[i] = data['z2'][i][f]; } var data2 = source2.get('data'); c1x = data2['c1x']; c2x = data2['c2x']; c1y = data2['c1y']; c2y = data2['c2y']; c1z = data2['c1z']; c2z = data2['c2z']; cc1 = data2['cc1']; cc2 = data2['cc2']; for (i = 0; i < c1x.length; i++) { c1x[i] = cc1[0][f][i] c2x[i] = cc2[0][f][i] } for (i = 0; i < c1y.length; i++) { c1y[i] = cc1[1][f][i] c2y[i] = cc2[1][f][i] } for (i = 0; i < c1z.length; i++) { c1z[i] = cc1[2][f][i] c2z[i] = cc2[2][f][i] } source2.trigger('change'); source.trigger('change'); """) else: if image_type == 'corr': image_neurons = local_correlations(Yr.reshape(dims + (-1,), order='F'))[:, ::-1] elif image_type in ['mean', 'max']: image_neurons = {'mean': np.nanmean, 'max': np.nanmax}[image_type](k, axis=3)[:, ::-1] else: raise ValueError('image_type must be mean, max or corr') cmap = bokeh.models.mappers.LinearColorMapper([mpl.colors.rgb2hex(m) for m in colormap(np.arange(colormap.N))]) cmap.high = image_neurons.max() coors = get_contours3d(A, dims, thr=thr) pl.close() cc1 = [[l[:, 0] for l in n['coordinates']] for n in coors] cc2 = [[l[:, 1] for l in n['coordinates']] for n in coors] linit = int(round(coors[0]['CoM'][0])) # pick initl layer in which first neuron lies c1 = cc1[0][linit] c2 = cc2[0][linit] source2 = ColumnDataSource(data=dict(c1=c1, c2=c2, cc1=cc1, cc2=cc2)) x = list(range(d2)) y = list(range(d3)) source3 = ColumnDataSource( data=dict(im1=[image_neurons[linit]], im=image_neurons, xx=[x], yy=[y])) callback = CustomJS(args=dict(source=source, source2=source2), code=""" var data = source.get('data'); var f = slider_neuron.get('value')-1; var l = slider_layer.get('value')-1; y = data['y'] y2 = data['y2'] for (i = 0; i < y.length; i++) { y[i] = data['z'][i][f]; y2[i] = data['z2'][i][f]; } var data2 = source2.get('data'); c1 = data2['c1']; c2 = data2['c2']; for (i = 0; i < c1.length; i++) { c1[i] = data2['cc1'][f][l][i]; c2[i] = data2['cc2'][f][l][i]; } source2.trigger('change'); source.trigger('change'); """) callback_layer = CustomJS(args=dict(source=source3, source2=source2), code=""" var f = slider_neuron.get('value')-1; var l = slider_layer.get('value')-1; var im1 = source.get('data')['im1'][0]; for (var i = 0; i < source.get('data')['xx'][0].length; i++) { for (var j = 0; j < source.get('data')['yy'][0].length; j++){ im1[i][j] = source.get('data')['im'][l][i][j]; } } var data2 = source2.get('data'); c1 = data2['c1']; c2 = data2['c2']; for (i = 0; i < c1.length; i++) { c1[i] = data2['cc1'][f][l][i]; c2[i] = data2['cc2'][f][l][i]; } source.trigger('change'); source2.trigger('change'); """) plot = bpl.figure(plot_width=600, plot_height=300) plot.line('x', 'y', source=source, line_width=1, line_alpha=0.6) if denoised_color is not None: plot.line('x', 'y2', source=source, line_width=1, line_alpha=0.6, color=denoised_color) slider = bokeh.models.Slider(start=1, end=Y_r.shape[0], value=1, step=1, title="Neuron Number", callback=callback) xr = Range1d(start=0, end=image_neurons.shape[1] if max_projection else d3) yr = Range1d(start=image_neurons.shape[0] if max_projection else d2, end=0) plot1 = bpl.figure(x_range=xr, y_range=yr, plot_width=300, plot_height=300) if max_projection: plot1.image(image=[image_neurons[::-1, :]], x=0, y=image_neurons.shape[0], dw=image_neurons.shape[1], dh=image_neurons.shape[0], palette=grayp) plot1.patch('c1x', 'c2x', alpha=0.6, color='purple', line_width=2, source=source2) plot1.patch('c1y', 'c2y', alpha=0.6, color='purple', line_width=2, source=source2) plot1.patch('c1z', 'c2z', alpha=0.6, color='purple', line_width=2, source=source2) layout = vform(slider, hplot(plot1, plot)) else: slider_layer = bokeh.models.Slider(start=1, end=d1, value=linit + 1, step=1, title="Layer", callback=callback_layer) callback.args['slider_neuron'] = slider callback.args['slider_layer'] = slider_layer callback_layer.args['slider_neuron'] = slider callback_layer.args['slider_layer'] = slider_layer plot1.image(image='im1', x=[0], y=[d2], dw=[d3], dh=[d2], color_mapper=cmap, source=source3) plot1.patch('c1', 'c2', alpha=0.6, color='purple', line_width=2, source=source2) layout = vform(slider, slider_layer, hplot(plot1, plot)) bpl.show(layout) return Y_r
def get_multi_serie_flag_widget(position_source, data_source, datasets, key_mapper=None, parameter_selector=None, parameter_mapping=None, figure_objs=None): """Return a list of buttons. Each button represents a QC-flag which will be applied when the button is pressed. """ code = """ console.log('get_multi_serie_flag_widget'); var flag_color_mapping = {'A-flag': {'c':'navy', 'flag': '', 'size': 6}, 'B-flag': {'c':'red', 'flag': 'B', 'size': 12}, 'E-flag': {'c':'green', 'flag': 'E', 'size': 12}, 'S-flag': {'c':'orange', 'flag': 'S', 'size': 12}}; // Get data from ColumnDataSource var position_data = position_source.data; // var data = data_source.data; // Set variables attributes var selected_flag = flag; var flag_keys = parameter_mapping[parameter_selector.value]['q_flags'] var size_columns = parameter_mapping[parameter_selector.value]['size_keys'] var color_columns = parameter_mapping[parameter_selector.value]['color_keys'] var flag_value = flag_color_mapping[selected_flag]['flag']; var color_value = flag_color_mapping[selected_flag]['c']; var size_value = flag_color_mapping[selected_flag]['size']; var selected_position_indices = position_source.selected.indices; var selected_key = 0; var value_array = []; var valid_indices = []; for (var i_pos = 0; i_pos < selected_position_indices.length; i_pos++) { var selected_key = position_data['KEY'][selected_position_indices[i_pos]]; var value_array = data_source[selected_key].data['x1']; for (var i = 0; i < value_array.length; i++) { for (var j = 0; j < color_columns.length; j++) { data_source[selected_key].data[color_columns[j]][i] = color_value; data_source[selected_key].data[size_columns[j]][i] = size_value; } } data_source[selected_key].change.emit(); } for (var key in figure_objs) { figure_objs[key].reset.emit(); } // Trigger python callback inorder to save changes to the actual datasets dummy_trigger.glyph.size = {'value': Math.random(), 'units': 'screen'}; dummy_trigger.glyph.change.emit(); console.log('DONE - get_multi_serie_flag_widget'); """ flag_color_mapping = { 'A-flag': { 'c': 'navy', 'flag': '' }, 'B-flag': { 'c': 'red', 'flag': 'B' }, 'E-flag': { 'c': 'green', 'flag': 'E' }, 'S-flag': { 'c': 'orange', 'flag': 'S' } } def callback_py(attr, old, new, flag=None): flag_keys = parameter_mapping[parameter_selector.value].get('q_flags') selected_position = position_source.selected.indices for pos_source_index in selected_position: selected_key = position_source.data['KEY'][pos_source_index] ds_key = key_mapper.get(selected_key) flag_value = flag_color_mapping[flag].get('flag') datasets[ds_key]['data'].loc[:, flag_keys] = flag_value # button_types = default, primary, success, warning or danger button_types = ['primary', 'danger', 'success', 'warning'] flag_list = ['A-flag', 'B-flag', 'E-flag', 'S-flag'] button_list = [] dummy_figure = figure() for flag, b_type in zip(flag_list, button_types): dummy_trigger = dummy_figure.circle(x=[1], y=[2], alpha=0) dummy_trigger.glyph.on_change('size', partial(callback_py, flag=flag)) callback = CustomJS(args={ 'position_source': position_source, 'data_source': data_source, 'figure_objs': figure_objs, 'parameter_mapping': parameter_mapping, 'parameter_selector': parameter_selector, 'flag': flag, 'dummy_trigger': dummy_trigger }, code=code) button = Button(label=flag, width=30, button_type=b_type) button.js_on_event(ButtonClick, callback) button_list.append(button) return row(button_list, sizing_mode="stretch_width")
callback = CustomJS(args=dict(source=source), code=""" var data = source.data; var sel = select.value; var xm = []; var ym = []; var dis = []; x0 = data['x0']; y0 = data['y0']; x1 = data['x1']; y1 = data['y1']; var alfa = alfa.value; var beta = beta.value; var r = r.value; var b = b.value; var k = k.value; if(sel == 'Compartmental model'){ for (i = 0; i < x0.length; i++) { xm[i] = r-r*x0[i]+(1-r)*y0[i]-Math.pow(y0[i],2)-(1+alfa)*x0[i]*y0[i]+x0[i]; ym[i] = -(1+b)*y0[i]+Math.pow(y0[i],2)+(1+alfa-beta)*x0[i]*y0[i]+y0[i] dis[i] = Math.sqrt(Math.pow((xm[i] - x0[i]), 2) + Math.pow((ym[i] - y0[i]), 2)); x1[i] = (xm[i] - x0[i]) / (20 * dis[i]) + x0[i]; y1[i] = (ym[i] - y0[i]) / (20 * dis[i]) + y0[i]; } }else if(sel == 'Compartmental ecd'){ for (i = 0; i < x0.length; i++) { xm[i] = r-r*x0[i]+(1-x0[i]-y0[i]-r)*y0[i]-alfa*k*x0[i]*y0[i]+x0[i]; ym[i] = alfa*k*x0[i]*y0[i]-(x0[i]+y0[i])*b*y0[i]-(x0[i]+y0[i])*(1-b)*beta*k*x0[i]*y0[i]-y0[i]*(1-x0[i]-y0[i])+y0[i] dis[i] = Math.sqrt(Math.pow((xm[i] - x0[i]), 2) + Math.pow((ym[i] - y0[i]), 2)); x1[i] = (xm[i] - x0[i]) / (20 * dis[i]) + x0[i]; y1[i] = (ym[i] - y0[i]) / (20 * dis[i]) + y0[i]; } }else{ for (i = 0; i < x0.length; i++) { xm[i] = r + (Math.pow((1 - alfa * y0[i]), k) - r) * x0[i] + (1 - r - x0[i] - y0[i]) * y0[i]; ym[i] = (1 - Math.pow((1 - alfa * y0[i]),k)) * x0[i] + ((x0[i] + y0[i]) * (1 - b) * (Math.pow((1 - beta * x0[i]),k))) * y0[i]; dis[i] = Math.sqrt(Math.pow((xm[i] - x0[i]), 2) + Math.pow((ym[i] - y0[i]), 2)); x1[i] = (xm[i] - x0[i]) / (20 * dis[i]) + x0[i]; y1[i] = (ym[i] - y0[i]) / (20 * dis[i]) + y0[i]; } } source.trigger('change'); """)
title="Select Here") p.circle('x', 'y', color='color', size=8, source=s, alpha=0.4) s2 = ColumnDataSource(data=dict(ym=[0.5, 0.5])) p.line(x=[0, 1], y='ym', color="orange", line_width=5, alpha=0.6, source=s2) s.callback = CustomJS(args=dict(s2=s2), code=""" var inds = cb_obj.get('selected')['1d'].indices; var d = cb_obj.get('data'); var ym = 0 if (inds.length == 0) { return; } for (i = 0; i < d['color'].length; i++) { d['color'][i] = "navy" } for (i = 0; i < inds.length; i++) { d['color'][inds[i]] = "firebrick" ym += d['y'][inds[i]] } ym /= inds.length s2.get('data')['ym'] = [ym, ym] cb_obj.trigger('change'); s2.trigger('change'); """) show(p)
def interactive_hist(adata, keys=['n_counts', 'n_genes'], bins='auto', max_bins=100, groups=None, fill_alpha=0.4, palette=None, display_all=True, tools='pan, reset, wheel_zoom, save', legend_loc='top_right', plot_width=None, plot_height=None, *args, **kwargs): """Utility function to plot distributions with variable number of bins. Params -------- adata: AnnData object annotated data object keys: list(str), optional (default: `['n_counts', 'n_genes']`) keys in `adata.obs` or `adata.var` where the distibutions are stored bins: int; str, optional (default: `auto`) number of bins used for plotting or str from numpy.histogram max_bins: int, optional (default: `1000`) maximum number of bins possible groups: list(str), (default: `None`) keys in `adata.obs.obs_keys()`, groups by all possible combinations of values, e.g. for 3 plates and 2 time points, we would create total of 6 groups fill_alpha: float[0.0, 1.0], (default: `0.4`) alpha channel of the fill color palette: list(str), optional (default: `None`) palette to use display_all: bool, optional (default: `True`) display the statistics for all data tools: str, optional (default: `'pan,reset, wheel_zoom, save'`) palette of interactive tools for the user legend_loc: str, (default: `'top_right'`) position of the legend legend_loc: str, default(`'top_left'`) position of the legend plot_width: int, optional (default: `None`) width of the plot plot_height: int, optional (default: `None`) height of the plot *args, **kwargs: arguments, keyword arguments addition argument to bokeh.models.figure Returns -------- None """ if max_bins < 1: raise ValueError(f'`max_bins` must >= 1') palette = Set1[9] + Set2[8] + Set3[12] if palette is None else palette # check the input for key in keys: if key not in adata.obs.keys() and \ key not in adata.var.keys() and \ key not in adata.var_names: raise ValueError(f'The key `{key}` does not exist in `adata.obs`, `adata.var` or `adata.var_names`.') def _create_adata_groups(): if groups is None: return [adata], [('all',)] combs = list(product(*[set(adata.obs[g]) for g in groups])) adatas= [adata[reduce(lambda l, r: l & r, (adata.obs[k] == v for k, v in zip(groups, vals)), True)] for vals in combs] + [adata] if display_all: combs += [('all',)] adatas += [adata] return adatas, combs # group_v_combs contains the value combinations ad_gs = _create_adata_groups() cols = [] for key in keys: callbacks = [] fig = figure(*args, tools=tools, **kwargs) slider = Slider(start=1, end=max_bins, value=0, step=1, title='Bins') plots = [] for j, (ad, group_vs) in enumerate(filter(lambda ad_g: ad_g[0].n_obs > 0, zip(*ad_gs))): if key in ad.obs.keys(): orig = ad.obs[key] hist, edges = np.histogram(orig, density=True, bins=bins) elif key in ad.var.keys(): orig = ad.var[key] hist, edges = np.histogram(orig, density=True, bins=bins) else: orig = ad[:, key].X hist, edges = np.histogram(orig, density=True, bins=bins) slider.value = len(hist) # original data, used for recalculation of histogram in JS code orig = ColumnDataSource(data=dict(values=orig)) # data that we update in JS code source = ColumnDataSource(data=dict(hist=hist, l_edges=edges[:-1], r_edges=edges[1:])) legend = ', '.join(': '.join(map(str, gv)) for gv in zip(groups, group_vs)) \ if groups is not None else 'all' # create figure p = fig.quad(source=source, top='hist', bottom=0, left='l_edges', right='r_edges', fill_color=palette[j], legend=legend if legend_loc is not None else None, muted_alpha=0, line_color="#555555", fill_alpha=fill_alpha) # create callback and slider callback = CustomJS(args=dict(source=source, orig=orig), code=_inter_hist_js_code) callback.args['bins'] = slider callbacks.append(callback) # add the current plot so that we can set it # visible/invisible in JS code plots.append(p) # slider now updates all values slider.js_on_change('value', *callbacks) button = Button(label='Toggle', button_type='primary') button.callback = CustomJS( args={'plots': plots}, code=''' for (var i = 0; i < plots.length; i++) { plots[i].muted = !plots[i].muted; } ''' ) if legend_loc is not None: fig.legend.location = legend_loc fig.legend.click_policy = 'mute' fig.xaxis.axis_label = key fig.yaxis.axis_label = 'normalized frequency' _set_plot_wh(fig, plot_width, plot_height) cols.append(column(slider, button, fig)) # transform list of pairs of figures and sliders into list of lists, where # each sublist has length <= 2 # note that bokeh does not like np.arrays grid = list(map(list, np.array_split(cols, np.ceil(len(cols) / 2)))) show(layout(children=grid, sizing_mode='fixed', ncols=2))
options = ['Single', 'Joint', 'Head of Household'] scr1 = ColumnDataSource(get_csv_data(options[0])) scr2 = ColumnDataSource(get_csv_data(options[1])) scr3 = ColumnDataSource(get_csv_data(options[2])) ref_source = ColumnDataSource(get_csv_data(options[0])) sources = dict(Single=scr1, Joint=scr2, Head=scr3) plot = make_a_plot(ref_source) callback = CustomJS(args=sources, code=""" var input = select.value; var data_1 = Single.data; var data_2 = Joint.data; var data_3 = Head.data; if (input == "Joint"){ ref_source.data = data_2; } else if (input == "Head of Household"){ ref_source.data = data_3; } ref_source.trigger('change'); if (input == "Single") { ref_source.data = data_1; } ref_source.trigger('change'); """) select = Select(title='Filing Status', value='Single', options=options, callback=callback) callback.args['select'] = select callback.args['ref_source'] = ref_source grid = column(select, plot) output_file("index_landscape.html") show(grid)
def plot_linechart_areas_short_term_migration(): wb = openpyxl.load_workbook( 'data/Short term migration.xlsx') # Import datasets ws = wb.get_sheet_by_name('Data') x = [] areas = [] y1,y2,y3,y4,y5,y6,y7,y8,y9,y10,y11,y12,y13,y14,y15,y16,y17,y18,y19,y20,y21,y22,y23,y24,y25,y26,y27,y28,y29,y30,y31,y32,y33,y34 = [],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[] #Rearrange data for column in range(2, 12): areas.append(ws.cell(row=row, column=1).value) x.append(ws.cell(row=5, column=column).value) y1.append(ws.cell(row=6, column=column).value) y2.append(ws.cell(row=7, column=column).value) y3.append(ws.cell(row=8, column=column).value) y4.append(ws.cell(row=9, column=column).value) y5.append(ws.cell(row=10, column=column).value) y6.append(ws.cell(row=11, column=column).value) y7.append(ws.cell(row=12, column=column).value) y8.append(ws.cell(row=13, column=column).value) y9.append(ws.cell(row=14, column=column).value) y10.append(ws.cell(row=15, column=column).value) y11.append(ws.cell(row=16, column=column).value) y12.append(ws.cell(row=17, column=column).value) y13.append(ws.cell(row=18, column=column).value) y14.append(ws.cell(row=19, column=column).value) y15.append(ws.cell(row=20, column=column).value) y16.append(ws.cell(row=21, column=column).value) y17.append(ws.cell(row=22, column=column).value) y18.append(ws.cell(row=23, column=column).value) y19.append(ws.cell(row=24, column=column).value) y20.append(ws.cell(row=25, column=column).value) y21.append(ws.cell(row=26, column=column).value) y22.append(ws.cell(row=27, column=column).value) y23.append(ws.cell(row=28, column=column).value) y24.append(ws.cell(row=29, column=column).value) y25.append(ws.cell(row=30, column=column).value) y26.append(ws.cell(row=31, column=column).value) y27.append(ws.cell(row=32, column=column).value) y28.append(ws.cell(row=33, column=column).value) y29.append(ws.cell(row=34, column=column).value) y30.append(ws.cell(row=35, column=column).value) y31.append(ws.cell(row=36, column=column).value) y32.append(ws.cell(row=37, column=column).value) y33.append(ws.cell(row=38, column=column).value) y34.append(ws.cell(row=39, column=column).value) p_areas = figure( plot_width=1000, plot_height=500, x_axis_label="dates", y_axis_label="Migration population", y_range=(0, 7000), tools="hover,pan,box_zoom,save,reset,undo,zoom_in,zoom_out,wheel_zoom", title="Areas of London short-term migration") #Create a new figure p2 = p_areas.line(x=x, y=y2, line_width=1, color="#000003", legend="City of London") #draw a line chart p3 = p_areas.line(x=x, y=y3, line_width=1, color="#140D35", legend="Barking and Dagenham") #draw a line chart p4 = p_areas.line(x=x, y=y4, line_width=1, color="#3B0F6F", legend="Barnet") #draw a line chart p5 = p_areas.line(x=x, y=y5, line_width=1, color="#63197F", legend="Bexley") #draw a line chart p6 = p_areas.line(x=x, y=y6, line_width=1, color="#8C2980", legend="Brent") #draw a line chart p7 = p_areas.line(x=x, y=y7, line_width=1, color="#B53679", legend="Bromley") #draw a line chart p8 = p_areas.line(x=x, y=y8, line_width=1, color="#DD4968", legend="Camden") #draw a line chart p9 = p_areas.line(x=x, y=y9, line_width=1, color="#F66E5B", legend="Croydon") #draw a line chart p10 = p_areas.line(x=x, y=y10, line_width=1, color="#FD9F6C", legend="Ealing") #draw a line chart p11 = p_areas.line(x=x, y=y11, line_width=1, color="#FDCD90", legend="Enfield") #draw a line chart p12 = p_areas.line(x=x, y=y12, line_width=1, color="#FBFCBF", legend="Greenwich") #draw a line chart p13 = p_areas.line(x=x, y=y13, line_width=1, color="#a6cee3", legend="Hackney") #draw a line chart p14 = p_areas.line(x=x, y=y14, line_width=1, color="#1f78b4", legend="Hammersmith and Fulham") #draw a line chart p15 = p_areas.line(x=x, y=y15, line_width=1, color="#b2df8a", legend="Haringey") #draw a line chart p16 = p_areas.line(x=x, y=y16, line_width=1, color="#33a02c", legend="Harrow") #draw a line chart p17 = p_areas.line(x=x, y=y17, line_width=1, color="#fb9a99", legend="Havering") #draw a line chart p18 = p_areas.line(x=x, y=y18, line_width=1, color="#e31a1c", legend="Hillingdon") #draw a line chart p19 = p_areas.line(x=x, y=y19, line_width=1, color="#fdbf6f", legend="Hounslow") #draw a line chart p20 = p_areas.line(x=x, y=y20, line_width=1, color="#ff7f00", legend="Islington") #draw a line chart p21 = p_areas.line(x=x, y=y21, line_width=1, color="#cab2d6", legend="Kensington and Chelsea") #draw a line chart p22 = p_areas.line(x=x, y=y22, line_width=1, color="#6a3d9a", legend="Kingston upon Thames") #draw a line chart p23 = p_areas.line(x=x, y=y23, line_width=1, color="#ffff99", legend="Lambeth") #draw a line chart p24 = p_areas.line(x=x, y=y24, line_width=1, color="#b15928", legend="Lewisham") #draw a line chart p25 = p_areas.line(x=x, y=y25, line_width=1, color="#e41a1c", legend="Merton") #draw a line chart p26 = p_areas.line(x=x, y=y26, line_width=1, color="#377eb8", legend="Newham") #draw a line chart p27 = p_areas.line(x=x, y=y27, line_width=1, color="#4daf4a", legend="Redbridge") #draw a line chart p28 = p_areas.line(x=x, y=y28, line_width=1, color="#984ea3", legend="Richmond upon Thames") #draw a line chart p29 = p_areas.line(x=x, y=y29, line_width=1, color="#ff7f00", legend="Southwark") #draw a line chart p30 = p_areas.line(x=x, y=y30, line_width=1, color="#ffff33", legend="Sutton") #draw a line chart p31 = p_areas.line(x=x, y=y31, line_width=1, color="#a65628", legend="Tower Hamlets") #draw a line chart p32 = p_areas.line(x=x, y=y32, line_width=1, color="#f781bf", legend="Waltham Forest") #draw a line chart p33 = p_areas.line(x=x, y=y33, line_width=1, color="#410967", legend="Wandsworth") #draw a line chart p34 = p_areas.line(x=x, y=y34, line_width=1, color="#6A176E", legend="Westminster") #draw a line chart #Set legend location adn legemd orientation p_areas.legend.location = "top_left" p_areas.legend.orientation = "horizontal" #Set callback function after click checkboxes display_event = CustomJS(code=""" p2.visible = false; p3.visible = false; p4.visible = false; p5.visible = false; p6.visible = false; p7.visible = false; p8.visible = false; p9.visible = false; p10.visible = false; p11.visible = false; p12.visible = false; p13.visible = false; p14.visible = false; p15.visible = false; p16.visible = false; p17.visible = false; p18.visible = false; p19.visible = false; p20.visible = false; p21.visible = false; p22.visible = false; p23.visible = false; p24.visible = false; p25.visible = false; p26.visible = false; p27.visible = false; p28.visible = false; p29.visible = false; p30.visible = false; p31.visible = false; p32.visible = false; p33.visible = false; p34.visible = false; if(cb_obj.active.includes(0)){ p2.visible = true; } if (cb_obj.active.includes(1)){ p3.visible = true; } if (cb_obj.active.includes(2)){ p4.visible = true; } if (cb_obj.active.includes(3)){ p5.visible = true; } if (cb_obj.active.includes(4)){ p6.visible = true; } if (cb_obj.active.includes(5)){ p7.visible = true; } if (cb_obj.active.includes(6)){ p8.visible = true; } if (cb_obj.active.includes(7)){ p9.visible = true; } if (cb_obj.active.includes(8)){ p10.visible = true; } if (cb_obj.active.includes(9)){ p11.visible = true; } if (cb_obj.active.includes(10)){ p12.visible = true; } if (cb_obj.active.includes(11)){ p13.visible = true; } if (cb_obj.active.includes(12)){ p14.visible = true; } if (cb_obj.active.includes(13)){ p15.visible = true; } if (cb_obj.active.includes(14)){ p16.visible = true; } if (cb_obj.active.includes(15)){ p17.visible = true; } if (cb_obj.active.includes(16)){ p18.visible = true; } if (cb_obj.active.includes(17)){ p19.visible = true; } if (cb_obj.active.includes(18)){ p20.visible = true; } if (cb_obj.active.includes(19)){ p21.visible = true; } if (cb_obj.active.includes(20)){ p22.visible = true; } if (cb_obj.active.includes(21)){ p23.visible = true; } if (cb_obj.active.includes(22)){ p24.visible = true; } if (cb_obj.active.includes(23)){ p25.visible = true; } if (cb_obj.active.includes(24)){ p26.visible = true; } if (cb_obj.active.includes(25)){ p27.visible = true; } if (cb_obj.active.includes(26)){ p28.visible = true; } if (cb_obj.active.includes(27)){ p29.visible = true; } if (cb_obj.active.includes(28)){ p30.visible = true; } if (cb_obj.active.includes(29)){ p31.visible = true; } if (cb_obj.active.includes(30)){ p32.visible = true; } if (cb_obj.active.includes(31)){ p33.visible = true; } if (cb_obj.active.includes(32)){ p34.visible = true; } """, args={ 'p2': p2, 'p3': p3, 'p4': p4, 'p5': p5, 'p6': p6, 'p7': p7, 'p8': p8, 'p9': p9, 'p10': p10, 'p11': p11, 'p12': p12, 'p13': p13, 'p14': p14, 'p15': p15, 'p16': p16, 'p17': p17, 'p18': p18, 'p19': p19, 'p20': p20, 'p21': p21, 'p22': p22, 'p23': p23, 'p24': p24, 'p25': p25, 'p26': p26, 'p27': p27, 'p28': p28, 'p29': p29, 'p30': p30, 'p31': p31, 'p32': p32, 'p33': p33, 'p34': p34 }) #Set widgets checkboxes selection_box = CheckboxGroup(labels=[ "City of London", "Barking and Dagenham", "Barnet", "Bexley", "Brent", "Bromley", "Camden", "Croydon", "Ealing", "Enfield", "Greenwich", "Hackney", "Hammersmith and Fulham", "Haringey", "Harrow", "Havering", "Hillingdon", "Hounslow", "Islington", "Kensington and Chelsea", "Kingston upon Thames", "Lambeth", "Lewisham", "Merton", "Newham", "Redbridge", "Richmond upon Thames", "Southwark", "Sutton", "Tower Hamlets", "Waltham Forest", "Wandsworth", "Westminster" ], active=[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33 ]) selection_box.js_on_click(display_event) row_1 = [p_areas, selection_box] #Make selection boxes located besides line chart return row_1
# Add the hover (only against the circle and not other plot elements) tooltips = "@index" plot.add_tools(HoverTool(tooltips=tooltips, renderers=[circle_renderer])) plot.add_layout(Legend(items=[LegendItem(label=field('region'), renderers=[circle_renderer])])) # Add the slider code = """ var year = slider.value, sources = %s, new_source_data = sources[year].data; renderer_source.data = new_source_data; text_source.data = {'year': [String(year)]}; """ % js_source_array callback = CustomJS(args=sources, code=code) slider = Slider(start=years[0], end=years[-1], value=1, step=1, title="Year", callback=callback, name='testy') callback.args["renderer_source"] = renderer_source callback.args["slider"] = slider callback.args["text_source"] = text_source # Stick the plot and the slider together layout = column(plot, slider) # Open our custom template with open('gapminder_template.jinja', 'r') as f: template = Template(f.read()) # Use inline resources, render the html and open js_resources = JSResources(mode='inline')
def change_button_type_callback(button=None, btype=None): """Return a CustomJS callback.""" code = """ button.button_type = btype; """ return CustomJS(args={'button': button, 'btype': btype}, code=code)