How to add/ modify/ patch altair chart data dynamically? - python

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.

Related

In a pairplot, how can I not show confidence intervals but display grid lines instead? [duplicate]

I'm plotting two data series with Pandas with seaborn imported. Ideally I would like the horizontal grid lines shared between both the left and the right y-axis, but I'm under the impression that this is hard to do.
As a compromise I would like to remove the grid lines all together. The following code however produces the horizontal gridlines for the secondary y-axis.
import pandas as pd
import numpy as np
import seaborn as sns
data = pd.DataFrame(np.cumsum(np.random.normal(size=(100,2)),axis=0),columns=['A','B'])
data.plot(secondary_y=['B'],grid=False)
You can take the Axes object out after plotting and perform .grid(False) on both axes.
# Gets the axes object out after plotting
ax = data.plot(...)
# Turns off grid on the left Axis.
ax.grid(False)
# Turns off grid on the secondary (right) Axis.
ax.right_ax.grid(False)
sns.set_style("whitegrid", {'axes.grid' : False})
Note that the style can be whichever valid one that you choose.
For a nice article on this, refer to this site.
The problem is with using the default pandas formatting (or whatever formatting you chose). Not sure how things work behind the scenes, but these parameters are trumping the formatting that you pass as in the plot function. You can see a list of them here in the mpl_style dictionary
In order to get around it, you can do this:
import pandas as pd
pd.options.display.mpl_style = 'default'
new_style = {'grid': False}
matplotlib.rc('axes', **new_style)
data = pd.DataFrame(np.cumsum(np.random.normal(size=(100,2)),axis=0),columns=['A','B'])
data.plot(secondary_y=['B'])
This feels like buggy behavior in Pandas, with not all of the keyword arguments getting passed to both Axes. But if you want to have the grid off by default in seaborn, you just need to call sns.set_style("dark"). You can also use sns.axes_style in a with statement if you only want to change the default for one figure.
You can just set:
sns.set_style("ticks")
It goes back to normal.

Hover tooltip with stacked Area chart in holoviews

I am creating a stacked area chart in holoviews with bokeh backend, similarly to the example here:
http://holoviews.org/reference/elements/matplotlib/Area.html
I would like to have a Hover tooltip but if I add it to the code, the resulting chart shows the hover cross but no data is displayed in the tooltip.
My code:
import holoviews as hv
values = np.random.rand(5, 20)
percentages = (values/values.sum(axis=0)).T*100
overlay = hv.Overlay([hv.Area(percentages[:, i], vdims=[hv.Dimension('value', unit='%')]).opts(tools=["hover"]) for i in range(5)])
stackA = hv.Area.stack(overlay)
I also tried putting the hover option in the hv.Stack step instead:
stackA = hv.Area.stack(overlay).opts(tools=["hover"])
but this does nothing.
I would like the hover tooltip to show the area value below the cursor and potentially other dimensions of my dataset.
This is a known issue: https://github.com/pyviz/holoviews/issues/3187. The same is valid for the Spread element.
The reason is (my guess) that bokeh has no hovertool for Patch, which is the glyph used to render Area and Spread elements: https://stackoverflow.com/a/53384398. So at the moment your best bet is probably trying to implement the vectorized workaround proposed in that stackoverflow answer in holoviews/plotting/bokeh/chart.py.

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)

How to get rid of grid lines when plotting with Seaborn + Pandas with secondary_y

I'm plotting two data series with Pandas with seaborn imported. Ideally I would like the horizontal grid lines shared between both the left and the right y-axis, but I'm under the impression that this is hard to do.
As a compromise I would like to remove the grid lines all together. The following code however produces the horizontal gridlines for the secondary y-axis.
import pandas as pd
import numpy as np
import seaborn as sns
data = pd.DataFrame(np.cumsum(np.random.normal(size=(100,2)),axis=0),columns=['A','B'])
data.plot(secondary_y=['B'],grid=False)
You can take the Axes object out after plotting and perform .grid(False) on both axes.
# Gets the axes object out after plotting
ax = data.plot(...)
# Turns off grid on the left Axis.
ax.grid(False)
# Turns off grid on the secondary (right) Axis.
ax.right_ax.grid(False)
sns.set_style("whitegrid", {'axes.grid' : False})
Note that the style can be whichever valid one that you choose.
For a nice article on this, refer to this site.
The problem is with using the default pandas formatting (or whatever formatting you chose). Not sure how things work behind the scenes, but these parameters are trumping the formatting that you pass as in the plot function. You can see a list of them here in the mpl_style dictionary
In order to get around it, you can do this:
import pandas as pd
pd.options.display.mpl_style = 'default'
new_style = {'grid': False}
matplotlib.rc('axes', **new_style)
data = pd.DataFrame(np.cumsum(np.random.normal(size=(100,2)),axis=0),columns=['A','B'])
data.plot(secondary_y=['B'])
This feels like buggy behavior in Pandas, with not all of the keyword arguments getting passed to both Axes. But if you want to have the grid off by default in seaborn, you just need to call sns.set_style("dark"). You can also use sns.axes_style in a with statement if you only want to change the default for one figure.
You can just set:
sns.set_style("ticks")
It goes back to normal.

Categories