Beispiel #1
0
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
Beispiel #2
0
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)
    )
Beispiel #4
0
    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
Beispiel #5
0
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)
Beispiel #6
0
    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