Reputation: 3614
Can Altair plot bands on the y axis, similar to this Highcharts example?
The docs have an example showing how to draw a line on the y axis, but adapting the example to use plot_rect
to draw a band instead doesn't quite work:
import altair as alt
from vega_datasets import data
weather = data.seattle_weather.url
chart = alt.Chart(weather).encode(
alt.X("date:T")
)
bars = chart.mark_bar().encode(
y='precipitation:Q'
)
band = chart.mark_rect().encode(
y=alt.value(20),
y2=alt.value(50),
color=alt.value('firebrick')
)
alt.layer(bars, band)
Upvotes: 1
Views: 2031
Reputation: 2436
I think the problem when you give a value with alt.value
is that you specify the value in pixels starting from the top of the graph : it is not mapped to the data.
In the initial answer, with mark_rule
, it would'nt create a clean band but a lot of vertical stripes, so here is a way to correctly plot a band.
First solution is to create a brand new data frame for the band, and layer that on top of the bars:
import altair as alt
import pandas as pd
from vega_datasets import data
weather = data('seattle_weather')
band_df = pd.DataFrame([{'x_min': weather.date.min(),
'x_max': weather.date.max(),
'y_min': 20,
'y_max': 50}])
bars = alt.Chart(weather).mark_bar().encode(
x=alt.X('date:T'),
y=alt.Y('precipitation:Q', title="Precipitation")
)
band_2 = alt.Chart(band_df).mark_rect(color='firebrick', opacity=0.3).encode(
x='x_min:T',
x2='x_max:T',
y='y_min:Q',
y2='y_max:Q'
)
alt.layer(bars, band_2)
Second option, if you do not want/cannot create a dataframe, is to use transform_calculate
, and manually specify x
and x2
in the band chart:
bars = alt.Chart().mark_bar().encode(
x=alt.X('date:T', title='Date'),
y=alt.Y('precipitation:Q', title="Precipitation")
)
band_3 = alt.Chart().mark_rect(color='firebrick', opacity=0.3).encode(
x='min(date):T',
x2='max(date):T',
y='y_min:Q',
y2='y_max:Q'
).transform_calculate(y_min='20', y_max='50')
alt.layer(bars, band_3, data=data.seattle_weather.url)
Initial answer
I would do 2 things to mimic the highchart example you gave. First, use a transform_calculate
to set y_min
and y_max
values. And second, I'll use mark_rule
so that the band span on the X axis where there are values. (I also added some opacity and changed the order of the layers so that the band is behind the bars.)
import altair as alt
from vega_datasets import data
weather = data.seattle_weather.url
chart = alt.Chart().encode(
alt.X("date:T")
)
bars = chart.mark_bar().encode(
y='precipitation:Q'
)
band = chart.mark_rule(color='firebrick',
opacity=0.3).encode(
y=alt.Y('y_min:Q'),
y2=alt.Y('y_max:Q')
).transform_calculate(y_min="20",
y_max="50")
alt.layer(band, bars, data=weather)
Upvotes: 3