Esempio n. 1
0
def heatpack(matrix,
             palette=Magma256,
             low=None,
             high=None,
             low_color='gray',
             high_color='red',
             start=None,
             end=None,
             step=None,
             height=600,
             width=600,
             axes=None):
    """
	input:
		- width / height : width and height of the heatmap figure
		- matrix: 2D array
		- palette: list of colors
		- low: low value of the ColorMapper
		- high: high value of the ColorMapper
		- low_color: values below "low" will have that color
		- high_color: values above "high" will have that color
		- start / end : range for the slider
		- step: step of the range slider

	output:
		- the heatmap figure
		- dummy figure with the colorbar
		- range slider to change the low / high values of the color mapper
	"""

    # make sure the 2D array is a numpy array
    if type(matrix) != np.ndarray:
        matrix = np.array(matrix)

    if start == None:
        start = matrix.min()
    if end == None:
        end = matrix.max()
    if step == None:
        step = (end - start) / 100

    if low == None:
        low = matrix.min()
    if high == None:
        high = matrix.max()

    mapper = LinearColorMapper(
        palette=palette,
        low=low,
        high=high,
        low_color=low_color,
        high_color=high_color
    )  # linearly map the "magma" list to the [low,high] range

    color_bar = ColorBar(
        color_mapper=mapper, location=(0, 0),
        label_standoff=15)  # define the color bar with the linear color mapper

    len_mat = len(matrix)
    if axes is None:
        IDs = list(
            range(len_mat)
        ) * len_mat  # list of column indices for the flattened matrix elements
    else:
        IDs = list(axes) * len_mat
    source = ColumnDataSource(
        data={
            'row': np.array(sorted(IDs)),
            'col': np.array(IDs),
            'mat': matrix.flatten()
        })

    TOOLS = "box_zoom,hover,save,pan,reset,wheel_zoom"  # interactive tools for the plot

    # the heatmap plot
    fig = figure(plot_width=width,
                 plot_height=height,
                 tools=TOOLS,
                 active_drag="box_zoom")
    rect = fig.rect(x='col',
                    y='row',
                    width=1.1,
                    height=1.1,
                    source=source,
                    fill_color={
                        'field': 'mat',
                        'transform': mapper
                    },
                    line_alpha=0,
                    line_width=0,
                    dilate=True)

    # plot cosmetics
    fig.grid.grid_line_color = None
    fig.axis.axis_line_color = None
    fig.axis.major_tick_line_color = None
    fig.axis.major_label_standoff = 0
    fig.x_range.range_padding = 0  # prevents white bands on the inner sides of the plot
    fig.y_range.range_padding = 0  # prevents white bands on the inner sides of the plot

    # use a dummy figure to add the color bar (because add_layout will compress your plot)
    dumx = range(10)
    dumfig = figure(outline_line_alpha=0, plot_height=height, plot_width=120)
    dumfig.line(x=dumx, y=dumx, visible=False)
    for rend in dumfig.renderers:
        rend.visible = False
    dumfig.add_layout(color_bar, 'left')

    # configure the Hover tool
    fig.select_one(HoverTool).tooltips = [
        ('row, col', '@row, @col'),
        ('value', '@mat'),
    ]

    # widgets
    select = RangeSlider(start=start,
                         end=end,
                         step=step,
                         value=(low, high),
                         callback_policy='mouseup')

    # javascript callback codes for the widgets
    select_code = """
	var maxval = select.value[1];
	var minval = select.value[0]

	map.high = maxval;
	map.low = minval;
	"""

    # widget callbacks
    select.callback = CustomJS(args=dict(map=mapper, src=source,
                                         select=select),
                               code=select_code)

    return fig, dumfig, select
