def plot(SBJ, WL_sec):
    # Load data
    # ---------
    ts_df, swc_df, run_seg_df, win_run_seg_df, run_df = load_data(SBJ, WL_sec)

    # Run segments plot
    # -----------------
    # Color key for runs
    run_color_map = {
        'SleepAscending': '#DE3163',
        'SleepDescending': '#FF7F50',
        'SleepRSER': '#FFBF00',
        'WakeAscending': '#6495ED',
        'WakeDescending': '#40E0D0',
        'WakeRSER': '#CCCCFF',
        'Inbetween Runs': 'black'
    }
    # Plot of run segements along the x axis
    run_seg = hv.Segments(run_seg_df, [
        hv.Dimension('start'),
        hv.Dimension('start_event'), 'end', 'end_event'
    ], 'run').opts(
        color='run',
        cmap=run_color_map,
        line_width=10,
        show_legend=True,
    )
    win_run_seg = hv.Segments(win_run_seg_df, [
        hv.Dimension('start'),
        hv.Dimension('start_event'), 'end', 'end_event'
    ], 'run').opts(
        color='run',
        cmap=run_color_map,
        line_width=10,
        show_legend=True,
    )

    # Time series plot
    # ----------------
    ts_plot = (xr.DataArray(ts_df.values, dims=['Time [TRs]', 'ROIs'
                                                ]).hvplot.image(cmap='gray') *
               run_seg).opts(title='ROI Time Series Carpet Plot',
                             height=300,
                             width=1200,
                             legend_position='right')

    # SWC plot with PCA
    # -----------------
    swc_plot = (
        xr.DataArray(swc_df.values.T, dims=['Time [Windows]', 'Connection'
                                            ]).hvplot.image(cmap='jet') *
        win_run_seg).opts(title='SWC Matrix with PCA',
                          height=300,
                          width=1200,
                          legend_position='right')

    plots = pn.Column(ts_plot, swc_plot)

    return plots
Esempio n. 2
0
 def __init__(self, df, name):
     self.YMAX = df.Y.max()
     self.YMIN = df.Y.min()
     self.XMIN = df.X.min() + 1
     self.XMAX = df.X.max() - 1
     self.XDISTANCE = self.XMAX - self.XMIN
     self.AREA = self.XDISTANCE + (self.YMAX - self.YMIN)
     entrance = ENTRANCES_EXITS[name][0]
     exit = ENTRANCES_EXITS[name][1]
     self.limits = hv.Segments((-5,0,5,0)).opts(color='black', line_width=3) * hv.Segments((-5,5,5,5)).opts(color='black', line_width=3) * \
         hv.Segments((-5,0,-5,5)).opts(color='black', line_width=3) * hv.Segments((5,0,5,5)).opts(color='black', line_width=3) * \
         hv.Segments((-5,2.5-entrance/2, -5, 2.5 + entrance/2)).opts(color='blue',line_width=3) * hv.Segments((5,2.5-exit/2, 5, 2.5 + exit/2)).opts(color='blue',line_width=3)
Esempio n. 3
0
 def _interval_view(self):
     import panel as pn
     import holoviews as hv
     hv.extension("bokeh")
     df = self.tree.to_df(self.label)
     self.keys = list(self.tree.keys())
     # self.values = list(self.tree.values())
     plot = hv.Segments(df, kdims=["begin", "parameter",  "end", "parameter"], vdims="data", )
     
     defaults = dict(color="data", 
                     line_width=30, alpha=0.5,
                     responsive=True,
                     height=120,
                     colorbar=True,
                     toolbar="above",
                     tools=["hover", "tap"],
                     xlabel="index",
                     nonselection_alpha=0.2,
                     nonselection_color="grey",
                     title=self.label)
     # defaults.update(opts)
     self.segments = segments = plot.opts(**defaults)
     labels = hv.Labels(df, kdims=["mid", "parameter"], vdims="label")
     plot = labels*segments
     self.selector = hv.streams.Selection1D(source=plot)
     self.selector.param.watch(self.make_tree_view, ['index'], onlychanged=True)
     self.make_tree_view()
     return pn.Column(plot, sizing_mode="stretch_width", width=700)
