def generate_graph(self): """ Generate the graph; return a 2-tuple of strings, script to place in the head of the HTML document and div content for the graph itself. :return: 2-tuple (script, div) :rtype: tuple """ logger.debug('Generating graph for %s', self._graph_id) # tools to use tools = [ PanTool(), BoxZoomTool(), WheelZoomTool(), SaveTool(), ResetTool(), ResizeTool() ] # generate the stacked area graph try: g = Area( self._data, x='Date', y=self._y_series_names, title=self._title, stack=True, xlabel='Date', ylabel='Downloads', tools=tools, # note the width and height will be set by JavaScript plot_height=400, plot_width=800, toolbar_location='above', legend=False ) except Exception as ex: logger.error("Error generating %s graph", self._graph_id) logger.error("Data: %s", self._data) logger.error("y=%s", self._y_series_names) raise ex lines = [] legend_parts = [] # add a line at the top of each Patch (stacked area) for hovertool for renderer in g.select(GlyphRenderer): if not isinstance(renderer.glyph, Patches): continue series_name = renderer.data_source.data['series'][0] logger.debug('Adding line for Patches %s (series: %s)', renderer, series_name) line = self._line_for_patches(self._data, g, renderer, series_name) if line is not None: lines.append(line) legend_parts.append((series_name, [line])) # add the Hovertool, specifying only our line glyphs g.add_tools( HoverTool( tooltips=[ (self._y_name, '@SeriesName'), ('Date', '@FmtDate'), ('Downloads', '@Downloads'), ], renderers=lines, line_policy='nearest' ) ) # legend outside chart area legend = Legend(legends=legend_parts, location=(0, 0)) g.add_layout(legend, 'right') return components(g)
# 4 # 5 tkr_sel = ['BTC', 'ETH'] mcafr_vcc_mat = mca_vcc_mat.div(mca_vcc_mat.sum(1), axis=0) mcafr_vcc_mat.columns mcafr_vcc_mat_mthly = mcafr_vcc_mat.resample('MS').first() mcafr_vcc_mat_mthly[tkr_sel].isnull().sum() p4 = Area(mcafr_vcc_mat_mthly.loc['2016':, tkr_sel], stack=True, color=['Orange','Green']) #p4.line(mcafr_vcc_mat_mthly.loc['2016':,'BLX'].index, # mcafr_vcc_mat_mthly.loc['2016':,'BLX']) hover = HoverTool(tooltips=[('BTC', '@BTC'), ('ETH', '@ETH')]) p4.add_tools(hover) output_file('output/bokeh/mcafr2.html', mode='cdn') show(p4) # test test = pd.DataFrame({'col1': [1, 2], 'col2': [3, 4]}) p6 = Area(test, stack=True) output_file('output/bokeh/p6.html', mode='cdn') show(p6) ### bokeh server # Perform necessary imports from bokeh.io import curdoc from bokeh.layouts import widgetbox from bokeh.models import Slider
def _plot_public_data_statistics(self, all_data, version_attr_name, title_name, label_cb): """ generic method to plot flight hours one data type :param all_data: list with all types as string :param version_attr_name: attribute name of _VersionData :param title_name: name of the data for the title (and hover tool) :param label_cb: callback to create the label :return: bokeh plot """ # change data structure data_hours = {} # key=data id, value=list of hours for each version for d in all_data: data_hours[d] = [] versions = [] # sorted list of all versions for ver in sorted(self._version_data, key=functools.cmp_to_key(_Log.compare_version)): versions.append(ver) # all data points of the requested type for this version version_type_data = getattr(self._version_data[ver], version_attr_name) for d in all_data: if not d in version_type_data: version_type_data[d] = 0. data_hours[d].append(version_type_data[d]) # cumulative over each version for key in all_data: data_hours[key] = np.array(data_hours[key]) data_hours[key + "_cum"] = np.cumsum(data_hours[key]) # create a 2D numpy array. We could directly pass the dict to the bokeh # plot, but then we don't have control over the sorting order X = np.zeros((len(all_data), len(versions))) i = 0 all_data_sorted = [] for key in sorted( all_data, key=lambda data_key: data_hours[data_key + "_cum"][-1]): X[i, :] = data_hours[key + "_cum"] all_data_sorted.append(key) i += 1 all_data = all_data_sorted colors = viridis(len(all_data)) # alternative: use patches: http://bokeh.pydata.org/en/latest/docs/gallery/brewer.html area = Area(X, title="Flight Hours per " + title_name, tools=TOOLS, active_scroll=ACTIVE_SCROLL_TOOLS, stack=True, xlabel='version (including development states)', ylabel='', color=colors) # now set the labels for i in range(len(all_data)): area.legend[0].items[i].label = props.value( label_cb(all_data[i], False)) area.legend[0].items.reverse() # stack the data: we'll need it for the hover tool last = np.zeros(len(versions)) for i in range(len(all_data)): last = last + X[i, :] data_hours[all_data[i] + '_stacked'] = last data_hours['x'] = np.arange(len(versions)) # hover tool source = ColumnDataSource(data=data_hours) for d in all_data: renderer = area.circle(x='x', y=d + '_stacked', source=source, size=10, alpha=0, name=d) g1_hover = HoverTool(renderers=[renderer], tooltips=[ (title_name, label_cb(d, True)), ('Flight hours (only this version)', '@' + d + '{0,0.0}'), ('Flight hours (up to this version)', '@' + d + '_cum{0,0.0}') ]) area.add_tools(g1_hover) # TODO: space x-axis entries according to version release date? area.xaxis.formatter = FuncTickFormatter(code=""" var versions = """ + str(versions) + """; return versions[Math.floor(tick)] """) area.xaxis.ticker = FixedTicker(ticks=list(range(len(versions)))) self._setup_plot(area) return area