def colorbar(fig, cmap, title=None): ''' Adds a colorbar to a bokeh figure. fig: the figure title: title for colorbar cmap: name of desired bokeh or mpl colormap ''' from bokeh.models import LinearColorMapper from bokeh.models.annotations import ColorBar data = get_image_data(fig) color_mapper = LinearColorMapper(low=data.min(), high=data.max(), palette=choose_cmap(cmap)) cb = ColorBar(color_mapper=color_mapper, location=(0,0), orientation='vertical', padding=20, margin=0, title=title) cb.major_label_text_font_size = '12pt' cb.major_label_text_align = 'left' fig.add_layout(cb, 'left') # 'right' make plot squished with widgets return cb
def colorbar(fig, cmap, title=None): ''' Adds a colorbar to a bokeh figure. fig: the figure title: title for colorbar cmap: name of desired bokeh or mpl colormap ''' from bokeh.models import LinearColorMapper from bokeh.models.annotations import ColorBar data = get_image_data(fig) color_mapper = LinearColorMapper(low=data.min(), high=data.max(), palette=choose_cmap(cmap)) cb = ColorBar(color_mapper=color_mapper, location=(0, 0), orientation='vertical', padding=20, margin=0, title=title) cb.major_label_text_font_size = '12pt' cb.major_label_text_align = 'left' fig.add_layout(cb, 'left') # 'right' make plot squished with widgets return cb
def test_ColorBar(): color_bar = ColorBar() assert color_bar.plot is None assert color_bar.location == 'top_right' assert color_bar.orientation == 'vertical' assert color_bar.height == 'auto' assert color_bar.width == 'auto' assert color_bar.scale_alpha == 1.0 assert color_bar.title is None assert color_bar.title_standoff == 2 assert isinstance(color_bar.ticker, BasicTicker) assert isinstance(color_bar.formatter, BasicTickFormatter) assert color_bar.color_mapper is None assert color_bar.margin == 30 assert color_bar.padding == 10 assert color_bar.label_standoff == 5 assert color_bar.major_tick_in == 5 assert color_bar.major_tick_out == 0 assert color_bar.minor_tick_in == 0 assert color_bar.minor_tick_out == 0 check_text_properties(color_bar, "title_", "10pt", "bottom", "italic") check_text_properties(color_bar, "major_label_", "8pt", "middle", "normal", "center") check_line_properties(color_bar, "major_tick_", "#ffffff") check_line_properties(color_bar, "minor_tick_", None) check_line_properties(color_bar, "bar_", None) check_line_properties(color_bar, "border_", None) check_fill_properties(color_bar, "background_", "#ffffff", 0.95) check_properties_existence(color_bar, [ "plot", "level", "visible", "location", "orientation", "height", "width", "scale_alpha", "title", "title_standoff", "ticker", "formatter", "color_mapper", "margin", "padding", "label_standoff", "major_tick_in", "major_tick_out", "minor_tick_in", "minor_tick_out"], prefix('title_', TEXT), prefix('major_label_', TEXT), prefix('major_tick_', LINE), prefix('minor_tick_', LINE), prefix('bar_', LINE), prefix('border_', LINE), prefix('background_', FILL) )
def __init__(self, m): if debug: print("Initializing new View object...") self.curdoc = curdoc # reference to the current Bokeh document self.m = m self.firstrun = True self.subject_select = Select(title="Subjects:", value=sorted_xs[0], options=sorted_xs, width=200) self.model_select = Select(title="Model:", value=selected_model, options=stored_models, width=200) self.slice_slider_frontal = Slider(start=1, end=m.subj_bg.shape[2], value=50, step=1, title="Coronal slice", width=200) self.slice_slider_axial = Slider(start=1, end=m.subj_bg.shape[0], value=50, step=1, title="Axial slice", width=200) self.slice_slider_sagittal = Slider(start=1, end=m.subj_bg.shape[1], value=50, step=1, title="Sagittal slice", width=200) self.threshold_slider = Slider(start=0, end=1, value=0.4, step=0.05, title="Relevance threshold", width=200) self.clustersize_slider = Slider(start=0, end=250, value=50, step=10, title="Minimum cluster size", width=200) self.transparency_slider = Slider(start=0, end=1, value=0.3, step=0.05, title="Overlay transparency", width=200) # Initialize the figures: self.guide_frontal = figure(plot_width=208, plot_height=70, title='Relevance>threshold per slice:', toolbar_location=None, active_drag=None, active_inspect=None, active_scroll=None, active_tap=None) self.guide_frontal.title.text_font = 'arial' self.guide_frontal.title.text_font_style = 'normal' # guide_frontal.title.text_font_size = '10pt' self.guide_frontal.axis.visible = False self.guide_frontal.x_range.range_padding = 0 self.guide_frontal.y_range.range_padding = 0 self.guide_axial = figure(plot_width=208, plot_height=70, title='Relevance>threshold per slice:', toolbar_location=None, active_drag=None, active_inspect=None, active_scroll=None, active_tap=None) self.guide_axial.title.text_font = 'arial' self.guide_axial.title.text_font_style = 'normal' # guide_axial.title.text_font_size = '10pt' self.guide_axial.axis.visible = False self.guide_axial.x_range.range_padding = 0 self.guide_axial.y_range.range_padding = 0 self.guide_sagittal = figure(plot_width=208, plot_height=70, title='Relevance>threshold per slice:', toolbar_location=None, active_drag=None, active_inspect=None, active_scroll=None, active_tap=None) self.guide_sagittal.title.text_font = 'arial' self.guide_sagittal.title.text_font_style = 'normal' # guide_sagittal.title.text_font_size = '10pt' self.guide_sagittal.axis.visible = False self.guide_sagittal.x_range.range_padding = 0 self.guide_sagittal.y_range.range_padding = 0 self.clusthist = figure(plot_width=208, plot_height=70, title='Distribution of cluster sizes:', toolbar_location=None, active_drag=None, active_inspect=None, active_scroll=None, active_tap=None) self.clusthist.title.text_font = 'arial' self.clusthist.title.text_font_style = 'normal' self.clusthist.axis.visible = False self.clusthist.x_range.range_padding = 0 self.clusthist.y_range.range_padding = 0 self.p_frontal = figure( plot_width=int(np.floor(m.subj_bg.shape[1] * scale_factor)), plot_height=int(np.floor(m.subj_bg.shape[0] * scale_factor)), title='', toolbar_location=None, active_drag=None, active_inspect=None, active_scroll=None, active_tap=None) self.p_frontal.axis.visible = False self.p_frontal.x_range.range_padding = 0 self.p_frontal.y_range.range_padding = 0 self.flip_frontal_view = Toggle(label='Flip L/R orientation', button_type='default', width=200, active=flip_left_right_in_frontal_plot) self.orientation_label_shown_left = Label( text='R' if flip_left_right_in_frontal_plot else 'L', render_mode='css', x=3, y=self.m.subj_bg.shape[0] - 13, text_align='left', text_color='white', text_font_size='20px', border_line_color='white', border_line_alpha=0, background_fill_color='black', background_fill_alpha=0, level='overlay', visible=True) self.orientation_label_shown_right = Label( text='L' if flip_left_right_in_frontal_plot else 'R', render_mode='css', x=self.m.subj_bg.shape[1] - 3, y=self.m.subj_bg.shape[0] - 13, text_align='right', text_color='white', text_font_size='20px', border_line_color='white', border_line_alpha=0, background_fill_color='black', background_fill_alpha=0, level='overlay', visible=True) self.p_frontal.add_layout(self.orientation_label_shown_left, 'center') self.p_frontal.add_layout(self.orientation_label_shown_right, 'center') # The vertical crosshair line on the frontal view that indicates the selected sagittal slice. self.frontal_crosshair_from_sagittal = Span( location=self.slice_slider_sagittal.value - 1, dimension='height', line_color='green', line_width=1, render_mode="css") # The horizontal crosshair line on the frontal view that indicates the selected axial slice. self.frontal_crosshair_from_axial = Span( location=self.slice_slider_axial.value - 1, dimension='width', line_color='green', line_width=1, render_mode="css") self.p_frontal.add_layout(self.frontal_crosshair_from_sagittal) self.p_frontal.add_layout(self.frontal_crosshair_from_axial) self.p_axial = figure( plot_width=int(np.floor(m.subj_bg.shape[1] * scale_factor)), plot_height=int(np.floor(m.subj_bg.shape[2] * scale_factor)), title='', toolbar_location=None, active_drag=None, active_inspect=None, active_scroll=None, active_tap=None) self.p_axial.axis.visible = False self.p_axial.x_range.range_padding = 0 self.p_axial.y_range.range_padding = 0 self.axial_crosshair_from_sagittal = Span( location=self.slice_slider_sagittal.value - 1, dimension='height', line_color='green', line_width=1, render_mode="css") self.axial_crosshair_from_frontal = Span( location=self.slice_slider_frontal.end - self.slice_slider_frontal.value + 1, dimension='width', line_color='green', line_width=1, render_mode="css") self.p_axial.add_layout(self.axial_crosshair_from_sagittal) self.p_axial.add_layout(self.axial_crosshair_from_frontal) self.p_sagittal = figure( plot_width=int(np.floor(m.subj_bg.shape[2] * scale_factor)), plot_height=int(np.floor(m.subj_bg.shape[0] * scale_factor)), title='', toolbar_location=None, active_drag=None, active_inspect=None, active_scroll=None, active_tap=None) self.p_sagittal.axis.visible = False self.p_sagittal.x_range.range_padding = 0 self.p_sagittal.y_range.range_padding = 0 self.sagittal_crosshair_from_frontal = Span( location=self.slice_slider_frontal.value - 1, dimension='height', line_color='green', line_width=1, render_mode="css") self.sagittal_crosshair_from_axial = Span( location=self.slice_slider_axial.end - self.slice_slider_axial.value - 1, dimension='width', line_color='green', line_width=1, render_mode="css") self.p_sagittal.add_layout(self.sagittal_crosshair_from_frontal) self.p_sagittal.add_layout(self.sagittal_crosshair_from_axial) self.loading_label = Label(text='Processing scan...', render_mode='css', x=self.m.subj_bg.shape[1] // 2, y=self.m.subj_bg.shape[2] // 2, text_align='center', text_color='white', text_font_size='25px', text_font_style='italic', border_line_color='white', border_line_alpha=1.0, background_fill_color='black', background_fill_alpha=0.5, level='overlay', visible=False) self.p_axial.add_layout(self.loading_label) self.render_backround() # create empty plot objects with empty ("fully transparent") ColumnDataSources): self.frontal_zeros = np.zeros_like( np.flipud(self.bg[:, :, self.slice_slider_frontal.value - 1])) self.axial_zeros = np.zeros_like( np.rot90(self.bg[self.m.subj_bg.shape[0] - self.slice_slider_axial.value, :, :])) self.sagittal_zeros = np.zeros_like( np.flipud( self. bg[:, self.slice_slider_sagittal.end - self.slice_slider_sagittal.value if self.flip_frontal_view. active else self.slice_slider_sagittal.value - 1, :])) self.frontal_zeros[True] = 255 # value for a fully transparent pixel self.axial_zeros[True] = 255 self.sagittal_zeros[True] = 255 self.frontal_data = ColumnDataSource(data=dict( image=[self.frontal_zeros, self.frontal_zeros, self.frontal_zeros], x=[0, 0, 0], y=[0, 0, 0])) self.axial_data = ColumnDataSource(data=dict( image=[self.axial_zeros, self.axial_zeros, self.axial_zeros], x=[0, 0, 0], y=[0, 0, 0])) self.sagittal_data = ColumnDataSource(data=dict(image=[ self.sagittal_zeros, self.sagittal_zeros, self.sagittal_zeros ], x=[0, 0, 0], y=[0, 0, 0])) self.p_frontal.image_rgba(image="image", x="x", y="y", dw=self.frontal_zeros.shape[1], dh=self.frontal_zeros.shape[0], source=self.frontal_data) self.p_axial.image_rgba(image="image", x="x", y="y", dw=self.axial_zeros.shape[1], dh=self.axial_zeros.shape[0], source=self.axial_data) self.p_sagittal.image_rgba(image="image", x="x", y="y", dw=self.sagittal_zeros.shape[1], dh=self.sagittal_zeros.shape[0], source=self.sagittal_data) self.toggle_transparency = Toggle(label='Hide relevance overlay', button_type='default', width=200) self.toggle_regions = Toggle(label='Show outline of atlas region', button_type='default', width=200) self.region_ID = get_region_id( self.slice_slider_axial.value - 1, self.slice_slider_sagittal.end - self.slice_slider_sagittal.value if self.flip_frontal_view.active else self.slice_slider_sagittal.value - 1, self.slice_slider_frontal.value - 1) self.selected_region = get_region_name( self.slice_slider_axial.value - 1, self.slice_slider_sagittal.end - self.slice_slider_sagittal.value if self.flip_frontal_view.active else self.slice_slider_sagittal.value - 1, self.slice_slider_frontal.value - 1) self.region_div = Div(text="Region: " + self.selected_region, sizing_mode="stretch_both", css_classes=["region_divs"]) self.cluster_size_div = Div( text="Cluster Size: " + "0", css_classes=[ "cluster_divs" ]) # initialize with 0 because clust_labelimg does not exist yet self.cluster_mean_div = Div(text="Mean Intensity: " + "0", css_classes=["cluster_divs"]) self.cluster_peak_div = Div(text="Peak Intensity: " + "0", css_classes=["cluster_divs"]) # see InteractiveVis/static/ for default formatting/style definitions self.age_spinner = Spinner( title="Age:", placeholder="years", mode="int", low=55, high=99, width=int(np.floor(m.subj_bg.shape[1] * scale_factor) // 2 - 10), disabled=True) #no subject selected at time of initialization self.sex_select = Select( title="Sex:", value="N/A", options=["male", "female", "N/A"], width=int(np.floor(m.subj_bg.shape[1] * scale_factor) // 2 - 10), disabled=True) self.tiv_spinner = Spinner( title="TIV:", placeholder="cm³", mode="float", low=1000, high=2100, width=int(np.floor(m.subj_bg.shape[1] * scale_factor) // 2 - 10), disabled=True) self.field_strength_select = Select( title="Field Strength [T]:", value="1.5", options=["1.5", "3.0"], width=int(np.floor(m.subj_bg.shape[1] * scale_factor) // 2 - 10), disabled=True) # Empty dummy figure to add ColorBar to, because annotations (like a ColorBar) must have a # parent figure in Bokeh: self.p_color_bar = figure( plot_width=100, plot_height=int(np.floor(m.subj_bg.shape[0] * scale_factor)), title='', toolbar_location=None, active_drag=None, active_inspect=None, active_scroll=None, active_tap=None, outline_line_alpha=0.0) self.p_color_bar.axis.visible = False self.p_color_bar.x_range.range_padding = 0 self.p_color_bar.y_range.range_padding = 0 self.color_mapper = LinearColorMapper(palette=color_palette, low=-1, high=1) self.color_bar = ColorBar(color_mapper=self.color_mapper, title="Relevance") self.p_color_bar.add_layout(self.color_bar) self.scan_upload = FileInput(accept='.nii.gz, .nii') self.residualize_button = Button( label="Start residualization and view scan", disabled=True) def dummy(): pass self.residualize_button.on_click( dummy ) # TODO: remove this once on_click is working when setting callback only from the model class (bug in Bokeh 2.2.x ?) # Initialize column layout: self.layout = row( column( self.subject_select, self.model_select, Spacer(height=40, width=200, sizing_mode='scale_width'), self.threshold_slider, self.clusthist, self.clustersize_slider, self.transparency_slider, self.toggle_transparency, self.toggle_regions, self.region_div, column(self.cluster_size_div, self.cluster_mean_div, self.cluster_peak_div)), column( row(self.age_spinner, self.sex_select, self.tiv_spinner, self.field_strength_select, self.scan_upload, css_classes=["subject_divs"]), row(self.residualize_button), row( column(self.p_frontal, self.slice_slider_frontal, self.guide_frontal, self.flip_frontal_view), column(self.p_axial, self.slice_slider_axial, self.guide_axial), column(self.p_sagittal, self.slice_slider_sagittal, self.guide_sagittal), column(self.p_color_bar)))) self.clust_hist_bins = list(range( 0, 250 + 1, 10)) # list from (0, 10, .., 250); range max is slider_max_size+1
def interactive_plot_3d(rw_data, raw_data, subject, a, b, c): # bokeh serve --show 20190430_rw_newsim_parameter.py similarity_data = compute_similarity_maps(raw_data, a, b, c) data = rw_data data2 = similarity_data source = ColumnDataSource(data=dict(image=[np.flipud(data[:, :, 0].T)])) color_mapper = LinearColorMapper(palette="Greys256", low=0.0, high=1.0) plot = figure(title="RW aorta segmentation") plot.image(image='image', x=0, y=0, dw=data.shape[0], dh=data.shape[1], source=source, color_mapper=color_mapper) source_dict = {} name_dict = { 1: 'A', 2: 'A_a', 3: 'exp(-A_a)', 4: 'B', 5: 'B_b', 6: 'exp(-B_b)', 7: 'C', 8: 'C_c', 9: 'exp(-C_c)' } plot_dict = {} color_mapper_dict = {} colorbar_dict = {} # for x in name_dict: source_dict["source{0}".format(x)] = ColumnDataSource(data=dict( image=[np.flipud(data2[0][x - 1][:, :, 0].T)])) plot_dict['plot{0}'.format(x)] = figure( title="Similarity maps {0}".format(name_dict[x]), height=300, match_aspect=True) color_mapper_dict['color_mapper{0}'.format(x)] = LinearColorMapper( palette="Inferno256", low=min(np.amin(data2[0][x - 1]), np.amin(data2[1][x - 1]), np.amin(data2[2][x - 1])), high=max(np.amax(data2[0][x - 1]), np.amax(data2[1][x - 1]), np.amax(data2[2][x - 1]))) colorbar_dict['colorbar{0}'.format(x)] = ColorBar( color_mapper=color_mapper_dict["color_mapper{0}".format(x)], location=(0, 0)) plot_dict["plot{0}".format(x)].image( image='image', x=0, y=0, dw=data2[0][x - 1].shape[0], dh=data2[0][x - 1].shape[1], source=source_dict["source{0}".format(x)], color_mapper=color_mapper_dict["color_mapper{0}".format(x)]) plot_dict["plot{0}".format(x)].add_layout( colorbar_dict["colorbar{0}".format(x)], 'right') gt_data = load_gt_data(subject=subject) gt_data = np.rot90(gt_data, 1, (0, 1)) source10 = ColumnDataSource(data=dict(image=[gt_data[:, :, 0]])) plot10 = figure(title="GT data") plot10.image(image='image', x=0, y=0, dw=gt_data.shape[0], dh=gt_data.shape[1], source=source10, color_mapper=color_mapper) slider = Slider(start=0, end=(rw_data.shape[2] - 1), value=0, step=1, title="Scroll through z-axis") slider2 = Slider(start=0, end=(rw_data.shape[2] - 1), value=0, step=1, title="Scroll through z-axis", default_size=200) button = Button(label='Toggle segmentation') button2 = RadioButtonGroup( labels=['X-direction', "Y-direction", "Z-direction"], active=0) gt_data2 = np.rot90(gt_data, 1, (1, 0)) dice3d = calculate_dice(np.round(data), gt_data2) dice_3d = Div( text="The 3D dice score of current segmentation is:{0}".format(dice3d)) dice2d = np.zeros(data.shape[2]) for x in range(data.shape[2]): dice2d[x] = calculate_dice(np.round(data[:, :, x]), gt_data2[:, :, x]) dice_2d = Div( text="The 2D dice score of current slice is:{0}".format(dice2d[0])) def update(attr, old, new): source10.data = dict(image=[gt_data[:, :, slider.value]]) dice_2d.text = "The 2D dice score of current slice is:{0}".format( dice2d[slider.value]) if button.label == 'Toggle segmentation': source.data = dict(image=[np.flipud(data[:, :, slider.value].T)]) else: source.data = dict( image=[np.round(np.flipud(data[:, :, slider.value].T))]) def update2(attr, old, new): for x in name_dict: source_dict['source{0}'.format(x)].data = dict(image=[ np.flipud(data2[button2.active][x - 1][:, :, slider2.value].T) ]) def change_button_value(): if button.label == 'Toggle segmentation': button.label = 'Toggle prob. map' else: button.label = 'Toggle segmentation' update('value', slider.value, slider.value) slider.on_change('value', update) slider2.on_change('value', update2) button.on_click(change_button_value) button2.on_change('active', update2) fig0 = row(button, slider) fig1 = row(plot, plot10, dice_3d, dice_2d) fig2 = row(button2, slider2) fig3 = column( row(plot_dict['plot1'], plot_dict['plot2'], plot_dict['plot3']), row(plot_dict['plot4'], plot_dict['plot5'], plot_dict['plot6']), row(plot_dict['plot7'], plot_dict['plot8'], plot_dict['plot9'])) l1 = layout([[fig0], [fig1]], sizing_mode='fixed') l2 = layout([[fig2], [fig3]], sizing_mode='fixed') tab1 = Panel(child=l1, title="Random Walker") tab2 = Panel(child=l2, title="Similarity Maps") tabs = Tabs(tabs=[tab1, tab2]) # tabs = Tabs(tabs=[tab1]) curdoc().add_root(tabs)
def top_graph(self, ind, title, d_source, e_source, tooltip, **kwargs): """Generate the top graphs (KH, uptake, WC).""" # Generate figure dict plot_side_size = 400 fig_dict = dict(tools="pan,wheel_zoom,tap,reset,save", active_scroll="wheel_zoom", plot_width=plot_side_size, plot_height=plot_side_size, title=title) fig_dict.update(kwargs) # Create a colour mapper for number of isotherms mapper = log_cmap(field_name='{0}_n'.format(ind), palette="Viridis256", low_color='grey', high_color='yellow', low=3, high=100) # Create a new plot graph = figure(**fig_dict) # Add the hover tooltip graph.add_tools( HoverTool(names=["{0}_data".format(ind)], tooltips=tooltip.render(p=ind))) # Plot the data rend = graph.circle("{0}_x".format(ind), "{0}_y".format(ind), source=d_source, size=10, line_color=mapper, color=mapper, name="{0}_data".format(ind)) # Plot guide line graph.add_layout( Slope(gradient=1, y_intercept=0, line_color='black', line_dash='dashed', line_width=2)) # Plot the error margins graph.segment('{0}_x0'.format(ind), '{0}_y0'.format(ind), '{0}_x1'.format(ind), '{0}_y1'.format(ind), source=e_source, color="black", line_width=2, line_cap='square', line_dash='dotted') # Plot labels next to selected materials graph.add_layout( LabelSet( x='{0}_x'.format(ind), y='{0}_y'.format(ind), source=e_source, text='labels', level='glyph', x_offset=5, y_offset=5, render_mode='canvas', text_font_size='10pt', )) # Add the colorbar to the side graph.add_layout( ColorBar(color_mapper=mapper['transform'], ticker=LogTicker(desired_num_ticks=10), width=8, location=(0, 0)), 'right') return graph, rend