Esempio n. 4
0
 def _plot_base_matrix(hv_point_data):
     """
     Base function to plot record or hitlet matrix.
     """
     matrix_plot = hv.Segments(
         hv_point_data.data,
         kdims=['time', 'channel', 'endtime', 'channel']).opts(
             tools=['hover'],
             aspect=4,
             responsive='width',
         )
     return matrix_plot
def create_candle_stick(data: pd.DataFrame) -> hv.Layout:
    """Creates a candle stick plot

    Args:
        data (pd.DataFrame): A dataframe with columns time, open, high, low, close and volume

    Returns:
        hv.Layout: A candle stick plot
    """

    data = data.copy(deep=True)
    t_delta = timedelta(hours=1)
    data["time_start"] = data.time - 9 * t_delta  # rectangles start
    data["time_end"] = data.time + 9 * t_delta  # rectangles end
    data["positive"] = ((data.close - data.open) > 0).astype(int)
    tooltips = [
        ("Time", "@{time}{%F}"),
        ("Open", "@open"),
        ("High", "@high"),
        ("Low", "@{price}"),
        ("Close", "@close"),
        ("Volume", "@volume{0,0}"),
    ]
    hover = HoverTool(tooltips=tooltips, formatters={"@{time}": "datetime"})
    candlestick = hv.Segments(
        data, kdims=["time", "low", "time", "high"]) * hv.Rectangles(
            data,
            kdims=["time_start", "open", "time_end", "close"],
            vdims=["positive", "high", "low", "time", "volume"],
        )
    candlestick = candlestick.redim(low="price")
    candlestick.opts(
        hv.opts.Rectangles(
            color="positive",
            cmap=[RED, GREEN],
            responsive=True,
            tools=["box_zoom", "pan", "wheel_zoom", "save", "reset", hover],
            default_tools=[],
            active_tools=["box_zoom"],
        ),
        hv.opts.Segments(
            color=GRAY,
            height=400,
            responsive=True,
            tools=["box_zoom", "pan", "reset"],
            default_tools=[],
            active_tools=["box_zoom"],
        ),
    )
    return candlestick
Esempio n. 6
0
def plot_policy_gantt_chart(
    policies,
    effects=False,
    colors="categorical",
    fig_kwargs=None,
):
    """Plot a Gantt chart of the policies."""
    if fig_kwargs is None:
        fig_kwargs = {}
    fig_kwargs = {**DEFAULT_FIGURE_KWARGS, **fig_kwargs}

    if isinstance(policies, dict):
        df = (pd.DataFrame(policies).T.reset_index().rename(columns={
            "index": "name"
        }).astype({
            "start": "datetime64",
            "end": "datetime64"
        }).drop(columns="policy"))
    elif isinstance(policies, pd.DataFrame):
        df = policies
    else:
        raise ValueError(
            "'policies' should be either a dict or pandas.DataFrame.")

    if effects:
        effect_kwargs = effects if isinstance(effects, dict) else {}
        effects = compute_pseudo_effect_sizes_of_policies(policies=policies,
                                                          **effect_kwargs)
        effects_s = pd.DataFrame([{
            "policy": name,
            "effect": effects[name]["mean"]
        } for name in effects]).set_index("policy")["effect"]
        df = df.merge(effects_s, left_on="name", right_index=True)
        df["alpha"] = (1 - df["effect"] + 0.1) / 1.1
    else:
        df["alpha"] = 1

    df = df.reset_index()
    df = _complete_dates(df)
    df = _add_color_to_gantt_groups(df, colors)
    df = _add_positions(df)

    hv.extension("bokeh", logo=False)

    segments = hv.Segments(
        df,
        [
            hv.Dimension("start", label="Date"),
            hv.Dimension("position", label="Affected contact model"),
            "end",
            "position",
        ],
    )
    y_ticks_and_labels = list(zip(*_create_y_ticks_and_labels(df)))

    tooltips = [("Name", "@name")]
    if effects:
        tooltips.append(("Effect", "@effect"))
    hover = HoverTool(tooltips=tooltips)

    gantt = segments.opts(
        color="color",
        alpha="alpha",
        tools=[hover],
        yticks=y_ticks_and_labels,
        **fig_kwargs,
    )

    return gantt
