Dynamic indexes while zooming in Python Bokeh - python

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

Related

Seaborn bar plot - different y axis values?

I am very new to coding and just really stuck with a graph I am trying to produce for a Uni assignment
This is what it looks like
I am pretty happy with the styling my concern is with the y axis. I understand that because I have one value much higher than the rest it is difficult to see the true values of the values further down the scale.
Is there anyway to change this?
Or can anyone recommend a different grah type that may show this data mor clearly?
Thanks!
You can try using a combination of ScalarFormatter on the y-axis and MultipleLocator to specify the tick-frequency of the y-axis values. You can read more about customising tricks for data-visualisations here Customising tricks for visualising data in Python
import numpy as np
import seaborn.apionly as sns
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
ax_data = sns.barplot(x= PoliceForce, y = TotalNRMReferrals) # change as per how you are plotting, just for an example
ax_data.yaxis.set_major_locator(ticker.MultipleLocator(40)) # it would have a tick frequency of 40, change 40 to the tick-frequency you want.
ax_data.yaxis.set_major_formatter(ticker.ScalarFormatter())
plt.show()
Based on your current graph, I would suggest lowering the tick-frequency (try with values lower than 100, say 50 for instance). This would present the graph in a more readable fashion. I hope this helps answer your question.

Using Bokeh for a dropdown menu which would create different charts

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.

Bokeh time series plotting

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)

Python x-labels evenly spreaded

I am trying to get my labels turned up correctly.
I want it to show 10 values on the list, but I have no idea how.
The usual way to show it doesn't work and when there are a lot of values, it is hard to read, see the picture.
Here you see that it is impossible to read the data.
Do you have an idea to make it work properly?
I have tried autoDateLocator, but that didn't work. The axis values were wrong.
I also tried to do that manually, but the same result happened.
Thanks in advance!
I have kinda 'solved this issue'. I asked around and didn't really find an answer that suited my needs, as every tick always gets shown.
However, when I keep the xtick_labels in the datetime-format, it gets sorted out by matplotlib itself, if there are too many values to show. This according to the dataset Armamatita provided
import matplotlib.pyplot as plt
import datetime
import numpy as np
x = np.array([datetime.datetime(i,1,1) for i in range(1700,2017)])
y = np.random.randint(0,100,len(x))
fig, ax = plt.subplots()
ax.plot(x,y)
plt.show()
I when the days I want to see is more than 14, I just let matplotlib pick te xtick_labels. When equal or less than 14, I add it myself using:
alldays = DayLocator()
weekFormatter = DateFormatter('%a %b %d %Y')
and this right before returning the fig:
ax.xaxis.set_major_locator(alldays)
ax.xaxis.set_major_formatter(weekFormatter)
It isn't the most neat pythonic code, but it does the trick.

Python Bokeh: Plotting same chart multiple times in gridplot

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.

Categories