Reputation: 341
I am trying to setup a multi-line tooltip for a faceted chart in Altair. The facet helps to compare multi-year data (i.e. so that January 2018 can easily be compared to January 2019).
Below is a code sample with random data, following the example found in the documentation: https://altair-viz.github.io/gallery/multiline_tooltip.html.
Depending on where I define the facet I get one of the following errors:
AttributeError: 'FacetChart' object has no attribute 'mark_point'
: occurs when I facet the line chart in the beginning and then try to apply mark_point() on this line chart
ValueError: Faceted charts cannot be layered.
: occurs when I facet the line chart in the end (when building the layer)
Is there a workaround?
start = pd.Timestamp('20180101', tz='Europe/Rome')
end = pd.Timestamp('20200101', tz='Europe/Rome')
index = pd.date_range(start,end,freq='M')[:-1]
source = pd.DataFrame(np.cumsum(np.random.randn(len(index), 3), 0).round(2),
columns=['A', 'B', 'C'], index=index)
source.index.names = ['x']
source = source.reset_index().melt('x', var_name='category', value_name='y')
### line chart with facet
line = alt.Chart(source).mark_line(point=True).encode(alt.X('month(x):O', title=''), alt.Y('y:Q', title=''), color='category:N').facet(row=alt.Row('year(x):O', title=''))
nearest = alt.selection(type='single', nearest=True, on='mouseover',
fields=['x'], empty='none')
selectors = alt.Chart(source).mark_point().encode(
x='x:Q',
opacity=alt.value(0),
).add_selection(
nearest
)
points = line.mark_point().encode(
opacity=alt.condition(nearest, alt.value(1), alt.value(0))
)
text = line.mark_text(align='left', dx=5, dy=-5).encode(
text=alt.condition(nearest, 'y:Q', alt.value(' '))
)
rules = alt.Chart(source).mark_rule(color='gray').encode(
x='x:Q',
).transform_filter(
nearest
)
alt.layer(
line, selectors, points, rules, text
).properties(
width=600, height=300
)
Upvotes: 1
Views: 506
Reputation: 86320
If you would like to facet a layered chart, you should call the .facet()
method on that layered chart.
You also probably want to change your x-encodings in the layers so that they all encode the same thing.
The result looks like this:
import numpy as np
import pandas as pd
import altair as alt
start = pd.Timestamp('20180101', tz='Europe/Rome')
end = pd.Timestamp('20200101', tz='Europe/Rome')
index = pd.date_range(start,end,freq='M')[:-1]
source = pd.DataFrame(np.cumsum(np.random.randn(len(index), 3), 0).round(2),
columns=['A', 'B', 'C'], index=index)
source.index.names = ['x']
source = source.reset_index().melt('x', var_name='category', value_name='y')
### line chart with facet
line = alt.Chart(source).mark_line(point=True).encode(alt.X('month(x):O', title=''), alt.Y('y:Q', title=''), color='category:N')
nearest = alt.selection(type='single', nearest=True, on='mouseover',
fields=['x'], empty='none')
selectors = alt.Chart(source).mark_point().encode(
x='month(x):O',
opacity=alt.value(0),
).add_selection(
nearest
)
points = line.mark_point().encode(
opacity=alt.condition(nearest, alt.value(1), alt.value(0))
)
text = line.mark_text(align='left', dx=5, dy=-5).encode(
text=alt.condition(nearest, 'y:Q', alt.value(' '))
)
rules = alt.Chart(source).mark_rule(color='gray').encode(
x='month(x):O',
).transform_filter(
nearest
)
alt.layer(
line, selectors, points, rules, text
).properties(
width=600, height=300
).facet(row=alt.Row('year(x):O', title=''))
Upvotes: 1