Esempio n. 7
0
def task_fMRI_plots(SBJ, PURE, WL_sec, corr_range):
    # Define segment data
    # -------------------
    if WL_sec == 30:
        if PURE == 'pure':
            seg_df = WL30pure_taskseg_df
        else:
            seg_df = WL30_taskseg_df
    else:
        if PURE == 'pure':
            seg_df = WL45pure_taskseg_df
        else:
            seg_df = WL45_taskseg_df

    # Define PURE varaible based on widget
    # ------------------------------------
    if PURE == 'not pure':
        PURE = ''  # Load data with non pure windows

    # Load task fMRI data
    # -------------------
    file_name = SBJ + '_CTask001_WL0' + str(
        WL_sec) + '_WS01' + PURE + '_NROI0200_dF.mat'  # Data file name
    data_path = osp.join(
        '/data/SFIMJGC_HCP7T/PRJ_CognitiveStateDetection02/PrcsData_PNAS2015',
        SBJ, 'D02_CTask001', file_name)  # Path to data
    data_df = loadmat(data_path)['CB']['snapshots'][0][0]  # Read data
    num_samp = data_df.shape[0]  # Save number of samples as a varable

    # Create sleep segments plots
    # ---------------------------
    task_color_map = {
        'Rest': 'gray',
        'Memory': 'blue',
        'Video': 'yellow',
        'Math': 'green',
        'Inbetween': 'black'
    }  # Color key for task segments
    seg_x = hv.Segments(seg_df, [
        hv.Dimension('start', range=(-10, num_samp - 1.5)),
        hv.Dimension('start_event', range=(-5, num_samp - 1.5)), 'end',
        'end_event'
    ], 'task').opts(color='task',
                    cmap=task_color_map,
                    line_width=7,
                    show_legend=True)  # x axis segments
    seg_y = hv.Segments(seg_df, [
        hv.Dimension('start_event', range=(-10, num_samp - 1.5)),
        hv.Dimension('start', range=(-5, num_samp - 1.5)), 'end_event', 'end'
    ], 'task').opts(color='task',
                    cmap=task_color_map,
                    line_width=7,
                    show_legend=False)  # y axis segments
    seg_plot = (seg_x * seg_y).opts(xlabel=' ', ylabel=' ',
                                    show_legend=False)  # All segments

    # Compute correlation and distance matrix
    # ---------------------------------------
    data_corr = np.corrcoef(data_df)  # Correlation matrix
    data_dist = pairwise_distances(data_df,
                                   metric='euclidean')  # Distance matrix

    # Compute distribution of correlation and distance matrix
    # -------------------------------------------------------
    triangle = np.mask_indices(num_samp, np.triu,
                               k=1)  # Top triangle mask for matricies
    corr_freq, corr_edges = np.histogram(
        np.array(data_corr)[triangle], 100
    )  # Compute histogram of top triangle of correlation matrix (100 bars)
    dist_freq, dist_edges = np.histogram(
        np.array(data_dist)[triangle],
        100)  # Compute histogram of top triangle of distance matrix (100 bars)

    # Create matrix and histogram plots
    # ---------------------------------
    corr_img = hv.Image(
        np.rot90(data_corr),
        bounds=(-0.5, -0.5, num_samp - 1.5, num_samp - 1.5)).opts(
            cmap='viridis',
            colorbar=True,
            height=300,
            width=400,
            title='Correlation Matrix').redim.range(z=corr_range)
    dist_img = hv.Image(np.rot90(data_dist),
                        bounds=(-0.5, -0.5, num_samp - 1.5,
                                num_samp - 1.5)).opts(cmap='viridis',
                                                      colorbar=True,
                                                      height=300,
                                                      width=400,
                                                      title='Distance Matrix')
    corr_his = hv.Histogram(
        (corr_edges, corr_freq)).opts(xlabel='Correlation',
                                      height=300,
                                      width=400,
                                      title='Correlation Histogram')
    dist_his = hv.Histogram(
        (dist_edges, dist_freq)).opts(xlabel='Distance',
                                      height=300,
                                      width=400,
                                      title='Distance Histogram')

    corr_img_wseg = (corr_img * seg_plot).opts(
        width=600, height=300, legend_position='right'
    )  # Overlay task segemnt plot with correlation matrix
    dist_img_wseg = (dist_img * seg_plot).opts(
        width=600, height=300, legend_position='right'
    )  # Overlay task segemnt plot with distance matrix

    dash = (corr_img_wseg + corr_his + dist_img_wseg + dist_his).opts(
        opts.Layout(shared_axes=False)).cols(2)  # Dashboard of all plots

    return dash
