I have a bunch of time series objects I'm charting with bokeh.charts.TimeSeries data that I want to make into a beautiful plot with a description and title, etc. How can I add a chart to a bokeh.plotting.figure object? I'm using bokeh.layouts.row to organise them, but I want to make it look more professional than a webpage with nothing but a chart.
Is this possible? I was looking at the plotting interface, but I don't see a time series API. Would I just use my pandas.Series objects as the data for the line API?
The old bokeh.charts API, including TimeSeries was deprecated and subsequently removed. You can and should plot time series using the stable bokeh.plotting API. Here is a complete example created with Bokeh 0.13.0:
from bokeh.plotting import figure, show
from bokeh.sampledata.glucose import data
p = figure(x_axis_type="datetime", title="Glocose Range", plot_height=350, plot_width=800)
p.xgrid.grid_line_color=None
p.ygrid.grid_line_alpha=0.5
p.xaxis.axis_label = 'Time'
p.yaxis.axis_label = 'Value'
p.line(week.index, week.glucose)
show(p)
Related
I would like to add chart(s), or data to existing chart dynamically (via ipywidget.interact) as in the code below (chart + dotchart). I get nearly what I want except whole chart gets re-drawn and this causes flickering.
How do I add/ modify/ patch data dynamically and avoid re-drawing whole chart?
Thanks!
import pandas as pd
import numpy as np
import altair as alt
from ipywidgets import interact
df = pd.DataFrame({"xval": range(100), "yval": np.random.randint(0,100,100)})
chart = alt.Chart(df).mark_point().encode(x="xval", y="yval",)
def update(x, y):
dot = pd.DataFrame(dict(x=[x], y=[y]))
dotchart = alt.Chart(dot).mark_point().encode(x="x", y="y", color=alt.value("red"))
return chart + dotchart
interact(update, x=(0, 100), y=(0, 100))
# x, y widgets that control position of 'red dot'
The only way to patch data into an Altair chart without re-rendering it is in Javascript, using the Vega View API. You can see an example of this here: https://vega.github.io/vega-lite/tutorials/streaming.html.
I don't know of any prior work on calling the Vega view API from Python, but it's possible in principle.
See the related Altair feature request here: https://github.com/altair-viz/altair/issues/426.
you may be able to do so using the top-level chart configuration methods that altair provides. See here: https://altair-viz.github.io/user_guide/configuration.html
This way you can update many many properties of the current chart without regenerating it.
I am trying to create a dropdown interface for my work. My dataset looks like this, it is a random dataset
Now I would like 2 dropdowns say CNN and BBC here. After selecting a channel from dropdown, I would like to select a Topic which would produce a bar chart according to it's value.
I am trying to access just one value initially, but it gives me a blank graph.
from bokeh.plotting import figure
from bokeh.io import output_notebook,show,output_file
p=figure()
import csv
data = [row for row in csv.reader(open('C:/Users/Aishwarya/Documents/books/books_q4/crowd_computing/Bokeh-Python-Visualization-master/interactive/data/data.csv', 'r',encoding="utf8"))]
p.vbar(x=data[1][2], width=0.5, bottom=0,
top=data[1][1], color="firebrick")
#output_notebook()
output_file('1.html')
show(p)
There are probably two issues going on:
The first is that if you are using categorical coordinates on an axis, e.g. "CNN" which it appears you are expecting to use, then you need to etll Bokeh what the categorical range is:
p.figure(x_range=["CNN", ...]) # list all the factors for x_range
If you need to update the axis later you can update the range directly:
p.x_range.factors = [...]
Additionally, as of Bokeh 0.13.0 there is a current open issue that prevents "single" factors from working as coordinates: #6660 Coordinates should accept single categorical values. The upshot is that you will have to put the data in a Bokeh ColumnDataSource explicityl (always an option), or in this case a workaround is also just to pass a single-item list instead:
p.vbar(x=["cnn"], ...)
Here is a complete update of your code, with some fake data put in:
from bokeh.plotting import figure
from bokeh.io import show
p = figure(x_range=["cnn"])
p.vbar(x=["cnn"], width=0.5, bottom=0, top=10, color="firebrick")
show(p)
I would also recommend studying the User's guide section Handling Categorical Data.
I am fairly new to Bokeh and try to achieve the following:
I have a dataset with rows containing dates in the format dd-mm-yyyy.
The dates are counted and then plotted.
When zoomed in I want Bokeh to show the indiviudal dates (that works already).
When zoomed out I want Bokeh only to show the months (or years when zoomed out even further). Right know the index gets pretty messy due to individual dates getting closer and closer the more you zoom out.
Is there a way to tell Bokeh to change what is shown in the index depending on how far you zoomed in or out?
Here is my code:
import pandas as pd
from bokeh.charts import TimeSeries
from bokeh.io import output_file, show, gridplot
transactionssent = dict(pd.melt(df,value_vars=['datesent']).groupby('value').size())
transactionssent2 = pd.DataFrame.from_dict(transactionssent, orient= 'index')
transactionssent2.columns = ['Amount']
transactionssent2.index.rename('Date sent', inplace= True)
ts = TimeSeries(transactionssent2, x='index', y='Amount')
ts.xaxis.axis_label = 'Date sent'
If someone knows please point me in the right direction.
Thanks and best regards,
Stefan
What you've described as what you want already sounds like the standard behavior of the built in datetime axis. So, my guess is that TimeSeries is treating your dates as string/categorical values, which would explain why you are not seeing standard datetime axis scaling.
I should add that bokeh.charts (including TimeSeries) has recently been removed to a separate project and also is known to have problems. I would actually discourage it's use at this point. Fortunately, it's also easy to plot timeseries with the bokeh.plotting API, which is stable, well-tested and documented, and in widespread use.
Here is an example to demonstrate:
import datetime
import numpy as np
from bokeh.io import show, output_file
from bokeh.plotting import figure
# some fake data just for this example, Pandas columns work fine too
start = datetime.datetime(2017, 1, 1)
x = np.array([start + datetime.timedelta(hours=i) for i in range(800)])
y = np.sin(np.linspace(0, 2, len(x))) + 0.05 * np.random.random(len(x))
p = figure(x_axis_type="datetime")
p.line(x, y)
output_file("stocks.html")
show(p)
Whose axis looks like this when first displayed:
But like this when zoomed in:
You can also further customize how the dates are formatter by setting various properties on the p.xaxis[0].formatter. For details about available properties, see the reference guide:
http://docs.bokeh.org/en/latest/docs/reference/models/formatters.html#bokeh.models.formatters.DatetimeTickFormatter
I am trying to set Interval Unit (for interval between labels) of chart using openpyxl. This option is set to 'Automatic' by default.
Image shows how we can set the option manually in Excel. Image Link
I found this option in XlsxWriter:
chart.set_x_axis({'interval_unit': 5})
but could not find the option in openpyxl.
Please help.
For bar and column charts in openpyxl the axis labeling individual data is of type openpyxl.chart.axis.TextAxis. TextAxis features a property named tickLblSkip which defines what you are looking for. You can set a labeling interval of 5 as follows:
from openpyxl.chart import BarChart
chart = BarChart
chart.x_axis.tickLblSkip = 5
I'm currently trying to get an overview of plots of data of different dates. To get a good feeling of the data I would like to plot relevant plots next to each other. This means I want to use the same plot multiple times in the gridplot command. However what I noticed is that when i use the same chart multiple times it will only show it once in the final .html file. My first attempt at solving this was to use a copy.deepcopy for the charts, but this gave the following error:
RuntimeError: Cannot get a property value 'label' from a LineGlyph instance before HasProps.__init__
My approach has been as follows:
from bokeh.charts import Line, output_file, show, gridplot
import pandas as pd
output_file('test.html')
plots = []
df = pd.DataFrame([[1,2], [3,1], [2,2]])
print(df)
df.columns = ['x', 'y']
for i in range(10):
plots.append(Line(df, x='x', y='y', title='Forecast: ' + str(i),
plot_width=250, plot_height=250))
plot_matrix = []
for i in range(len(plots)-1, 2, -1):
plot_matrix.append([plots[i-3], plots[i-2], plots[i]])
p = gridplot(plot_matrix)
show(p)
The results of which is a an html page with a grid plot with a lot of missing graphs. Each graph is exactly shown once (instead of the 3 times required), which leads me to think that the gridplot does not like me using the same object multiple times. An obvious solve is to simply create every graph 3 times as a different object, which I will do for now, but not only is this inefficient, it also hurts my eyes when looking at my code. I'm hoping somebody has a more elegant solution for my problem.
EDIT: made code runable
This is not possible. Bokeh plots (or Bokeh objects in general) may not be re-used in layouts.