def modify_doc(doc):
    fid = polymer.getfid(ie)  #dataframe

    # TODO: more testing on get_x_axis
    tau = get_x_axis(polymer.getparameter(ie))

    #calculate magnetization:
    startpoint = int(0.05 * polymer.getparvalue(ie, 'BS'))
    endpoint = int(
        0.1 * polymer.getparvalue(ie, 'BS')
    )  #TODO: make a range slider to get start- and endpoint interactively
    phi = get_mag_amplitude(fid, startpoint, endpoint,
                            polymer.getparvalue(ie, 'NBLK'),
                            polymer.getparvalue(ie, 'BS'))

    #prepare magnetization decay curve for fit
    df = pd.DataFrame(data=np.c_[tau, phi], columns=['tau', 'phi'])
    df['phi_normalized'] = (df['phi'] - df['phi'].iloc[0]) / (
        df['phi'].iloc[-1] - df['phi'].iloc[1])
    polymer.addparameter(ie, 'df_magnetization', df)

    fit_option = 2
    p0 = [1, 2 * polymer.getparvalue(ie, 'T1MX')**-1, 0]
    df, popt = magnetization_fit(df, p0, fit_option)
    polymer.addparameter(ie, 'popt(mono_exp)', popt)

    df['fit_phi'] = model_exp_dec(df.tau, *popt)

    # convert data to handle in bokeh
    source_fid = ColumnDataSource(data=ColumnDataSource.from_df(fid))
    source_df = ColumnDataSource(data=ColumnDataSource.from_df(df))

    # create and plot figures
    p1 = figure(plot_width=300,
                plot_height=300,
                title='Free Induction Decay',
                webgl=True)
    p1.line('index', 'im', source=source_fid, color='blue')
    p1.line('index', 'real', source=source_fid, color='green')
    p1.line('index', 'magnitude', source=source_fid, color='red')

    fid_slider = RangeSlider(start=1,
                             end=polymer.getparvalue(ie, 'BS'),
                             step=1,
                             callback_policy='mouseup')

    p2 = figure(plot_width=300, plot_height=300, title='Magnetization Decay')
    p2.circle_cross('tau', 'phi_normalized', source=source_df, color="navy")
    p2.line('tau', 'fit_phi', source=source_df, color="teal")

    # in the plot 4 use followingimpo
    SIZES = list(range(6, 22, 3))  # for some sizes
    COLORS = Spectral5  # for some colors (more colors would be nice somehow)

    def plot_par():
        xs = par_df[x.value].values
        ys = par_df[y.value].values
        x_title = x.value.title()
        y_title = y.value.title()

        kw = dict()  #holds optional keyword arguments for figure()
        if x.value in discrete:
            kw['x_range'] = sorted(set(xs))
        if y.value in discrete:
            kw['y_range'] = sorted(set(ys))
        if y.value in time:
            kw['y_axis_type'] = 'datetime'
        if x.value in time:
            kw['x_axis_type'] = 'datetime'

        kw['title'] = "%s vs %s" % (x_title, y_title)

        p4 = figure(plot_height=300,
                    plot_width=600,
                    tools='pan,box_zoom,reset',
                    **kw)

        p4.xaxis.axis_label = x_title
        p4.yaxis.axis_label = y_title

        if x.value in discrete:
            p4.xaxis.major_label_orientation = pd.np.pi / 4  # rotates labels...

        sz = 9
        if size.value != 'None':
            groups = pd.qcut(pd.to_numeric(par_df[size.value].values),
                             len(SIZES))
            sz = [SIZES[xx] for xx in groups.codes]

        c = "#31AADE"
        if color.value != 'None':
            groups = pd.qcut(
                pd.to_numeric(par_df[color.value]).values, len(COLORS))
            c = [COLORS[xx] for xx in groups.codes]

        p4.circle(x=xs,
                  y=ys,
                  color=c,
                  size=sz,
                  line_color="white",
                  alpha=0.6,
                  hover_color='white',
                  hover_alpha=0.5)
        return p4

    def update(attr, old, new):
        layout_p4.children[1] = plot_par()

    def cb(attr, old, new):
        ## load experiment ie in plot p1 and p2
        ie = new['value'][0]
        fid = polymer.getfid(ie)
        #print(fid)
        #source_fid = ColumnDataSource.from_df(data=fid)
        source_fid.data = ColumnDataSource.from_df(fid)
        #print(source_fid)
        try:
            tau = get_x_axis(polymer.getparameter(ie))
            #print(tau)
            try:
                startpoint = polymer.getparvalue(ie, 'fid_amp_start')
                endpoint = polymer.getparvalue(ie, 'fid_amp_stop')
            except:
                startpoint = int(0.05 * polymer.getparvalue(ie, 'BS'))
                endpoint = int(0.1 * polymer.getparvalue(ie, 'BS'))
            phi = get_mag_amplitude(fid, startpoint, endpoint,
                                    polymer.getparvalue(ie, 'NBLK'),
                                    polymer.getparvalue(ie, 'BS'))
            df = pd.DataFrame(data=np.c_[tau, phi], columns=['tau', 'phi'])
            df['phi_normalized'] = (df['phi'] - df['phi'].iloc[0]) / (
                df['phi'].iloc[-1] - df['phi'].iloc[1])
            polymer.addparameter(ie, 'df_magnetization', df)
            fit_option = 2  #mono exponential, 3 parameter fit
            p0 = [1.0, polymer.getparvalue(ie, 'T1MX')**-1 * 2, 0]
            df, popt = magnetization_fit(df, p0, fit_option)
            source_df.data = ColumnDataSource.from_df(df)

            polymer.addparameter(ie, 'popt(mono_exp)', popt)
            print(popt)

            #print(df)
            print(polymer.getparvalue(ie, 'df_magnetization'))
            fid_slider = RangeSlider(start=1,
                                     end=polymer.getparvalue(ie, 'BS'),
                                     range=(startpoint, endpoint),
                                     step=1,
                                     callback_policy='mouseup')
            layout_p1.children[2] = fid_slider

        except KeyError:
            print('no relaxation experiment found')
            tau = np.zeros(1)
            phi = np.zeros(1)
            df = pd.DataFrame(data=np.c_[tau, phi], columns=['tau', 'phi'])
            df['phi_normalized'] = np.zeros(1)
            df['fit_phi'] = np.zeros(1)
            source_df.data = ColumnDataSource.from_df(df)

    #this source is only used to communicate to the actual callback (cb)
    source = ColumnDataSource(data=dict(value=[]))
    source.on_change('data', cb)

    slider = Slider(start=1,
                    end=nr_experiments,
                    value=1,
                    step=1,
                    callback_policy='mouseup')
    slider.callback = CustomJS(
        args=dict(source=source),
        code="""
        source.data = { value: [cb_obj.value] }
    """
    )  #unfortunately this customjs is needed to throttle the callback in current version of bokeh

    def calculate_mag_dec(attr, old, new):
        ie = slider.value
        polymer.addparameter(ie, 'fid_range', new['range'])
        print(polymer.getparvalue(ie, 'fid_range'))  #this works
        start = new['range'][0]
        stop = new['range'][1]
        fid = polymer.getfid(ie)
        tau = polymer.getparvalue(ie, 'df_magnetization').tau
        phi = get_mag_amplitude(fid, start, stop,
                                polymer.getparvalue(ie, 'NBLK'),
                                polymer.getparvalue(ie, 'BS'))

        df = pd.DataFrame(data=np.c_[tau, phi], columns=['tau', 'phi'])
        df['phi_normalized'] = (df['phi'] - df['phi'].iloc[0]) / (
            df['phi'].iloc[-1] - df['phi'].iloc[1])

        fit_option = 2  #mono exponential, 3 parameter fit
        p0 = polymer.getparvalue(ie, 'popt(mono_exp)')
        df, popt = magnetization_fit(df, p0, fit_option)
        source_df.data = ColumnDataSource.from_df(df)
        polymer.addparameter(ie, 'df_magnetization', df)
        polymer.addparameter(ie, 'popt(mono_exp)', popt)
        pass

    source2 = ColumnDataSource(data=dict(range=[], ie=[]))
    source2.on_change('data', calculate_mag_dec)
    fid_slider.callback = CustomJS(
        args=dict(source=source2),
        code="""
        source.data = { range: cb_obj.range }
    """
    )  #unfortunately this customjs is needed to throttle the callback in current version of bokeh

    # select boxes for p4
    x = Select(title='X-Axis', value='ZONE', options=columns)
    x.on_change('value', update)

    y = Select(title='Y-Axis', value='TIME', options=columns)
    y.on_change('value', update)

    size = Select(title='Size', value='None', options=['None'] + quantileable)
    size.on_change('value', update)

    color = Select(title='Color',
                   value='None',
                   options=['None'] + quantileable)
    color.on_change('value', update)

    controls_p4 = widgetbox([x, y, color, size], width=150)
    layout_p4 = row(controls_p4, plot_par())

    #fitting on all experiments
    p3 = figure(plot_width=300,
                plot_height=300,
                title='normalized phi vs normalized tau',
                webgl=True,
                y_axis_type='log',
                x_axis_type='linear')

    #fit magnetization decay for all experiments
    r1 = np.zeros(nr_experiments)
    MANY_COLORS = 0
    p3_line_glyph = []
    for i in range(nr_experiments):
        try:
            par = polymer.getparameter(i)
            fid = polymer.getfid(i)
            tau = get_x_axis(polymer.getparameter(i))
            startpoint = int(0.05 * polymer.getparameter(i)['BS'])
            endpoint = int(
                0.1 * polymer.getparameter(i)['BS']
            )  #TODO: make a range slider to get start- and endpoint interactively
            phi = get_mag_amplitude(fid, startpoint, endpoint,
                                    polymer.getparameter(i)['NBLK'],
                                    polymer.getparameter(i)['BS'])
            df = pd.DataFrame(data=np.c_[tau, phi], columns=['tau', 'phi'])
            df['phi_normalized'] = (df['phi'] - df['phi'].iloc[0]) / (
                df['phi'].iloc[-1] - df['phi'].iloc[1])
            polymer.addparameter(i, 'df_magnetization', df)

            p0 = [1, 2 * polymer.getparvalue(i, 'T1MX'), 0]
            df, popt = magnetization_fit(df, p0, fit_option=2)
            polymer.addparameter(i, 'amp', popt[0])
            polymer.addparameter(i, 'r1', popt[1])
            polymer.addparameter(i, 'noise', popt[2])
            r1[i] = popt[1]
            tau = popt[1] * df.tau
            phi = popt[0]**-1 * (df.phi_normalized - popt[2])
            p3_df = pd.DataFrame(data=np.c_[tau, phi], columns=['tau', 'phi'])
            source_p3 = ColumnDataSource(data=ColumnDataSource.from_df(p3_df))
            p3_line_glyph.append(p3.line(
                'tau', 'phi', source=source_p3))  #TODO add nice colors
            MANY_COLORS += 1
        except KeyError:
            print('no relaxation experiment found')
    COLORS = viridis(MANY_COLORS)
    for ic in range(MANY_COLORS):
        p3_line_glyph[ic].glyph.line_color = COLORS[ic]
    par_df['r1'] = r1
    layout_p1 = column(slider, p1, fid_slider, p2, p3)
    doc.add_root(layout_p1)
    doc.add_root(layout_p4)
    doc.add_root(source)  # i need to add source to detect changes
    doc.add_root(source2)