Esempio n. 8
0
def rs_fMRI_plots(SBJ, RUN, WL_sec, corr_range):
    # Load rs fMRI data
    # -----------------
    file_name = SBJ + '_fanaticor_Craddock_T2Level_0200_wl' + str(
        WL_sec).zfill(
            3) + 's_ws002s_' + RUN + '_PCA_vk97.5.swcorr.pkl'  # Data file name
    data_path = osp.join('/data/SFIM_Vigilance/PRJ_Vigilance_Smk02/PrcsData',
                         SBJ, 'D02_Preproc_fMRI', file_name)  # Path to data
    data_df = pd.read_pickle(data_path).T  # Read data into pandas data frame
    num_samp = data_df.shape[0]  # Save number of samples as a varable

    # Load sleep segmenting data
    # --------------------------
    seg_path = osp.join(PRJDIR, 'Data', 'Samika_DSet02', 'Sleep_Segments',
                        SBJ + '_' + RUN + '_WL_' + str(WL_sec) +
                        'sec_Sleep_Segments.pkl')  # Path to segment data
    seg_df = pd.read_pickle(seg_path)  # Load segment data

    # Compute correlation and distance matrix
    # ---------------------------------------
    data_corr = np.corrcoef(data_df)  # Correlation matrix
    data_dist = pairwise_distances(data_df,
                                   metric='euclidean')  # Distance matrix

    # Compute distribution of correlation and distance matrix
    # -------------------------------------------------------
    triangle = np.mask_indices(num_samp, np.triu,
                               k=1)  # Top triangle mask for matricies
    corr_freq, corr_edges = np.histogram(
        np.array(data_corr)[triangle], 100
    )  # Compute histogram of top triangle of correlation matrix (100 bars)
    dist_freq, dist_edges = np.histogram(
        np.array(data_dist)[triangle],
        100)  # Compute histogram of top triangle of distance matrix (100 bars)

    # Create sleep segments plots
    # ---------------------------
    sleep_color_map = {
        'Wake': 'orange',
        'Stage 1': 'yellow',
        'Stage 2': 'green',
        'Stage 3': 'blue',
        'Undetermined': 'gray'
    }  # Color key for sleep staging
    seg_x = hv.Segments(seg_df, [
        hv.Dimension('start', range=(-10, num_samp - 1.5)),
        hv.Dimension('start_event', range=(-5, num_samp - 1.5)), 'end',
        'end_event'
    ], 'stage').opts(color='stage',
                     cmap=sleep_color_map,
                     line_width=7,
                     show_legend=True)  # x axis segments
    seg_y = hv.Segments(seg_df, [
        hv.Dimension('start_event', range=(-10, num_samp - 1.5)),
        hv.Dimension('start', range=(-5, num_samp - 1.5)), 'end_event', 'end'
    ], 'stage').opts(color='stage',
                     cmap=sleep_color_map,
                     line_width=7,
                     show_legend=False)  # y axis segments
    seg_plot = (seg_x * seg_y).opts(xlabel=' ', ylabel=' ',
                                    show_legend=False)  # All segments

    # Create matrix and histogram plots
    # ---------------------------------
    # raterize() fucntion used for big data set
    corr_img = rasterize(
        hv.Image(np.rot90(data_corr),
                 bounds=(-0.5, -0.5, num_samp - 1.5, num_samp - 1.5)).opts(
                     cmap='viridis', colorbar=True,
                     title='Correlation Matrix')).redim.range(z=corr_range)
    dist_img = rasterize(
        hv.Image(np.rot90(data_dist),
                 bounds=(-0.5, -0.5, num_samp - 1.5,
                         num_samp - 1.5)).opts(cmap='viridis',
                                               colorbar=True,
                                               title='Distance Matrix'))
    corr_his = rasterize(
        hv.Histogram(
            (corr_edges, corr_freq)).opts(xlabel='Correlation',
                                          height=300,
                                          width=400,
                                          title='Correlation Histogram'))
    dist_his = rasterize(
        hv.Histogram((dist_edges, dist_freq)).opts(xlabel='Distance',
                                                   height=300,
                                                   width=400,
                                                   title='Distance Histogram'))

    corr_img_wseg = (corr_img * seg_plot).opts(
        width=600, height=300, legend_position='right'
    )  # Overlay sleep segemnt plot with correlation matrix
    dist_img_wseg = (dist_img * seg_plot).opts(
        width=600, height=300, legend_position='right'
    )  # Overlay sleep segemnt plot with distance matrix

    dash = (corr_img_wseg + corr_his + dist_img_wseg + dist_his).opts(
        opts.Layout(shared_axes=False)).cols(2)  # Dashboard of all plots

    return dash
