def suffix_yaxis(f): f.yaxis.formatter = bom.FuncTickFormatter(code=""" var min_diff = Infinity; for (var i = 0; i < ticks.length-1; i++) { min_diff = Math.min(min_diff, ticks[i+1]-ticks[i]); } var suffixes = [ 'y', 'z', 'a', 'f', 'p', 'n', 'µ', 'm', '', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']; var precision = Math.floor(Math.log10(min_diff)); var scale = Math.floor(precision/3); var index = scale + 8; if (index < 0) { //TODO: Fall back to numbro here return tick; } else if (index == 7) { // Millis are weird. Feels better to rende them as decimals. var decimals = -precision; return `${tick.toFixed(decimals)}` } else if (index < suffixes.length) { var suffix = suffixes[index]; var scaled = tick/Math.pow(10, 3*scale); return `${scaled.toFixed(0)}${suffix}` } else { //TODO: Fall back to numbro here return tick; } """)
def timedelta_xaxis(f): f.xaxis.ticker = bom.tickers.DatetimeTicker() f.xaxis.formatter = bom.FuncTickFormatter(code=""" // TODO: Add support for millis // Calculate the hours, mins and seconds var s = Math.floor(tick / 1e3); var m = Math.floor(s/60); var s = s - 60*m; var h = Math.floor(m/60); var m = m - 60*h; var h = h.toString(); var m = m.toString(); var s = s.toString(); var pm = m.padStart(2, "0"); var ps = s.padStart(2, "0"); // Figure out what the min resolution is going to be var min_diff = Infinity; for (var i = 0; i < ticks.length-1; i++) { min_diff = Math.min(min_diff, ticks[i+1]-ticks[i]); } if (min_diff <= 60e3) { var min_res = 2; } else if (min_diff <= 3600e3) { var min_res = 1; } else { var min_res = 0; } // Figure out what the max resolution is going to be if (ticks.length > 1) { var max_diff = ticks[ticks.length-1] - ticks[0]; } else { var max_diff = Infinity; } if (max_diff >= 3600e3) { var max_res = 0; } else if (max_diff >= 60e3) { var max_res = 1; } else { var max_res = 2; } // Format the timedelta. Finally. if ((max_res == 0) && (min_res == 0)) { return `${h}h`; } else if ((max_res == 0) && (min_res == 1)) { return `${h}h${pm}`; } else if ((max_res == 0) && (min_res == 2)) { return `${h}h${pm}m${ps}`; } else if ((max_res == 1) && (min_res == 1)) { return `${m}m`; } else if ((max_res == 1) && (min_res == 2)) { return `${m}m${ps}`; } else if ((max_res == 2) && (min_res == 2)) { return `${s}s`; } """)
def scatter_grid(data, parameters): plot_width, plot_height = 300, 300 data = data[parameters] # add scaled data for the hexbin plots scaler = preprocessing.MinMaxScaler() scaled_data = scaler.fit_transform(data) for i, p in enumerate(parameters): data[p + 'scaled'] = scaled_data[:, i] # new formatters so that hexbin plots show the original range of data on axis instead of [0-1] formatters = {} for p in parameters: vmin, vmax = data[p].min(), data[p].max() code = """ tick = {vmin} + tick * ({vmax} - {vmin}) return tick.toFixed(1) """.format(vmin=vmin, vmax=vmax) formatters[p] = mpl.FuncTickFormatter(code=code) source = mpl.ColumnDataSource(data) grid_plots = [] for i, xpar in enumerate(parameters): line_plots = [] for j, ypar in enumerate(parameters): if i == j: # make a histogram p = bpl.figure(plot_width=plot_width, plot_height=plot_height) hist, edges, p = histogram(p, data[xpar], bins='knuth') p.quad(top=hist, bottom=0, left=edges[:-1], right=edges[1:], fill_color="navy", line_color="white", alpha=0.5) p.xaxis.axis_label = xpar elif i < j: # make a scatter plot p = bpl.figure(plot_width=plot_width, plot_height=plot_height) p.scatter(xpar, ypar, source=source, alpha=0.5) p.xaxis.axis_label = xpar p.yaxis.axis_label = ypar else: # make a hex plot p = bpl.figure(plot_width=plot_width, plot_height=plot_height) r, bins = p.hexbin(data[xpar + 'scaled'], data[ypar + 'scaled'], size=0.05) p.xaxis.axis_label = xpar p.yaxis.axis_label = ypar p.xaxis.formatter = formatters[xpar] p.yaxis.formatter = formatters[ypar] p.add_tools( mpl.HoverTool(tooltips=[("count", "@c")], mode="mouse", point_policy="follow_mouse", renderers=[r])) line_plots.append(p) grid_plots.append(line_plots) return gridplot(grid_plots)
source=phase_shift_source, line_color='orange') ctf_fig.line(x='omega_abs', y='ctf_values', source=ctf_source) ctf_fig.line(x='omega_abs', y='epa', y_range_name='epa', source=ctf_source, line_color='orange') ctf_fig.line(x='omega_abs', y='ctffind', source=ctf_source, line_color='green') ctf_fig.line(x='omega_abs', y='ctffind_ctf', source=ctf_source, line_color='red') ctf_fig.xaxis.formatter = bmodels.FuncTickFormatter(code=""" return "1/" + (1/tick).toFixed(4); """) def phase_shift_on_select(attr, old, new): if len(new['1d']['indices']) > 0: new_micrograph_number = new['1d']['indices'][0] print("Selected micrograph {}".format(new_micrograph_number)) update_plot(new_micrograph_number) phase_shift_glyphs.data_source.on_change('selected', phase_shift_on_select) layout = blayouts.layout([[phase_shift_fig, micrograph_ps_fig], [ctf_fig, blayouts.widgetbox(*widgets)]])
def barplot(df, x_col, y_col, output_path, group_col=None, error_col=None, color_col=None, fig_kwargs=None, y_tick_fontsize='14pt', x_tick_fontsize='16pt', x_tick_orientation=np.pi/2.0, fa=0.85, err_lw=2): '''Plots vertical bar plots using bokeh. Strictly uses pd.DataFrame # Assumptions - user can put data in correct format. note: this is not at "smart" as seaborn - x is categorical - data isnt too big. not efficiently coded for large data # Arguments df: pd.DataFrame x_col: name of column in df to use as x-axis. assumes categorical y_col: name of column in df to use as y-axis. bar plot values. output_path: path to output html file group_col: name of column to groupby df to plot nested groupings error_col: col to use for plotting error bars. plots error symmetrically, aka y +/- error color_col: col to use for coloring bars. if group_col is specified, color is chosen to override this column. fig_kwargs: dictionary argument to send to p.figure(). height, width, title etc y_tick_fontsize: this is a string with 'pt' attached x_tick_fontsize: this is a string with 'pt' attached x_tick_orientation: float. 0 for horizontal, np.pi/2.0 for vertical fa: fill_alpha of the bars. Globally applied to all bars err_lw: line width of the error bars. Globally applied to all bars ''' if fig_kwargs is None: fig_kwargs = {'height': 600, 'width': 1300} # TODO: reevaluate me. # make a copy of df as to not edit the original data df = df.copy() # --- construct figure --- # bki.output_file(output_path) p = bkp.figure(**fig_kwargs) p.yaxis.major_label_text_font_size = y_tick_fontsize p.xaxis.major_label_text_font_size = x_tick_fontsize p.xaxis.axis_line_width = 2 p.xgrid.grid_line_alpha = 0.0 p.x_range.range_padding = 0.15 p.y_range.range_padding = 0.1 p.xaxis.major_label_orientation = x_tick_orientation quad_kwargs = {'line_color': None, 'line_width': 1, 'fill_alpha': fa} error_lw_kwargs = {'line_width': err_lw, 'color':'black'} # hover hover = bkm.HoverTool(tooltips=[('x', '@x_cat'), ('y', '@y'), ('group', '@group')]) p.add_tools(hover) # find unique values of x and coordinate mapping to the categorical unique_xs = find_unique_keep_order(df[x_col]) # x_plot = len(unique_xs) x_map = {i: x_name for i, x_name in enumerate(unique_xs)} p.xaxis.ticker = bkm.FixedTicker(ticks=range(len(x_map))) p.xaxis.formatter = bkm.FuncTickFormatter(code='''var labels = %s; return labels[tick];''' % x_map) if group_col is None: df['_groups'] = '_' group_col = '_groups' if color_col is None: color_col = '_color' df[color_col] = 'black' # if group is given, give a color if group_col != '_groups': colour_wheel = pycolor.colour_wheel(color_palette=pycolor.palettes.category20_alt) for k, indices in df.groupby(group_col).indices.iteritems(): df[color_col].iloc[indices] = next(colour_wheel) else: df[color_col] = 'black' gb = df.groupby(group_col) ngroups = gb.ngroups if ngroups > 1: x_offsets, x_width = np.linspace(0, 1.0, num=ngroups + 1, endpoint=False, retstep=True) x_offsets = (x_offsets - x_width)[:ngroups] else: x_offsets = [0] x_width = 0.9 for i, (group_name, sub_df) in enumerate(gb): sub_df = sub_df.set_index(x_col) x_offset = x_offsets[i] y = list(sub_df.loc[unique_xs, y_col].fillna(value=0).values) x = range(len(y)) if error_col is None: error = None else: error = sub_df[error_col].values if color_col is None: c = None else: c = sub_df[color_col].values if group_col == '_groups': leg = None else: leg = group_name _plot_bar(p, x, y, x_map, x_offset=x_offset, width=x_width/2.0, error=error, c=c, quad_kwargs=quad_kwargs, error_lw_kwargs=error_lw_kwargs, legend=leg, group_name=group_name) p.x_range.start = x_offsets[0] - x_width p.x_range.end = len(x_map) - 1 + x_offsets[-1] + x_width p.legend.click_policy = 'hide' bki.save(p) return p
def set_ylabel_to_positive(fig): """Replace negative-valued y labels with thier absolute value""" fig.yaxis.formatter = bk_model.FuncTickFormatter( code="return Math.abs(tick)")