def prediction_plot(data_prev, data_pred, target_col, date_col): """ Creates a plotwith prediction and true values for 60 days ahead Args: data_prev: historic true values of variable data_pred: predictions of variable target_col: column from which data will be displayed in format (column name, name to display in hoover tool) data_col: coulmn with datetime data """ data_prev.rename({"date_x": "date"}, axis=1, inplace=True) # function used to plot values supplied in per_million format, multiplying values by 37.9 to get real values data_prev[target_col[0]] = data_prev[target_col[0]] * 37.9 data_pred[target_col[0]] = data_pred[target_col[0]] * 37.9 # defining tooltips for hover tool and data source for bokeh to use source_prev = ColumnDataSource(data=data_prev) source_preds = ColumnDataSource(data=data_pred) # defining fgure, scaling enabled p = figure(plot_width=900, plot_height=400, x_axis_type="datetime", sizing_mode="scale_width") # historic line and it's hover tool historic = p.line(x="date", y=target_col[0], source=source_prev, color="grey", line_width=2, legend_label="Dane historyczne") hover = HoverTool(tooltips=[(target_col[1], f"@{target_col[0]}" + "{0.0}") ], mode='vline', point_policy='follow_mouse', renderers=[historic]) hover.formatters = {"@date": "datetime"} p.tools.append(hover) # predictions line and it's hover tool pred = p.line(x="date", y=target_col[0], source=source_preds, line_width=2, color="#2422bb", legend_label="Prognoza") hover1 = HoverTool(tooltips=[(target_col[1], f"@{target_col[0]}" + "{0.0}") ], mode='vline', point_policy='follow_mouse', renderers=[pred]) hover1.formatters = {"@date": "datetime"} p.tools.append(hover1) # creating hover tool p.legend.location = "top_left" return p
def plot_time_series(data, fig, fig_size=[800, 350], title="", legend="", labels=["Date", ""], linewidth=1, color="blue", linestyle="solid", alpha=1): fig.plot_width = fig_size[0] fig.plot_height = fig_size[1] source = ColumnDataSource() source.add(data.index, name="date") source.add(data.values, name="values") source.add(data.index.strftime("%Y-%m-%d %H:%M:%S"), "date_formatted") # create a line plot fig.line(source=source, x="date", y="values", legend=legend, line_color=color, line_dash=linestyle, line_alpha=alpha, line_width=linewidth) fig.title.text = title fig.title.text_font = 'Helvetica' fig.title.text_font_size = '18px' fig.title.align = 'center' fig.legend.background_fill_alpha = 0.6 fig.legend.label_text_font = 'Helvetica' fig.legend.location = 'bottom_right' fig.xaxis.axis_label = labels[0] fig.yaxis.axis_label = labels[1] hover = HoverTool(tooltips=[("Value: ", "@values"), ("Timestamp: ", "@date_formatted")]) hover.formatters = {'Timestamp': "datetime"} fig.add_tools(hover) fig.toolbar_location = "above" return fig
def areaplot(p, source, data_cols, colormap, hovertool, xlabelname, x_axis_type, stacked, **kwargs): """Adds areaplot to figure p for each data_col.""" # Add element to start and end of each x and y column for vertical lines at # end of areaplots: for key in source.keys(): if key == "x": source[key] = [source[key][0]] + list( source[key]) + [source[key][-1]] else: source[key] = np.array([0] + list(source[key]) + [0]) N_source = len(source[key]) # Stack data if <stacked>=True: if stacked: baseline = np.zeros(N_source) for col in data_cols: source[col] = baseline + source[col] baseline = source[col] if "alpha" not in kwargs: kwargs["alpha"] = 1 elif "alpha" not in kwargs: kwargs["alpha"] = 0.5 # Add line (and optional scatter glyphs) to figure: for j, name, color in list(zip(range(len(data_cols)), data_cols, colormap))[::-1]: p.patch(x="x", y=str(name), legend=" " + str(name), source=source, color=color, **kwargs) glyph = p.line( x="x", y=str(name), legend=" " + str(name), source=source, color=color, alpha=0, ) if hovertool and int(len(data_cols) / 2) == j: my_hover = HoverTool(mode="vline", renderers=[glyph]) if x_axis_type == "datetime": my_hover.tooltips = [(xlabelname, "@x{%F}") ] + [(str(name), "@{%s}" % str(name)) for name in data_cols[::-1]] my_hover.formatters = {"x": "datetime"} else: my_hover.tooltips = [ (xlabelname, "@x"), (str(name), "@{%s}" % str(name)), ] p.add_tools(my_hover) return p
def plot_graph(timestamps, arrays_to_plot, array_labels, graph_title, save=True): """ This is a utility function to plot out any set of NumPy arrays you pass into it using the Bokeh library. The precondition of this function is that the length of arrays_to_plot and array_labels are equal. This is because there be a 1:1 mapping of each entry of arrays_to_plot to array_labels such that: arrays_to_plot[n] has label array_labels[n] Another precondition of this function is that each of the arrays within arrays_to_plot also have the same length. This is each of them will share the same time axis. Args: timestamps: An array of timestamps for the race arrays_to_plot: An array of NumPy arrays to plot array_labels: An array of strings for the individual plot titles graph_title: A string that serves as the plot's main title save: Boolean flag to contorl whether to save an .html file Result: Produces a 3 x ceil(len(arrays_to_plot) / 3) plot If save is enabled, save html file """ compress_constant = int(timestamps.shape[0] / 5000) for index, array in enumerate(arrays_to_plot): arrays_to_plot[index] = array[::compress_constant] figures = list() hover_tool = HoverTool() hover_tool.formatters = {"x": "datetime"} hover_tool.tooltips = [ ("time", "$x"), ("data", "$y") ] for (index, data_array) in enumerate(arrays_to_plot): # create figures and put them in list figures.append(figure(title=array_labels[index], x_axis_label="Time (hr)", y_axis_label=array_labels[index], x_axis_type="datetime")) # add line renderers to each figure figures[index].line(timestamps[::compress_constant] * 1000, data_array, line_color=Bokeh8[index], line_width=2) figures[index].add_tools(hover_tool) grid = gridplot(figures, sizing_mode="scale_both", ncols=3, plot_height=200, plot_width=300) if save: output_file(filename=graph_title + '.html', title=graph_title) show(grid) return
def _create_hover(tooltips=[('date', '$x{%F}'), ('value', '@y{0.000}')], formatters={'$x': 'datetime'}, mode='vline', **kwargs): hover = HoverTool(**kwargs) hover.tooltips = tooltips hover.formatters = formatters hover.mode = mode return hover
def make_plot(df): #Make the plot, save on .HTML file fig = figure(x_axis_label='Date', y_axis_label='Price', x_axis_type='datetime', plot_width=1024, plot_height=768) #datetime formatted_date = [] date = df['datetime'].tolist() for f in date: formatted_date.append(datetime.strptime(f, "%Y-%m-%d %H:%M:%S")) #Making the source source = ColumnDataSource( data={ 'price': df['daiusd_price'].tolist(), 'date': formatted_date, 'price_selling': df['daiusd_selling'].tolist(), 'price_purchase': df['daiusd_purchase'].tolist() }) #Drawing the lines fig.line(x='date', y='price', line_width=3, color='red', source=source, legend_label='DAI/USD price') fig.line(x='date', y='price_selling', line_width=3, color='blue', source=source, legend_label='DAI/USD selling price') fig.line(x='date', y='price_purchase', line_width=3, color='green', source=source, legend_label='DAI/USD purchase price') #Configuring hovers hover = HoverTool() hover.tooltips = [('DAI price', '$@{price}{%0.2f}'), ('Date', '@date{%F}'), ('DAI selling price', '$@{price_selling}{%0.2f}'), ('DAI purchase price', '$@{price_purchase}{%0.2f}')] hover.mode = 'vline' hover.formatters = { '@{price}': 'printf', '@date': 'datetime', '@{price_selling}': 'printf', '@{price_purchase}': 'printf' } #Quiting toolbar fig.toolbar_location = None #Adding hovers fig.add_tools(hover) #Save save(obj=fig, title='Dai price - Beta')
def fill_under_plot_stacked(data, target_col, date_col, span=500): """ Creates a plot with two lines and fills spaces between them. Stacks values Data - dataframe with datta to use in plotting target_columns - columns to include on the plot. Date is always included as x axis values. Columns supplied in format: (column name,name to display on hover tool) span - how much data to view on the plot [negative indexed] """ # calculating values of the higher plot data[target_col[0][0]] = data[target_col[0][0]] + data[target_col[1][0]] # defining data range data = data.iloc[-span:, :] # defining tooltips tooltips = [("Data", "@date{%F}"), (target_col[0][1], f"@{target_col[0][0]}" + "{0.0}"), (target_col[1][1], f"@{target_col[1][0]}" + "{0.0}")] # defining data source source = ColumnDataSource(data=data) # defining plot p = figure(plot_width=900, plot_height=400, x_axis_type="datetime", sizing_mode="scale_both") # plotting lines and areas line_1 = p.line(x="date", y=target_col[0][0], source=source, color="grey", line_width=2) line_2 = p.line(x="date", y=target_col[1][0], source=source, line_width=2, color="#2422bb") area_1 = p.varea(x="date", y1=target_col[0][0], y2=target_col[1][0], fill_color='grey', alpha=0.2, source=source) area_2 = p.varea(x="date", y1=0, y2=target_col[1][0], fill_color="#2422bb", alpha=0.2, source=source) # defining hover tools hover = HoverTool(tooltips=tooltips, mode='vline', point_policy='follow_mouse', renderers=[line_1]) hover.formatters = {"@date": "datetime"} p.tools.append(hover) return p
def pointplot(p, source, data_cols, colormap, hovertool, xlabelname, x_axis_type, **kwargs): """Adds pointplot to figure p for each data_col.""" N_cols = len(data_cols) # Define marker for pointplot: if "marker" in kwargs: markers = [kwargs["marker"]] * N_cols del kwargs["marker"] else: marker = [ "circle", "square", "triangle", "asterisk", "circle_x", "square_x", "inverted_triangle", "x", "circle_cross", "square_cross", "diamond", "cross", ] markers = marker * int(N_cols / 20 + 1) markers = markers[:N_cols] # Add scatter/point glyphs to figure: for name, color, marker in zip(data_cols, colormap, markers): glyph = p.scatter(x="x", y=str(name), legend=" " + str(name), source=source, color=color, marker=marker, **kwargs) if hovertool: my_hover = HoverTool(mode="vline", renderers=[glyph]) if x_axis_type == "datetime": my_hover.tooltips = [ (xlabelname, "@x{%F}"), (str(name), "@{%s}" % str(name)), ] my_hover.formatters = {"x": "datetime"} else: my_hover.tooltips = [ (xlabelname, "@x"), (str(name), "@{%s}" % str(name)), ] p.add_tools(my_hover) return p
def bar_line_plot(data, target_col, date_col, span=500): """ Creates a plot with bars and a line. Bars represent daily values, line represents 7 day rolling mean Data - dataframe with datta to use in plotting target_columns - columns to include on the plot. Date is always included as x axis values. Columns supplied in format: (column name,name to display on hover tool) date_col - column with dates span - variable used to restrict size of the plot. Number of days to display """ # calculating rolling mean data["rolling_mean"] = data[target_col[0]].rolling(7).mean() # clipping data to have length equal to span supplied data = data.iloc[-span:, :] # defining tooltips tooltips = [("Data", "@date{%F}"), ((target_col[1], f"@{target_col[0]}" + "{0,0}")), ("Średnia 7-dniowa", '@rolling_mean{0,0}')] source = ColumnDataSource(data=data) # creating figure, enabling sizing plots to fit containers on site p = figure(plot_width=900, plot_height=400, x_axis_type="datetime", sizing_mode="scale_both") # creatin bars and line plot bars = p.vbar(x="date", top=target_col[0], source=source, color="#2422bb", alpha=0.5, width=timedelta(days=1), legend_label=target_col[1]) line = p.line(x="date", y="rolling_mean", source=source, line_width=2, color="black", legend_label="Średnia 7-dniowa") # creating hoover tool hover = HoverTool(tooltips=tooltips, mode='vline', point_policy='follow_mouse', renderers=[line]) hover.formatters = { "@date": "datetime" } # specyfying datetime formater for date field in hoover tool p.tools.append(hover) # returning plot p.legend.location = "top_left" return p
def dash_line_plot(data, target_col, date_col, span=500): """ Creates a plot with two lines. One follows daily changes of the parameter, second one follows 7 day rolling mean. target_columns - columns to include on the plot. Date must be always included as x axis values. Supplied in format: (column name,name to display on hover tool) span - variable used to restrict size of the plot. Number of days to display """ # calculating the rolling mean data["rolling_mean"] = data[target_col[0]].rolling(7).mean() # clipping data to match span lenght data = data.iloc[-span:, :] # defining tooltips for hover tool and data source for bokeh to use tooltips = [("Data", "@date{%F}"), ((target_col[1], f"@{target_col[0]}" + "{0.0}")), ("Średnia 7-dniowa", '@rolling_mean' + "{0.0}")] source = ColumnDataSource(data=data) # defining fgure, scaling enabled p = figure(plot_width=900, plot_height=400, x_axis_type="datetime", sizing_mode="scale_width") # defining lines to display - dash line represents daily values, normaln line - rolling mean line_dash = p.line(x="date", y=target_col[0], source=source, color="grey", line_width=1, alpha=0.6, legend_label=target_col[1]) line = p.line(x="date", y="rolling_mean", source=source, line_width=2, color="#2422bb", legend_label="Średnia 7-dniowa") # plot often used to display values around zero - plotting horizontal line at zero hline = Span(location=0, dimension='width', line_color='black', line_width=1) p.renderers.extend([hline]) # creating hover tool hover = HoverTool(tooltips=tooltips, mode='vline', point_policy='follow_mouse', renderers=[line]) hover.formatters = {"@date": "datetime"} p.tools.append(hover) p.legend.location = "top_left" return p
def AddToolTip(self, plot, tooltips, formatters = None): # Create a hover tool hover_tool = HoverTool() # Set the tooltips hover_tool.tooltips = tooltips # Formatter for dates hover_tool.formatters = formatters # Add the tooltip plot.add_tools(hover_tool) return hover_tool
def lineplot(p, source, data_cols, colormap, hovertool, xlabelname, x_axis_type, plot_data_points, plot_data_points_size, **kwargs): """Adds lineplot to figure p for each data_col.""" if "marker" in kwargs: marker = kwargs["marker"] del kwargs["marker"] else: marker = "circle" # Add line (and optional scatter glyphs) to figure: for name, color in zip(data_cols, colormap): glyph = p.line(x="x", y=str(name), legend=" " + str(name), source=source, color=color, **kwargs) if plot_data_points: p.scatter( x="x", y=str(name), legend=" " + str(name), source=source, color=color, marker=marker, size=plot_data_points_size, ) if hovertool: my_hover = HoverTool(mode="vline", renderers=[glyph]) if x_axis_type == "datetime": my_hover.tooltips = [ (xlabelname, "@x{%F}"), (str(name), "@{%s}" % str(name)), ] my_hover.formatters = {"x": "datetime"} else: my_hover.tooltips = [ (xlabelname, "@x"), (str(name), "@{%s}" % str(name)), ] p.add_tools(my_hover) return p
def plot_2(self): group = self.valore temp = self.data().groupby(group).sum()[[ "NA_Sales", "EU_Sales", "JP_Sales", "Other_Sales" ]] temp = temp.div(temp.sum(axis=1), axis=0) temp = temp.reset_index() temp[group] = temp[group].astype("str") fruits = temp[group].tolist() years = ["NA_Sales", "EU_Sales", "JP_Sales", "Other_Sales"] p = figure( x_range=fruits, plot_height=350, title="Sales percentage for each area of the world grouped by " + str(group), toolbar_location=None, tools="") p.vbar_stack(years, x=group, width=0.9, source=temp, legend_label=years, color=Category20[11][2:6]) hover = HoverTool() hover.tooltips = [("Zone", "$name"), ("Value", "@$name")] hover.formatters = {'Value': 'printf'} p.add_tools(hover) p.y_range.start = 0 p.x_range.range_padding = 0.1 p.xgrid.grid_line_color = None p.axis.minor_tick_line_color = None p.outline_line_color = None p.legend.location = "top_left" p.legend.orientation = "vertical" p.add_layout(p.legend[0], 'right') if group == "Publisher": p.xaxis.major_label_orientation = 45 p.xaxis.axis_label_text_font_size = "2pt" return pn.pane.Bokeh(p)
def SelectCountry(attr, old, new): now_selected = list(set(new) - set(old)) was_selected = list(set(old) - set(new)) if now_selected: country = checkboxes.labels[now_selected[0]] if country_data.glyph_dict[country] == None: country_df = country_data.GetDataFrame(country) if tail == True: country_df = country_data.GetTail( country, x_data, y_data, tail_threshold) country_cds = ColumnDataSource(country_df) country_data.glyph_dict[country] = plot.line( x=x_data, y=y_data, source=country_cds, name=country, line_color=country_data.colour_dict[country], line_width=1) for tool in plot.tools: if type(tool).__name__ == 'HoverTool': plot.tools.remove(tool) # Create a hover tool hover_tool = HoverTool() # Set the tooltips hover_tool.tooltips = tooltips # Formatter for dates hover_tool.formatters = formatters # Add the tooltip plot.add_tools(hover_tool) country_data.glyph_dict[country].visible = True elif was_selected: country = checkboxes.labels[was_selected[0]] country_data.glyph_dict[country].visible = False
def createHoverTool(simg, cols): """ """ # Make the hovertool only follow the patches (still a hack) htline = simg ht = HoverTool() ht.tooltips = [("Time", "@index{%F %T}")] for col in cols: fStr = "@%s{0.00}" % (col) ht.tooltips.append((col, fStr)) ht.formatters = {'index': 'datetime'} ht.show_arrow = False ht.point_policy = 'follow_mouse' ht.line_policy = 'nearest' ht.renderers = [htline] return ht
def fill_dotplot(plot, source, data_field, tooltips=None, tooltips_formatters=None, js_tap_callback=None, server_tap_callback=None, lines=False, lower_bound=False): ''' General function for filling dotplots. Here are the possible parameters : tooltips: Bokeh Tooltip object to use for the plot tooltips_formatters: Formatter for the tooltip js_tap_callback: CustomJS object for client side click callback server_tap_callback: Callback object for server side click callback lines: Specify if lines should be drawn to connect the dots lower_bound: Specify if a lower bound interval should be displayed ''' # (Optional) Tooltip and tooltip formatters if tooltips is not None: hover = HoverTool(tooltips=tooltips, mode="vline", names=["circle"]) if tooltips_formatters is not None: hover.formatters = tooltips_formatters plot.add_tools(hover) # (Optional) Add TapTool (for JS tap callback) if js_tap_callback is not None: tap = TapTool(callback=CustomJS(code=js_tap_callback)) plot.add_tools(tap) # (Optional) Add segment to represent a lower bound if lower_bound: lower_segment = plot.segment(x0="%s_x" % data_field, y0=data_field, x1="%s_x" % data_field, y1="%s_lower_bound" % data_field, source=source, line_color="black") # Draw dots (actually Bokeh circles) circle = plot.circle(name="circle", x="%s_x" % data_field, y=data_field, source=source, size=12) # (Optional) Draw lines between dots if lines: line = plot.line(x="%s_x" % data_field, y=data_field, source=source) # (Optional) Add server tap callback if server_tap_callback is not None: circle.data_source.selected.on_change("indices", server_tap_callback) # Plot appearance plot.xgrid.grid_line_color = None plot.ygrid.grid_line_color = None plot.yaxis[0].formatter.power_limit_high = 0 plot.yaxis[0].formatter.power_limit_low = 0 plot.yaxis[0].formatter.precision = 3 plot.xaxis[0].major_label_orientation = pi / 8
def plot_multiple_lines(df: pd.DataFrame, title: str, x_axis: str, y_axis: str, category_column: str, x_axis_type: str = 'datetime', **kwargs): """ Cretes plot with multiple lines :param df: :param title: :param x_axis: :param y_axis: :param category_column: :param x_axis_type: :param kwargs: :return: """ """ prepare data """ if (x_axis in df.index.names) | (y_axis in df.index.names): df.reset_index(inplace=True) df[category_column] = df[category_column].apply(str) df_pivoted = df.pivot(index=x_axis, columns=category_column, values=y_axis) """ Multiple line chart """ custom_hover = HoverTool() p = figure(x_axis_type=x_axis_type, title=title, plot_width=kwargs.get('plot_width', 800), plot_height=kwargs.get('plot_height', 400), tools=[custom_hover, 'save']) legend_list = [] source = ColumnDataSource(df_pivoted) colours = create_multi_colour_pallete() if len(colours) < len(df[category_column].unique()): raise IndexError("""There are more categorical ({} categories) columns than there are colours ({} colours). Reduce categories or add more colours.""".format(str(len(df[category_column].unique())), str(len(colours)))) for ind, category_line in enumerate(df_pivoted.columns): line_g = p.line( x_axis, category_line, line_width=kwargs.get('line_width', 1), color=colours[ind], line_alpha=kwargs.get('line_alpha', 0.9), source=source ) legend_list.append(LegendItem(label=category_line, renderers=[line_g], index=ind)) """ hover tooltips """ x_axis_default_format = '{%F, %A}' if x_axis_type == 'datetime' else '' tooltips = [(x_axis, "@" + x_axis + kwargs.get('x_tooltip_format', x_axis_default_format))] + \ [("{} of {} {}".format(y_axis, category_column, y), "@" + y + kwargs.get('y_tooltip_format', '{0,0}')) for y in df_pivoted.columns] custom_hover.tooltips = get_custom_hover_tooltips(tooltips) custom_hover.formatters = {x_axis: x_axis_type} """ legend """ legend = Legend(items=legend_list, location=kwargs.get('legend_location', (10, 10))) p.add_layout(legend, kwargs.get('legend_placement', 'right')) """ axis """ p.xaxis.axis_label = kwargs.get('x_axis_label', x_axis) p.yaxis.axis_label = kwargs.get('y_axis_label', y_axis) p = format_axis(p, **kwargs) p = format_grid(p, **kwargs) return p
dell_2_time = pandas.to_datetime(dell_2_con, unit='s') juniper = result[(result.DeviceName == 'juniper') & (result.TypeId == 1234)] juniper_up = juniper["UpBytes"] juniper_down = juniper["DownBytes"] juniperconv = juniper["StatTime"] juniper_time = pandas.to_datetime(juniperconv, unit='s') p.multi_line(xs = [juniper_time, juniper_time], ys = [juniper_up, juniper_down] color=['red', 'blue'] line_width=1, legend='juniper') p.multi_line(xs = [cisco_time, cisco_time], ys = [cisco_up, cisco_down], color=['#EE0091','#2828B0'], line_width=1, legend='cisco') p.multi_line(xs = [hp_time, hp_time], ys = [hp_up, hp_down], color=['yellow','green'], line_width=1, legend='cisco') p.multi_line(xs = [cisco_time, cisco_time], ys = [cisco_up, cisco_down], color=['pink','black'], line_width=1, legend='cisco') p.multi_line(xs = [cisco_time, cisco_time], ys = [cisco_up, cisco_down], color=['#498ABF','#2F00E1'], line_width=1, legend='cisco') hover = HoverTool(tooltips = [('Time', '@x{int}'), ('Value', '@y{1.11} GB'), ('Device', '@DeviceName')]) hover.formatters = {"Date": "datetime"} p.legend.label_text_font = "times" p.legend.label_text_font_style = "italic" p.grid.grid_line_alpha=0.5 p.xaxis.major_tick_line_width = 3 p.xaxis.minor_tick_line_color = "navy" p.add_tools(hover) output_file("plotting.html", title="Device_Reports") show(p)
def fill_boxplot(plot, source, prefix="", tooltips=None, tooltips_formatters=None, js_tap_callback=None, server_tap_callback=None): ''' General function for filling boxplots. Here are the possible parameters : prefix: specify which prefix to use for the name of data fields tooltips: Bokeh Tooltip object to use for the plot tooltips_formatters: Formatter for the tooltip js_tap_callback: CustomJS object for client side click callback server_tap_callback: Callback object for server side click callback ''' # (Optional) Tooltip and tooltip formatters if tooltips is not None: hover = HoverTool(tooltips=tooltips, mode="vline", names=["full_box"]) if tooltips_formatters is not None: hover.formatters = tooltips_formatters plot.add_tools(hover) # (Optional) Add TapTool (for JS tap callback) if js_tap_callback is not None: tap = TapTool(callback=CustomJS(code=js_tap_callback)) plot.add_tools(tap) # Draw boxes (the prefix argument modifies the fields of ColumnDataSource # that are used) if prefix != "": prefix = "%s_" % prefix # Stems top_stem = plot.segment(x0="%sx" % prefix, y0="%smax" % prefix, x1="%sx" % prefix, y1="%squantile75" % prefix, source=source, line_color="black") bottom_stem = plot.segment(x0="%sx" % prefix, y0="%smin" % prefix, x1="%sx" % prefix, y1="%squantile25" % prefix, source=source, line_color="black") # Boxes full_box = plot.vbar(name="full_box", x="%sx" % prefix, width=0.5, top="%squantile75" % prefix, bottom="%squantile25" % prefix, source=source, line_color="black") bottom_box = plot.vbar(x="%sx" % prefix, width=0.5, top="%squantile50" % prefix, bottom="%squantile25" % prefix, source=source, line_color="black") # Mu dot mu_dot = plot.dot(x="%sx" % prefix, y="%smu" % prefix, size=30, source=source, color="black") # (Optional) Add server tap callback if server_tap_callback is not None: top_stem.data_source.selected.on_change("indices", server_tap_callback) bottom_stem.data_source.selected.on_change("indices", server_tap_callback) full_box.data_source.selected.on_change("indices", server_tap_callback) bottom_box.data_source.selected.on_change("indices", server_tap_callback) mu_dot.data_source.selected.on_change("indices", server_tap_callback) # Plot appearance plot.xgrid.grid_line_color = None plot.ygrid.grid_line_color = None plot.yaxis[0].formatter.power_limit_high = 0 plot.yaxis[0].formatter.power_limit_low = 0 plot.yaxis[0].formatter.precision = 3 plot.xaxis[0].major_label_orientation = pi / 8
def scatterplot(p, x, y, category, category_values, colormap, hovertool, x_axis_type, xlabelname, ylabelname, **kwargs): """Adds a scatterplot to figure p for each data_col.""" # Set standard size and linecolor of markers: if "size" not in kwargs: kwargs["size"] = 10 if "line_color" not in kwargs: kwargs["line_color"] = "black" # Define source: source = ColumnDataSource({"x": x, "y": y}) # Define Colormapper for categorical scatterplot: if not category is None: category = str(category) source.data[category] = category_values # Make numerical categorical scatterplot: if check_type(category_values) == "numeric": kwargs["legend"] = category + " " # Define colormapper for numerical scatterplot: if colormap == None: colormap = Inferno256 elif isinstance(colormap, str): if colormap in all_palettes: colormap = all_palettes[colormap] max_key = max(colormap.keys()) colormap = colormap[max_key] else: raise ValueError( "Could not find <colormap> with name %s. The following predefined colormaps are supported (see also https://bokeh.pydata.org/en/latest/docs/reference/palettes.html ): %s" % (colormap, list(all_palettes.keys()))) elif isinstance(colormap, (list, tuple)): pass else: raise ValueError( "<colormap> can onyl be None, a name of a colorpalette as string( see https://bokeh.pydata.org/en/latest/docs/reference/palettes.html ) or a list/tuple of colors." ) colormapper = LinearColorMapper(palette=colormap) # Set fill-color to colormapper: kwargs["fill_color"] = { "field": category, "transform": colormapper } # Define Colorbar: colorbar_options = { "color_mapper": colormapper, "label_standoff": 0, "border_line_color": None, "location": (0, 0), } colorbar = ColorBar(**colorbar_options) p.add_layout(colorbar, "right") # Draw glyph: glyph = p.scatter(x="x", y="y", source=source, **kwargs) # Add Hovertool if hovertool: my_hover = HoverTool(renderers=[glyph]) if x_axis_type == "datetime": my_hover.tooltips = [(xlabelname, "@x{%F}"), (ylabelname, "@y")] my_hover.formatters = {"x": "datetime"} else: my_hover.tooltips = [(xlabelname, "@x"), (ylabelname, "@y")] my_hover.tooltips.append((str(category), "@{%s}" % category)) p.add_tools(my_hover) # Make categorical scatterplot: elif check_type(category_values) == "object": # Define colormapper for categorical scatterplot: labels, categories = pd.factorize(category_values) colormap = get_colormap(colormap, len(categories)) # Draw each category as separate glyph: x, y = source.data["x"], source.data["y"] for cat, color in zip(categories, colormap): x_cat = x[category_values == cat] y_cat = y[category_values == cat] cat_cat = category_values[category_values == cat] source = ColumnDataSource({ "x": x_cat, "y": y_cat, "category": cat_cat }) # Draw glyph: glyph = p.scatter(x="x", y="y", legend=str(cat) + " ", source=source, color=color, **kwargs) # Add Hovertool if hovertool: my_hover = HoverTool(renderers=[glyph]) if x_axis_type == "datetime": my_hover.tooltips = [(xlabelname, "@x{%F}"), (ylabelname, "@y")] my_hover.formatters = {"x": "datetime"} else: my_hover.tooltips = [(xlabelname, "@x"), (ylabelname, "@y")] my_hover.tooltips.append((str(category), "@category")) p.add_tools(my_hover) if len(categories) > 5: warnings.warn( "There are more than 5 categories in the scatterplot. The legend might be crowded, to hide the axis you can pass 'legend=False' as an optional argument." ) else: raise ValueError( "<category> is not supported with datetime objects. Consider casting the datetime objects to strings, which can be used as <category> values." ) # Draw non categorical plot: else: # Draw glyph: glyph = p.scatter(x="x", y="y", source=source, **kwargs) # Add Hovertool: if hovertool: my_hover = HoverTool(renderers=[glyph]) if x_axis_type == "datetime": my_hover.tooltips = [(xlabelname, "@x{%F}"), (ylabelname, "@y")] my_hover.formatters = {"x": "datetime"} else: my_hover.tooltips = [(xlabelname, "@x"), (ylabelname, "@y")] p.add_tools(my_hover) return p
def assembly_chart(df, complements): """function to assembly the chart""" print('starting the plot...') # specify the output file name output_file("movigrama_chart.html") # force to show only one plot when multiples executions of the code occur # otherwise the plots will append each time one new calling is done reset_output() # create ColumnDataSource objects directly from Pandas data frames source = ColumnDataSource(df) # use the column DT as index df.set_index('DT', inplace=True) ########################################################################### # # Movigrama Plot # ########################################################################### # build figure of the plot p = figure(x_axis_type='datetime', x_axis_label='days of moviment', y_axis_label='unities movimented', plot_width=1230, plot_height=500, active_scroll='wheel_zoom') # TODO Specify X range (not all plots have 365 days of moviment) # build the Stock Level bar r1 = p.vbar(x='DT', bottom=0, top='STOCK', width=pd.Timedelta(days=1), fill_alpha=0.4, color='paleturquoise', source=source) # build the OUT bar p.vbar(x='DT', bottom=0, top='SOMA_SAI', width=pd.Timedelta(days=1), fill_alpha=0.8, color='crimson', source=source) # build the IN bar p.vbar(x='DT', bottom=0, top='SOMA_ENTRA', width=pd.Timedelta(days=1), fill_alpha=0.8, color='seagreen', source=source) # edit title # adds warehouse title p.add_layout( Title(text=complements['warehouse'], text_font='helvetica', text_font_size='10pt', text_color='orangered', text_alpha=0.5, align='center', text_font_style="italic"), 'above') # adds product title p.add_layout( Title(text=complements['product'], text_font='helvetica', text_font_size='10pt', text_color='orangered', text_alpha=0.5, align='center', text_font_style="italic"), 'above') # adds main title p.add_layout( Title(text='Movigrama Endicon', text_font='helvetica', text_font_size='16pt', text_color='orangered', text_alpha=0.9, align='center', text_font_style="bold"), 'above') # adds horizontal line hline = Span(location=0, line_alpha=0.4, dimension='width', line_color='gray', line_width=3) p.renderers.extend([hline]) # adapt the range to the plot p.x_range.range_padding = 0.1 p.y_range.range_padding = 0.1 # format the plot's outline p.outline_line_width = 4 p.outline_line_alpha = 0.1 p.outline_line_color = 'orangered' # format major labels p.axis.major_label_text_color = 'gray' p.axis.major_label_text_font_style = 'bold' # format labels p.axis.axis_label_text_color = 'gray' p.axis.axis_label_text_font_style = 'bold' # p.xgrid.grid_line_color = None # disable vertical bars # p.ygrid.grid_line_color = None # disable horizontal bars # change placement of minor and major ticks in the plot p.axis.major_tick_out = 10 p.axis.minor_tick_in = -3 p.axis.minor_tick_out = 6 p.axis.minor_tick_line_color = 'gray' # format properly the X datetime axis p.xaxis.formatter = DatetimeTickFormatter(days=['%d/%m'], months=['%m/%Y'], years=['%Y']) # iniciate hover object hover = HoverTool() hover.mode = "vline" # activate hover by vertical line hover.tooltips = [("SUM-IN", "@SOMA_ENTRA"), ("SUM-OUT", "@SOMA_SAI"), ("COUNT-IN", "@TRANSACT_ENTRA"), ("COUNT-OUT", "@TRANSACT_SAI"), ("STOCK", "@STOCK"), ("DT", "@DT{%d/%m/%Y}")] # use 'datetime' formatter for 'DT' field hover.formatters = {"DT": 'datetime'} hover.renderers = [r1] # display tolltip only to one render p.add_tools(hover) ########################################################################### # # Demand analysis # ########################################################################### # change to positive values df['out_invert'] = df['SOMA_SAI'] * -1 # moving average with n=30 days df['MA30'] = df['out_invert'].rolling(30).mean().round(0) # moving standard deviation with n=30 days df['MA30_std'] = df['out_invert'].rolling(30).std().round(0) # lower control limit for 1 sigma deviation df['lcl_1sigma'] = (df['MA30'] - df['MA30_std']) # upper control limit for 1 sigma deviation df['ucl_1sigma'] = (df['MA30'] + df['MA30_std']) source = ColumnDataSource(df) p1 = figure(plot_width=1230, plot_height=500, x_range=p.x_range, x_axis_type="datetime", active_scroll='wheel_zoom') # build the Sum_out bar r1 = p1.vbar(x='DT', top='out_invert', width=pd.Timedelta(days=1), color='darkred', line_color='salmon', fill_alpha=0.4, source=source) # build the moving average line p1.line(x='DT', y='MA30', source=source) # build the confidence interval band = Band(base='DT', lower='lcl_1sigma', upper='ucl_1sigma', source=source, level='underlay', fill_alpha=1.0, line_width=1, line_color='black') p1.renderers.extend([band]) # adds title p1.add_layout( Title(text='Demand Variability', text_font='helvetica', text_font_size='16pt', text_color='orangered', text_alpha=0.5, align='center', text_font_style="bold"), 'above') # adds horizontal line hline = Span(location=0, line_alpha=0.4, dimension='width', line_color='gray', line_width=3) p1.renderers.extend([hline]) # format the plot's outline p1.outline_line_width = 4 p1.outline_line_alpha = 0.1 p1.outline_line_color = 'orangered' # format major labels p1.axis.major_label_text_color = 'gray' p1.axis.major_label_text_font_style = 'bold' # format labels p1.axis.axis_label_text_color = 'gray' p1.axis.axis_label_text_font_style = 'bold' # change placement of minor and major ticks in the plot p1.axis.major_tick_out = 10 p1.axis.minor_tick_in = -3 p1.axis.minor_tick_out = 6 p1.axis.minor_tick_line_color = 'gray' # format properly the X datetime axis p1.xaxis.formatter = DatetimeTickFormatter(days=['%d/%m'], months=['%m/%Y'], years=['%Y']) # iniciate hover object hover = HoverTool() hover.mode = "vline" # activate hover by vertical line hover.tooltips = [("DEMAND", '@out_invert'), ("UCL 1σ", "@ucl_1sigma"), ("LCL 1σ", "@lcl_1sigma"), ("M AVG 30d", "@MA30"), ("DT", "@DT{%d/%m/%Y}")] # use 'datetime' formatter for 'DT' field hover.formatters = {"DT": 'datetime'} hover.renderers = [r1] # display tolltip only to one render p1.add_tools(hover) ########################################################################### # # Demand groupped by month # ########################################################################### resample_M = df.iloc[:, 0:6].resample('M').sum() # resample to month # create column date as string resample_M['date'] = resample_M.index.strftime('%b/%y').values # moving average with n=3 months resample_M['MA3'] = resample_M['out_invert'].rolling(3).mean() resample_M['MA3'] = np.ceil(resample_M.MA3) # round up the column MA3 # resample to month with mean resample_M['mean'] = np.ceil(resample_M['out_invert'].mean()) # resample to month with standard deviation resample_M['std'] = np.ceil(resample_M['out_invert'].std()) # moving standard deviation with n=30 days resample_M['MA3_std'] = np.ceil(resample_M['out_invert'].rolling(3).std()) # lower control limit for 1 sigma deviation resample_M['lcl_1sigma'] = resample_M['MA3'] - resample_M['MA3_std'] # upper control limit for 1 sigma deviation resample_M['ucl_1sigma'] = resample_M['MA3'] + resample_M['MA3_std'] source = ColumnDataSource(resample_M) p2 = figure(plot_width=1230, plot_height=500, x_range=FactorRange(factors=list(resample_M.date)), title='demand groupped by month') colors = factor_cmap('date', palette=Category20_20, factors=list(resample_M.date)) p2.vbar(x='date', top='out_invert', width=0.8, fill_color=colors, fill_alpha=0.8, source=source, legend=value('OUT')) p2.line(x='date', y='MA3', color='red', line_width=3, line_dash='dotted', source=source, legend=value('MA3')) p2.line(x='date', y='mean', color='blue', line_width=3, line_dash='dotted', source=source, legend=value('mean')) band = Band(base='date', lower='lcl_1sigma', upper='ucl_1sigma', source=source, level='underlay', fill_alpha=1.0, line_width=1, line_color='black') labels1 = LabelSet(x='date', y='MA3', text='MA3', level='glyph', y_offset=5, source=source, render_mode='canvas', text_font_size="8pt", text_color='darkred') labels2 = LabelSet(x='date', y='out_invert', text='out_invert', level='glyph', y_offset=5, source=source, render_mode='canvas', text_font_size="8pt", text_color='gray') low_box = BoxAnnotation( top=resample_M['mean'].iloc[0] - resample_M['std'].iloc[0], # analysis:ignore fill_alpha=0.1, fill_color='red') mid_box = BoxAnnotation( bottom=resample_M['mean'].iloc[0] - resample_M['std'].iloc[0], # analysis:ignore top=resample_M['mean'].iloc[0] + resample_M['std'].iloc[0], # analysis:ignore fill_alpha=0.1, fill_color='green') high_box = BoxAnnotation( bottom=resample_M['mean'].iloc[0] + resample_M['std'].iloc[0], # analysis:ignore fill_alpha=0.1, fill_color='red') p2.renderers.extend([band, labels1, labels2, low_box, mid_box, high_box]) p2.legend.click_policy = "hide" p2.legend.background_fill_alpha = 0.4 p2.add_layout( Title(text='Demand Grouped by Month', text_font='helvetica', text_font_size='16pt', text_color='orangered', text_alpha=0.5, align='center', text_font_style="bold"), 'above') # adds horizontal line hline = Span(location=0, line_alpha=0.4, dimension='width', line_color='gray', line_width=3) p2.renderers.extend([hline]) # format the plot's outline p2.outline_line_width = 4 p2.outline_line_alpha = 0.1 p2.outline_line_color = 'orangered' # format major labels p2.axis.major_label_text_color = 'gray' p2.axis.major_label_text_font_style = 'bold' # format labels p2.axis.axis_label_text_color = 'gray' p2.axis.axis_label_text_font_style = 'bold' # change placement of minor and major ticks in the plot p2.axis.major_tick_out = 10 p2.axis.minor_tick_in = -3 p2.axis.minor_tick_out = 6 p2.axis.minor_tick_line_color = 'gray' # iniciate hover object # TODO develop hoverTool # hover = HoverTool() # hover.mode = "vline" # activate hover by vertical line # hover.tooltips = [("SUM-IN", "@SOMA_ENTRA"), # ("SUM-OUT", "@SOMA_SAI"), # ("COUNT-IN", "@TRANSACT_ENTRA"), # ("COUNT-OUT", "@TRANSACT_SAI"), # ("STOCK", "@STOCK")] # hover.renderers = [r1] # display tolltip only to one render # p2.add_tools(hover) ########################################################################### # # Plot figures # ########################################################################### # put the results in a column and show show(column(p, p1, p2)) # show(p) # plot action print('plot finished')
def plot_single_line(df: pd.DataFrame, x_axis: str, y_axis: str, title: str, x_axis_type: str = 'datetime', colour_name: str = 'blue', colour_code: str = '500', md_design_colour: bool = True, show_legend: bool = False, **kwargs) -> figure: """ Creates a single line Bokeh chart :param df: dataframe with the x and y values :param x_axis: column name in df used for the x axis :param y_axis: column name in df used for the y axis :param title: title for figure :param x_axis_type: if axis type is datetime or linear (default: datetime) :param colour_name: colour name used by material design :param colour_code: colour code used by material desgin :param md_design_colour: if we should use Material Design's colours, otherwise a hex code can be passed in line_colour :param show_legend: if legend should be shown :param kwargs: extra information that can be passed :return: Bokehfigure with line chart """ """ prepare data """ if (x_axis in df.index.names) | (y_axis in df.index.names): df.reset_index(inplace=True) if x_axis_type == 'datetime': df = df.sort_values(x_axis, ascending=True) source = ColumnDataSource(df) """ line plot """ custom_hover = HoverTool() p = figure(x_axis_type=x_axis_type, title=title, plot_width=kwargs.get('plot_width', 700), plot_height=kwargs.get('plot_height', 350), tools=[custom_hover, 'save']) if md_design_colour: line_colour = get_colour_hex_code( colour_name, colour_code ) else: line_colour = kwargs.get('line_colour', '#2196f3') line_chart = p.line(x_axis, y_axis, line_width=kwargs.get('line_width', 1), color=line_colour, source=source) """ hover tooltips """ x_axis_default_format = "{%F, %A}" if x_axis_type == 'datetime' else '' tooltips = [(x_axis, "@" + x_axis + kwargs.get('x_tooltip_format', x_axis_default_format)), (y_axis, "@" + y_axis + kwargs.get('y_tooltip_format', '{0,0}'))] custom_hover.tooltips = get_custom_hover_tooltips(tooltips) custom_hover.formatters = {x_axis: x_axis_type} p.add_tools(custom_hover) """ legend """ if show_legend: legend = Legend( items=[LegendItem(label=kwargs.get('y_axis_label', y_axis), renderers=[line_chart], index=0)], location=kwargs.get('legend_location', (10, 10)) ) p.add_layout(legend, kwargs.get('legend_placement', 'below')) """ axis """ p.xaxis.axis_label = kwargs.get('x_axis_label', x_axis) p.yaxis.axis_label = kwargs.get('y_axis_label', y_axis) p = format_axis(p, **kwargs) p = format_grid(p, **kwargs) return p
def fill_dotplot(plot, source, data_field, tooltips=None, tooltips_formatters=None, js_tap_callback=None, server_tap_callback=None, lines=False, lower_bound=False, second_series=None, legend=None, second_legend=None, custom_colors="#1f77b4"): ''' General function for filling dotplots. Here are the possible parameters : tooltips: Bokeh Tooltip object to use for the plot tooltips_formatters: Formatter for the tooltip js_tap_callback: CustomJS object for client side click callback server_tap_callback: Callback object for server side click callback lines: Specify if lines should be drawn to connect the dots lower_bound: Specify if a lower bound interval should be displayed second_series: Name of a second data series to plot on the same figure. It should also have its own x series with the "_x" prefix. legend: lengend for the first data series second_legend: same for the second optional data series custom_colors: Will plot additional glyphs with a custom color (to display check errors for instance). Should be the name of the series of colors. ''' # (Optional) Tooltip and tooltip formatters if tooltips is not None: hover = HoverTool(tooltips=tooltips, mode="vline", names=["circle"]) if tooltips_formatters is not None: hover.formatters = tooltips_formatters plot.add_tools(hover) # (Optional) Add TapTool (for JS tap callback) if js_tap_callback is not None: tap = TapTool(callback=CustomJS(code=js_tap_callback)) plot.add_tools(tap) # (Optional) Add segment to represent a lower bound if lower_bound: lower_segment = plot.segment(x0="%s_x" % data_field, y0=data_field, x1="%s_x" % data_field, y1="%s_lower_bound" % data_field, source=source, line_color="black") # (Optional) Draw a second data series if second_series is not None: if second_legend is not None: second_circle = plot.circle(name="second_circle", x="%s_x" % data_field, y=second_series, source=source, size=12, fill_color="gray", line_color="gray", legend_label=second_legend) else: second_circle = plot.circle( name="second_circle", x="%s_x" % data_field, y=second_series, source=source, size=12, fill_color="gray", line_color="gray", ) if lines: second_line = plot.line(x="%s_x" % data_field, y=second_series, source=source, color="gray", line_dash="dashed") # (Optional) Draw lines between dots if lines: line = plot.line(x="%s_x" % data_field, y=data_field, source=source) # Draw dots (actually Bokeh circles) if legend is not None: circle = plot.circle(name="circle", x="%s_x" % data_field, y=data_field, source=source, size=12, fill_color=custom_colors, line_color=custom_colors, legend_label=legend) else: circle = plot.circle(name="circle", x="%s_x" % data_field, y=data_field, source=source, size=12, fill_color=custom_colors, line_color=custom_colors) # (Optional) Add server tap callback if server_tap_callback is not None: circle.data_source.selected.on_change("indices", server_tap_callback) # Plot appearance plot.xgrid.grid_line_color = None plot.ygrid.grid_line_color = None plot.yaxis[0].formatter.power_limit_high = 0 plot.yaxis[0].formatter.power_limit_low = 0 plot.yaxis[0].formatter.precision = 3 plot.xaxis[0].major_label_orientation = pi / 8
from bokeh.models.widgets import Slider, RangeSlider, CheckboxGroup, Button, TextInput, Paragraph from bokeh.models.widgets import Panel, Tabs from bokeh.models.widgets import DataTable, DateFormatter, TableColumn import sys import waveform from participant import participant from xlrd import open_workbook import os import glob # Hover tool definitions hover = HoverTool(tooltips=[('Time', '@index{%H:%M:%S:%3Nms}'), ('index', '$index')], mode='vline') hover.formatters = {'index': 'datetime'} vs_hover = HoverTool(tooltips=[('Time', '@DateTime{%Y-%m-%d-%H:%M}'), ('index', '$index')], mode='vline') vs_hover.formatters = {'DateTime': 'datetime'} dt_axis_format = ["%d-%m-%Y %H:%M"] vs_x_axis = DatetimeTickFormatter( hours=dt_axis_format, days=dt_axis_format, months=dt_axis_format, years=dt_axis_format, ) wf_classes = [
def plot( df_in, x=None, y=None, kind="line", figsize=None, use_index=True, title="", grid=None, # TODO: legend="top_right", logx=False, logy=False, xlabel=None, ylabel=None, xticks=None, yticks=None, xlim=None, ylim=None, fontsize=None, # TODO: color=None, colormap=None, category=None, histogram_type="topontop", stacked=False, weights=None, bins=None, normed=False, cumulative=False, show_average=False, plot_data_points=False, plot_data_points_size=5, show_figure=True, return_html=False, panning=True, zooming=True, toolbar_location="right", hovertool=True, vertical_xlabel=False, webgl=True, **kwargs): # TODO: Make docstring """Method for creating a interactive with 'Bokeh' as plotting backend. Available plot kinds are: * line * point * scatter * bar * histogram Examples -------- >>> df.plot_bokeh.line() >>> df.plot_bokeh.scatter(x='x',y='y') These plotting methods can also be accessed by calling the accessor as a method with the ``kind`` argument: ``df.plot_bokeh(kind='line')`` is equivalent to ``df.plot_bokeh.line()`` For more informations about the individual plot kind implementations, have a look at the underlying methods (like df.plot_bokeh.line) or visit https://github.com/PatrikHlobil/Pandas-Bokeh. """ # Make a local copy of the DataFrame: df = df_in.copy() if isinstance(df, pd.Series): df = pd.DataFrame(df) # Get and check options for base figure: figure_options = { "title": title, "toolbar_location": toolbar_location, "active_scroll": "wheel_zoom", "plot_width": 600, "plot_height": 400, "output_backend": "webgl", } if not figsize is None: width, height = figsize figure_options["plot_width"] = width figure_options["plot_height"] = height if logx: figure_options["x_axis_type"] = "log" if logy: figure_options["y_axis_type"] = "log" if not xlabel is None: figure_options["x_axis_label"] = xlabel if not ylabel is None: figure_options["y_axis_label"] = ylabel if not xlim is None: if not isinstance(xlim, (tuple, list)): raise ValueError( "<xlim> must be a list/tuple of form (x_min, x_max).") elif len(xlim) != 2: raise ValueError( "<xlim> must be a list/tuple of form (x_min, x_max).") else: figure_options["x_range"] = xlim if not ylim is None: if not isinstance(ylim, (tuple, list)): raise ValueError( "<ylim> must be a list/tuple of form (y_min, y_max).") elif len(ylim) != 2: raise ValueError( "<ylim> must be a list/tuple of form (y_min, y_max).") else: figure_options["y_range"] = ylim if webgl: figure_options["output_backend"] = "webgl" # Set standard linewidth: if "line_width" not in kwargs: kwargs["line_width"] = 2 # Get x-axis Name and Values: delete_in_y = None if not x is None: if x in df.columns: delete_in_y = x name = str(x) x = df[x].values elif isinstance(x, (tuple, list, type(np.array))): if len(x) == len(df): x = x name = "" else: raise Exception( "Length of provided <x> argument does not fit length of DataFrame or Series." ) else: raise Exception( "Please provide for the <x> parameter either a column name of the DataFrame/Series or an array of the same length." ) else: if use_index: x = df.index.values if not df.index.name is None: name = str(df.index.name) else: name = "" else: x = np.linspace(0, len(df) - 1, len(df)) name = "" if "x_axis_label" not in figure_options and not name is None: figure_options["x_axis_label"] = name # Check type of x-axis: if check_type(x) == "datetime": figure_options["x_axis_type"] = "datetime" xaxis_type = "datetime" if not xlim is None: starttime, endtime = xlim try: starttime = pd.to_datetime(starttime) except: raise ValueError( "Could not parse x_min input of <xlim> as datetime.") try: endtime = pd.to_datetime(endtime) except: raise ValueError( "Could not parse x_max input of <xlim> as datetime.") figure_options["x_range"] = (starttime, endtime) elif check_type(x) == "numeric": xaxis_type = "numerical" else: xaxis_type = "categorical" if kind == "bar": xaxis_type = "categorical" if xaxis_type == "categorical": x = [str(el) for el in x] if kind != "hist": figure_options["x_range"] = x if "x_axis_type" in figure_options: del figure_options["x_axis_type"] # Determine data cols to plot (only plot numeric data): if y is None: cols = df.columns elif not isinstance(y, (list, tuple)): cols = [y] else: cols = y data_cols = [] for i, col in enumerate(cols): if col not in df.columns: raise Exception( "Could not find '%s' in the columns of the provided DataFrame/Series. Please provide for the <y> parameter either a column name of the DataFrame/Series or an array of the same length." % col) if np.issubdtype(df[col].dtype, np.number): data_cols.append(col) N_cols = len(data_cols) if N_cols == 0: raise Exception("No numeric data columns found for plotting.") # Delete x column if it appears in y columns: if not delete_in_y is None: if delete_in_y in data_cols: data_cols.remove(delete_in_y) # Create Figure for plotting: p = figure(**figure_options) if "x_axis_type" not in figure_options: figure_options["x_axis_type"] = None # Define xlabel name as "x" if no label is provided by user or data: xlabelname = (figure_options["x_axis_label"] if figure_options["x_axis_label"] != "" else "x") # Define ColumnDataSource for Plot if kind != "hist": if kind != "hist": source = {str(col): df[col].values for col in data_cols} source["x"] = x # Define colormap if kind != "scatter": colormap = get_colormap(colormap, N_cols) if not color is None: colormap = get_colormap([color], N_cols) # Add Glyphs to Plot: if kind == "line": p = lineplot(p, source, data_cols, colormap, hovertool, xlabelname, figure_options["x_axis_type"], plot_data_points, plot_data_points_size, **kwargs) if kind == "point": p = pointplot(p, source, data_cols, colormap, hovertool, xlabelname, figure_options["x_axis_type"], **kwargs) if kind == "scatter": if N_cols > 2: raise Exception( "For scatterplots <x> and <y> values can only be a single column of the DataFrame, not a list of columns. Please specify both <x> and <y> columns for a scatterplot uniquely." ) # Get and set y-labelname: y_column = data_cols[0] if "y_axis_label" not in figure_options: p.yaxis.axis_label = str(y_column) # Get values for y-axis: y = df[y_column].values # Get values for categorical colormap: category_values = None if category in df.columns: category_values = df[category].values elif not category is None: raise Exception( "<category> parameter has to be either None or the name of a single column of the DataFrame" ) scatterplot(p, x, y, category, category_values, colormap, hovertool, x_axis_type=figure_options["x_axis_type"], xlabelname=xlabelname, ylabelname=str(y_column), **kwargs) if kind == "bar": # Define data source for barplot: data = {str(col): df[col].values for col in data_cols} data["x"] = x source = ColumnDataSource(data) # Create Figure (just for categorical barplots): figure_options["x_range"] = x del figure_options["x_axis_type"] p = figure(**figure_options) figure_options["x_axis_type"] = None if N_cols >= 3: base_width = 0.5 else: base_width = 0.35 width = base_width / (N_cols - 0.5) if N_cols == 1: shifts = [0] else: delta_shift = base_width / (N_cols - 1) shifts = [-base_width / 2 + i * delta_shift for i in range(N_cols)] for i, name, color, shift in zip(range(N_cols), data_cols, colormap, shifts): glyph = p.vbar(x=dodge("x", shift, range=p.x_range), top=str(name), width=width, source=source, color=color, legend=" " + str(name), **kwargs) if hovertool: my_hover = HoverTool(mode="vline", renderers=[glyph]) if figure_options["x_axis_type"] == "datetime": my_hover.tooltips = [ (xlabelname, "@x{%F}"), (str(name), "@{%s}" % str(name)), ] my_hover.formatters = {"x": "datetime"} else: my_hover.tooltips = [ (xlabelname, "@x"), (str(name), "@{%s}" % str(name)), ] p.add_tools(my_hover) if kind == "hist": # Check for stacked keyword: if stacked and histogram_type != "stacked": warnings.warn( "<histogram_type> was set to '%s', but was overriden by <stacked>=True parameter." % histogram_type) histogram_type = "stacked" # Set xlabel if only one y-column is given and user does not override this via # xlabel parameter: if len(data_cols) == 1 and xlabel is None: p.xaxis.axis_label = data_cols[0] # If Histogram should be plotted, calculate bins, aggregates and # averages: if bins is None: values = df[data_cols].values values = values[~np.isnan(values)] data, bins = np.histogram(values) if not weights is None: if weights not in df.columns: raise ValueError( "Columns '%s' for <weights> is not in provided DataFrame.") else: weights = df[weights].values aggregates = [] averages = [] for col in data_cols: values = df[col].values if not weights is None: not_nan = ~(np.isnan(values) | np.isnan(weights)) values_not_nan = values[not_nan] weights_not_nan = weights[not_nan] if sum(not_nan) < len(not_nan): warnings.warn( "There are NaN values in column '%s' or in the <weights> column. For the histogram, these rows have been neglected." % col, Warning, ) else: not_nan = ~np.isnan(values) values_not_nan = values[not_nan] weights_not_nan = None if sum(not_nan) < len(not_nan): warnings.warn( "There are NaN values in column '%s'. For the histogram, these rows have been neglected." % col, Warning, ) average = np.average(values_not_nan, weights=weights_not_nan) averages.append(average) data, bins = np.histogram(values_not_nan, bins=bins, weights=weights_not_nan) if normed: data = data / np.sum(data) * normed if cumulative: data = np.cumsum(data) aggregates.append(data) p = histogram(p, data_cols, colormap, aggregates, bins, averages, hovertool, normed, cumulative, show_average, histogram_type, **kwargs) if kind == "area": p = areaplot(p, source, data_cols, colormap, hovertool, xlabelname, figure_options["x_axis_type"], stacked, **kwargs) # Set xticks: if not xticks is None: p.xaxis[0].ticker = list(xticks) elif xaxis_type == "numerical" and kind not in ["hist", "scatter"]: p.xaxis.ticker = x if not yticks is None: p.yaxis.ticker = yticks # Format datetime ticks correctly: if figure_options["x_axis_type"] == "datetime": p.xaxis.formatter = DatetimeTickFormatter( milliseconds=["%H:%M:%S.%f"], seconds=["%H:%M:%S"], minutes=["%H:%M:%S"], hours=["%H:%M:%S"], days=["%d %B %Y"], months=["%d %B %Y"], years=["%d %B %Y"], ) # Rotate xlabel if wanted: if vertical_xlabel: p.xaxis.major_label_orientation = np.pi / 2 # Set click policy for legend: if not (kind == "area" and stacked): p.legend.click_policy = "hide" # Hide legend if wanted: if not legend: p.legend.visible = False # Modify legend position: else: if legend is True: p.legend.location = "top_right" elif legend in [ "top_left", "top_center", "top_right", "center_left", "center", "center_right", "bottom_left", "bottom_center", "bottom_right", ]: p.legend.location = legend else: raise ValueError( "Legend can only be True/False or one of 'top_left', 'top_center', 'top_right', 'center_left', 'center', 'center_right', 'bottom_left', 'bottom_center', 'bottom_right'" ) # Display plot if wanted if show_figure: show(p) # Return as (embeddable) HTML if wanted: if return_html: return embedded_html(p) # Return plot: return p
def fill_barplot( plot, source, single_series=None, double_series=None, tooltips=None, tooltips_formatters=None, js_tap_callback=None, server_tap_callback=None, ): ''' General function for filling barplots. Here are the possible parameters : single_series: Series that display one value at each x (string) double_series: Series that display two values at each x (list of strings, size 2) columns: Array of columns to display. Size should be coherent with "check_mode". legend: Array of texts to put in the legend. This should be specified when plotting more than one culum, and its size should be coherent with "check_mode". tooltips: Bokeh Tooltip object to use for the plot tooltips_formatters: Formatter for the tooltip js_tap_callback: CustomJS object for client side click callback server_tap_callback: Callback object for server side click callback ''' vbars = [] vbars_names = [] # Draw "single" vbar if single_series is not None: vbar = plot.vbar(name="vbar", x="x", width=0.5, top=single_series, source=source) vbars.append(vbar) vbars_names.append("vbar") # Draw "double" vbars if double_series is not None: vbar1 = plot.vbar(name="vbar1", x=dodge("x", -0.15, range=plot.x_range), width=0.25, top=double_series[0], source=source) vbar2 = plot.vbar(name="vbar2", x=dodge("x", 0.15, range=plot.x_range), width=0.25, top=double_series[1], source=source, line_color="gray", fill_color="gray") vbars.append(vbar1) vbars.append(vbar2) vbars_names.append("vbar1") vbars_names.append("vbar2") # (Optional) Tooltip and tooltip formatters if tooltips is not None: hover = HoverTool(tooltips=tooltips, mode="vline", names=vbars_names) if tooltips_formatters is not None: hover.formatters = tooltips_formatters plot.add_tools(hover) # (Optional) Add server tap callback if server_tap_callback is not None: for vbar in vbars: vbar.data_source.selected.on_change("indices", server_tap_callback) # Plot appearance plot.xgrid.grid_line_color = None plot.ygrid.grid_line_color = None plot.yaxis[0].formatter.power_limit_high = 0 plot.yaxis[0].formatter.power_limit_low = 0 plot.yaxis[0].formatter.precision = 3 plot.xaxis[0].major_label_orientation = pi / 8
def make_cluster_plot(plot_data, pod, recs): # get x, y coordinates for pod and recs main_pod = pod.merge(plot_data, on=["title", "itunes_id", "genre", "subgenre"]) recs = recs.merge(plot_data, on=["title", "itunes_id", "genre", "subgenre"]) genre_list = list(plot_data.groupby(by="genre").groups.keys()) show_list = recs["genre"].unique() p = figure(tools="wheel_zoom,pan,box_zoom,reset,tap",\ plot_width=700, plot_height=500,\ toolbar_location="right") p.toolbar.active_drag = None # disabling pan helps with scrolling on smartphones # plot all data points and group them by genres for the legends group = dict() legend_items = [] for i, g in enumerate(genre_list): source = ColumnDataSource(plot_data.loc[plot_data["genre"] == g]) group[g] = p.circle(x='x', y='y', size = 10,\ color = Category20[19][-(i+1)],\ fill_alpha=0.5,\ line_alpha=0, muted_color="lightgray",\ source = source, muted_alpha = 0.05) legend_items.append((g,[group[g]])) if g not in show_list: # only show genres that are in the recommendations group[g].muted = True # plot the main podcast p.image_url(url="artwork_url", x="x", y="y", w=50, h = 50, \ anchor="center", global_alpha = 0.8, \ h_units = "screen", w_units = "screen",\ source = ColumnDataSource(main_pod)) p.rect(main_pod['x'], main_pod['y'], width = 52, height = 52, \ line_width = 3, height_units="screen", width_units="screen", \ fill_alpha = 0, line_color = "red") # plot the recommendations on the current page recs_source = ColumnDataSource(recs) rend_main = p.rect('x', 'y', width = 18, height = 18, \ line_width = 2, height_units="screen", width_units="screen", \ fill_alpha = 0, line_color = "royalblue", source = recs_source) p.image_url(url="artwork_url", x="x", y="y", w=16, h=16, \ anchor="center", h_units="screen", w_units="screen",\ source=recs_source) # plot the recommendations on the current page # rend_main = p.hex('x', 'y', fill_color = 'ivory', line_color = "royalblue", \ # line_width = 3, size = 15, \ # fill_alpha = 1, source = recs_source) # plot the main podcast # p.circle(main_pod['x'], main_pod['y'], color = "red", size = 5) # p.circle(main_pod['x'], main_pod['y'], fill_color = "red", \ # fill_alpha = 0.2, radius = 10, line_color = "red", \ # line_alpha = 0.2) custom_hover = HoverTool(mode="mouse", point_policy="snap_to_data", \ muted_policy = "ignore", renderers = [rend_main]) # limit the hover list to 5 items in case of overlapping glyphs custom_formatter = CustomJSHover(code=""" special_vars.indices = special_vars.indices.slice(0,5) if (special_vars.indices.indexOf(special_vars.index) >= 0) { return " " } else { return " hidden " }""") custom_hover.tooltips = """ <div @title{custom|safe}> <div> <img src="@artwork_url" alt="@artwork_url" width="42" style="margin: 5px 5px 5px 5px;" border="2" ></img> <span style="font-size: 15px; font-weight: bold;">@title</span> </div> </div> """ custom_hover.formatters = {'@title':custom_formatter} p.add_tools(custom_hover) p.outline_line_width = 7 p.outline_line_alpha = 0.2 p.outline_line_color = "navy" p.toolbar.autohide = True p.grid.visible = False legends = [] for i in range(0, len(legend_items), 4): legends.append(Legend(items=legend_items[i:i+4], margin=2)) for legend in legends: p.add_layout(legend,'below') p.plot_height = (600 + ((len(legend_items)-1)//4)*40) p.legend.click_policy="mute" p.legend.location = "bottom_center" p.legend.orientation = "horizontal" # url for selected recommendation selection_url_code = """ var ind = source.selected.indices if (ind.length==1) { var itunes_id = source.data['itunes_id'][ind] } else { var itunes_id = source.data['itunes_id'][ind[0]] } var url = "/itunes_id=".concat(itunes_id, "&offset=0") window.open(url, "_self") """ taptool = p.select(type=TapTool) taptool.renderers = [rend_main] taptool.callback = CustomJS(args = dict(source = recs_source), \ code = selection_url_code) # make the figure responsive clusters = column([p], sizing_mode = "stretch_width") return components(clusters)
'ahr': rk_data['Average Heart Rate (bpm)'], 'type': rk_data['Type'], 'col': rk_data['color'], } hvr = HoverTool() tooltip_main = [('Activity', '@type'), ('Date', '@x_ax{%a %b %d %Y}'), ('Distance', '@distance{0.00} km'), ('Duration', '@duration{%H:%M:%S}'), ('Average Pace', '@average_pace{%M:%S}')] current_tooltip = [('Average Speed', '@average_speed{0.00} km/h')] hvr.tooltips = tooltip_main + current_tooltip hvr.formatters = { 'x_ax': 'datetime', 'duration': 'datetime', 'average_pace': 'datetime', } toolbox = ['pan', 'box_zoom', 'reset', 'crosshair', hvr] plot1 = figure( plot_width=700, x_axis_label='Date', x_axis_type='datetime', tools=toolbox, toolbar_location='above', background_fill_color='#bbbbbb', border_fill_color="whitesmoke", )
def make_time_plot(place_1, place_dict, place_2=None, window_len=11, y_axis="log"): x_1 = np.array(list(place_dict[place_1].keys())) y_1 = np.array(list(place_dict[place_1].values())) # just to be sure, order the dates order = np.argsort(np.array(x_1), kind="stable") x_sorted = np.array(x_1)[order] y_sorted = np.array(y_1)[order] y_smooth = smooth(y_sorted, window_len=window_len) if place_2 is not None: x_2 = np.array(list(place_dict[place_2].keys())) y_2 = np.array(list(place_dict[place_2].values())) # just to be sure, order the dates order = np.argsort(np.array(x_2), kind="stable") x_2_sorted = np.array(x_2)[order] y_2_sorted = np.array(y_2)[order] y_2_smooth = smooth(y_2_sorted) len_diff = len(y_sorted) - len(y_2_sorted) if len_diff > 0: y_2_smooth = np.append(y_2_smooth, np.zeros(len_diff)) m_hover = ColumnDataSource( dict({ "date": x_sorted, "counts": y_sorted, "counts2": y_2_smooth })) m_title = "counts vs Date: " + args.type + " : " + place_1 + " overlaid with " + place_2 \ + " (black), shifted to " + place_1 + " first date" else: m_hover = ColumnDataSource(dict({ "date": x_sorted, "counts": y_sorted })) m_title = "counts vs Date: " + args.type + " : " + place_1 m = figure(tools=TOOLS, title=m_title, x_axis_type="datetime", x_axis_label='Date', y_axis_label='counts', width=750, y_axis_type=y_axis) m_hover_tool = HoverTool(tooltips=[("date", "@date{%F}"), ("counts", "@counts")]) m_hover_tool.formatters = {"date": "datetime"} m.add_tools(m_hover_tool) m.line(x="date", y="counts", color="navy", source=m_hover) m.line(x=x_sorted, y=y_smooth, line_color="red") if place_2 is not None: m.line(x=x_2_sorted, y=y_2_smooth, line_color="black") return m
def run(stock): # Get stock quote = get(stock, "quote") stock_quote = { "companyName": quote['companyName'], "latestPrice": quote['latestPrice'], "symbol": quote['symbol'], "change": "{0:.2%}".format(quote['changePercent']), "volume": "{:,}".format(quote['latestVolume']), "logo": get(stock, 'logo')['url'] } # Get stock related news news = get(stock, "news/last/5") stock_news = [] for article in news: stock_news.append({ "headline": article['headline'], "url": article['url'] }) # Get stock related company data company = get(stock, "company") company_data = { "website": company['website'], "CEO": company['CEO'], "description": company['description'] } # Get stock key stats stats = get(stock, "stats") key_stats = { "latestEPS": stats['latestEPS'], "day5Change": "{0:.2%}".format(stats['day5ChangePercent']), "month3Change": "{0:.2%}".format(stats['month3ChangePercent']), "year1Change": "{0:.2%}".format(stats['year1ChangePercent']), } # Get chart stats and make bokeh chart = get(stock, "chart/5y") chart_cds_df = get(stock, 'chart/1m') chart = pd.DataFrame(chart) chart = chart.set_index(pd.to_datetime(chart.date)) chart_cds = ColumnDataSource(chart) p = Figure(x_axis_label="Date", y_axis_label="Price", x_axis_type="datetime", title="{} - 5Y Graph".format(stock), sizing_mode='scale_width') # p.background_fill_color = '#8FBC8F' # p.background_fill_alpha = 0.2 p.grid.grid_line_alpha = 0.3 p.line(x='date', y='close', source=chart_cds, line_width=1, color='#F2583E') hover = HoverTool(mode='vline') hover.tooltips = [('Date', '@label'), ('Open', '$@open{%0.2f}'), ('High', '$@high{%0.2f}'), ('Low', '$@low{%0.2f}'), ('Close', '$@close{%0.2f}')] hover.formatters = { 'open': 'printf', 'high': 'printf', 'low': 'printf', 'close': 'printf' } p.add_tools(hover) cdl = Figure(x_axis_label="Date", y_axis_label="Price", x_axis_type="datetime", title="{} - Candlestick".format(stock), sizing_mode='scale_width') chart_cds_df = pd.DataFrame(chart_cds_df) chart_cds_df = chart_cds_df.set_index(pd.to_datetime(chart_cds_df.date)) inc = chart_cds_df.close > chart_cds_df.open dec = chart_cds_df.open > chart_cds_df.close w = 12 * 60 * 60 * 1000 cdl.segment(chart_cds_df.index, chart_cds_df.high, chart_cds_df.index, chart_cds_df.low, color='black') cdl.vbar(chart_cds_df.index[inc], w, chart_cds_df.open[inc], chart_cds_df.close[inc], fill_color='#D5E1DD', line_color='black') cdl.vbar(chart_cds_df.index[dec], w, chart_cds_df.open[dec], chart_cds_df.close[dec], fill_color='#F2583E', line_color='black') cdl.grid.grid_line_alpha = 0.3 cdl_s, cdl_div = components(cdl) script, div = components(p) return { "stock_quote": stock_quote, "stock_news": stock_news, "company_data": company_data, "key_stats": key_stats, "chart_script": script, "chart_div": div, "s": cdl_s, "d": cdl_div }