def distance_matrix(SBJ, RUN, WL_sec, x_dim, y_dim, z_dim):
    """
    This fuction plots a heat map of the distnaces of each window for a given run.
    The inputs for the fuction (subject, run, and window leght) allows the user to choose what run and window leghth
    they with to plot for a given subject.
    The distance between two windows (i.e. points on the 3D plot) is computed using numpys squareform(pdist()).
    The fuction plots the heat map using holoviews hv.Image().
    The x and y axes of the plot are the two windows in which you are finding the distance.
    The z value is that distance.
    A plot of the sleep staging segments are ploted along the x and y axis of the image using hv.Segments().
    If all runs are being displayed a plot of the run segments are ploted along the x and y axis of the image using hv.Segments().
    """
    LE3D_df = load_data(SBJ, RUN, WL_sec)  # Load embedding data
    LE3D_df = LE3D_df.infer_objects(
    )  # Infer objects to be int, float, or string apropriatly
    LE3D_df = LE3D_df[[
        'x' + str(x_dim).zfill(2), 'x' + str(y_dim).zfill(2),
        'x' + str(z_dim).zfill(2), 'x' + str(x_dim).zfill(2) + '_norm',
        'x' + str(y_dim).zfill(2) + '_norm',
        'x' + str(z_dim).zfill(2) + '_norm', 'Run', 'Sleep Value',
        'Sleep Stage', 'mean FD', 'label'
    ]]
    LE3D_df.columns = [
        'x', 'y', 'z', 'x_norm', 'y_norm', 'z_norm', 'Run', 'Sleep Value',
        'Sleep Stage', 'mean FD', 'label'
    ]

    data_path = osp.join(PRJDIR, 'PrcsData', SBJ, 'D02_Preproc_fMRI',
                         SBJ + '_' + RUN + '_WL_' + str(WL_sec) +
                         'sec_Sleep_Segments.pkl')  # path to segment data
    sleep_segments_df = pd.read_pickle(data_path)  # Load segment data
    data_df = LE3D_df[[
        'x_norm', 'y_norm', 'z_norm', 'Sleep Stage'
    ]].copy()  # New data frame of only x_norm, y_norm, and z_norm values
    num_win = data_df.shape[0]  # Number of windwos in data

    data_array = data_df[['x_norm', 'y_norm',
                          'z_norm']].to_numpy()  # Data as a numpy array
    dist_array = squareform(pdist(
        data_array,
        'euclidean'))  # Calculate distance matrix and rehape into one vecotr
    dist_array = xr.DataArray(dist_array,
                              dims=['Time [Window ID]', 'Time [Window ID] Y'
                                    ])  # Distances as x_array data frame

    sleep_color_map = {
        'Wake': 'orange',
        'Stage 1': 'yellow',
        'Stage 2': 'green',
        'Stage 3': 'blue',
        'Undetermined': 'gray'
    }  # Color key for sleep staging

    # Plot of sleep staging segements along the x and y axis
    # Range is from (-10, num_win) so we have space to display segments
    sleep_seg_x = hv.Segments(sleep_segments_df, [
        hv.Dimension('start', range=(-10, num_win)),
        hv.Dimension('start_event', range=(-5, num_win)), 'end', 'end_event'
    ], 'stage').opts(color='stage',
                     cmap=sleep_color_map,
                     line_width=10,
                     show_legend=False)
    sleep_seg_y = hv.Segments(sleep_segments_df, [
        hv.Dimension('start_event', range=(-10, num_win)),
        hv.Dimension('start', range=(-5, num_win)), 'end_event', 'end'
    ], 'stage').opts(color='stage',
                     cmap=sleep_color_map,
                     line_width=10,
                     show_legend=False)

    # If plotting all runs add segent to x and y axis for coloring by run
    if RUN == 'All':
        run_list = [
            SubDict[SBJ][i][0] for i in range(0,
                                              len(SubDict[SBJ]) - 1)
        ]  # List of all runs
        time_list = [
            SubDict[SBJ][i][1] for i in range(0,
                                              len(SubDict[SBJ]) - 1)
        ]  # List of all run lenghts in TR's (in the same order as runs in list above)

        WL_trs = int(WL_sec / 2)  # Window length in TR's (TR = 2.0 sec)

        run_segments_df = pd.DataFrame(
            columns=['run', 'start',
                     'end'])  # Emptly data frame for segment legths of runs

        # For each run a row is appended into the data frame created above (run_segments_df) with the run name and the start and end window of the run
        # For the windows that overlap runs the run will be called 'Inbetween Runs'
        x = 0  # Starting at 0th window
        for i in range(len(run_list)):
            time = time_list[i]  # Number of windows in run
            run = run_list[i]  # Name of run
            end = x + time - WL_trs  # Last window of run
            if i == len(
                    run_list
            ) - 1:  # If its the last run no need to append inbetween run
                run_segments_df = run_segments_df.append(
                    {
                        'run': run,
                        'start': x,
                        'end': end
                    }, ignore_index=True)  # Append run info
            else:
                run_segments_df = run_segments_df.append(
                    {
                        'run': run,
                        'start': x,
                        'end': end
                    }, ignore_index=True)  # Append run info
                x = end + 1
                run_segments_df = run_segments_df.append(
                    {
                        'run': 'Inbetween Runs',
                        'start': x,
                        'end': (x - 1) + (WL_trs - 1)
                    },
                    ignore_index=True)  # Append inbetween run info
                x = x + (WL_trs - 1)

        # Add 0.5 to each end of segment to span entire heat map
        run_segments_df['start'] = run_segments_df['start'] - 0.5
        run_segments_df['end'] = run_segments_df['end'] + 0.5

        # 'start_event' and 'end_event' represent the axis along which the segments will be (-50 so it is not on top of the heat map or sleep segments)
        run_segments_df['start_event'] = -50
        run_segments_df['end_event'] = -50

        # Color key for runs
        run_color_map = {
            'SleepAscending': '#DE3163',
            'SleepDescending': '#FF7F50',
            'SleepRSER': '#FFBF00',
            'WakeAscending': '#6495ED',
            'WakeDescending': '#40E0D0',
            'WakeRSER': '#CCCCFF',
            'Inbetween Runs': 'gray'
        }

        # Plot of run segements along the x and y axis
        # Range is from (-80, num_win) so we have space to display both segments
        run_seg_x = hv.Segments(run_segments_df, [
            hv.Dimension('start', range=(-80, num_win)),
            hv.Dimension('start_event', range=(-80, num_win)), 'end',
            'end_event'
        ], 'run').opts(color='run',
                       cmap=run_color_map,
                       line_width=10,
                       show_legend=False)
        run_seg_y = hv.Segments(run_segments_df, [
            hv.Dimension('start_event', range=(-80, num_win)),
            hv.Dimension('start', range=(-80, num_win)), 'end_event', 'end'
        ], 'run').opts(color='run',
                       cmap=run_color_map,
                       line_width=10,
                       show_legend=False)

        segment_plot = (
            sleep_seg_x * sleep_seg_y * run_seg_x * run_seg_y).opts(
                xlabel=' ', ylabel=' ',
                show_legend=False)  # All segments (run and sleep) overlayed
    else:
        segment_plot = (sleep_seg_x * sleep_seg_y).opts(
            xlabel=' ', ylabel=' ',
            show_legend=False)  # All segments (not including runs)overlayed

    # Plot heat map using hv.Image
    # Set bounds to (-0.5,-0.5,num_win-0.5,num_win-0.5) to corespond with acurate windows
    plot = hv.Image(dist_array,
                    bounds=(-0.5, -0.5, num_win - 0.5,
                            num_win - 0.5)).opts(cmap='jet',
                                                 colorbar=True,
                                                 ylabel='Time [Window ID]')

    # Overlay segment plots and heat map
    output = (plot * segment_plot).opts(width=600, height=390)

    return output
