Hi everyone,
I need some help on being able to render multiple glyphs on the same figure object using data coming from pandas DataFrame. For the purposes of the graphs I want to plot, I have already been able to do it for Series objects, but don’t know how to do it for DataFrames. I know its definitely possible, but I just need some suggestions here from you guys; even some pointers on where in the documnetation I should look will be helpful.
So I already have a function here that does plotting for the figure I want using a series object and it works fine:
from bokeh.plotting import figure , output_file, show, save
from bokeh.models import HoverTool, TapTool, OpenURL, ColumnDataSource
from collections import OrderedDict
def bokeh_plot(data, metric):
‘’’
The metric parameter must be a string that must be exactly the same as the name
of the column on the DataFrame or Series that contains all the data we want to plot
against the build numbers
‘’’
if isinstance(data, pd.Series):
# We generate two lists from the series object
buildnums = list(data.index)
datapts = list(data)
# We construct a dictionary from the two lists in order to pass the data into
# the ColumnDataSource instance because ColumnDataSource does not accept Series objects
source = ColumnDataSource(dict(x = buildnums, y=datapts))
p = figure(title="Geometric Mean of %s vs Build Number" %metric,
tools="pan,wheel_zoom,reset,hover")
# Be sure to instantiate the circle glyph factory before the line glyph factory
# otherwise TapTool OpenURL on the circle won't work with the clickable link
p.circle(x = buildnums, y = datapts, radius=0.3, source = source,
fill_color="blue", fill_alpha=0.6, line_color=None)
p.line(x = buildnums, y = datapts)
hover = p.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
("(Build Number, Geometric Mean)", "(@x, @y)")
])
tap = TapTool(plot=p,
action=OpenURL(url="http://192.168.1.253:8010/builders/Synthesis/builds/@x"))
p.tools.append(tap)
output_file("data_analysis_%s.html" % metric)
save(p)
``
But knowing that the ColumnDataSource is able to take in DataFrames directly, when I try adding this chunk:
if isinstance(data, pd.DataFrame):
dictionary = ColumnDataSource.from_df(data)
source = ColumnDataSource(dictionary)
# Obtain the list of buildnums and datapts via indexing the dictionary object
# these give us the x and y values for our plot
buildnums = dictionary['build_number']
datapts = dictionary['%s' %metric]
p = figure(title="Geometric Mean of %s vs Build Number" %metric,
tools="pan,wheel_zoom,reset,hover")
p.circle(x = buildnums, y = datapts, radius=0.3, source =source,
fill_color="blue", fill_alpha=0.6, line_color=None)
p.line(x = buildnums, y = datapts)
hover = p.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
("(Build Number, Geometric Mean)", "(@x, @y)")
])
tap = TapTool(plot=p,
action=OpenURL(url="http://192.168.1.253:8010/builders/Synthesis/builds/@x"))
p.tools.append(tap)
output_file("data_analysis_%s.html" % metric)
save(p)
``
When I try running my code with this chunk and passing in a DataFrame, the html file gets saved, but when I open it, I find that hovertool and tooltips are not working at all, totally unlike the one for Series object.
Please correct me if I’m using anything incorrectly here, and I would greatly appreciate any suggestions for alternative implementations to plot from a DataFrame. It will also be great if someone could explain to me, what is the purpose for us assigning the argument ‘source=source’ when we are calling the circle factory object , which I did in my code here.
thank you very much.