# use datashader so we're not plotting tons of points
plot = hv.operation.datashader.dynspread(
    hv.operation.datashader.datashade(
        points,
        aggregator=datashader.by('concentration', datashader.count()),
        color_key=colors,
    ))

# make segments to show range of D
D_segments = hv.NdOverlay({
    concentration: hv.Segments((
        df_mle.loc[(df_mle['concentration'] == concentration) &
                   (df_mle['parameter'] == 'alpha'), 'conf_start'],
        df_mle.loc[(df_mle['concentration'] == concentration) &
                   (df_mle['parameter'] == 'beta (1/s)'), 'mle'],
        df_mle.loc[(df_mle['concentration'] == concentration) &
                   (df_mle['parameter'] == 'alpha'), 'conf_end'],
        df_mle.loc[(df_mle['concentration'] == concentration) &
                   (df_mle['parameter'] == 'beta (1/s)'), 'mle'],
    ), ).opts(color=color, line_width=2)
    for concentration, color in zip(df_mle['concentration'].unique(), colors)
}).opts(title="Alpha and Beta Confidence Regions for Different Concentrations")

# make segments to show range of k_off
k_off_segments = hv.NdOverlay({
    concentration: hv.Segments((
        df_mle.loc[(df_mle['concentration'] == concentration) &
                   (df_mle['parameter'] == 'alpha'), 'mle'],
        df_mle.loc[(df_mle['concentration'] == concentration) &
                   (df_mle['parameter'] == 'beta (1/s)'), 'conf_start'],
        df_mle.loc[(df_mle['concentration'] == concentration) &