Reputation: 340
I have the following data:
The measurement dataframe looks approx like this:
Time Trend Value
0 2021-03-24 16:10:20 A -1.3
1 2021-03-24 16:10:35 A -5.3
2 2021-03-24 16:10:50 A -6.3
3 2021-03-24 16:11:05 A -2.3
4 2021-03-24 22:39:05 A -5.3
... ... ... ...
12443 2021-03-24 16:10:20 H 0.0
12444 2021-03-24 22:38:20 H 1.0
12445 2021-03-24 22:38:35 H 2.0
12446 2021-03-24 22:38:50 H 3.0
12447 2021-03-24 22:39:05 H 4.0
For this purpose, I extract the time-ranges where a certain state is "active", as here:
State Start End
0 Idle 2021-03-24 16:10:20 2021-03-24 16:10:50
1 Pump 2021-03-24 16:10:50 2021-03-24 16:20:05
...
5 Cool 2021-03-24 20:42:20 2021-03-24 22:01:35
6 Pump 2021-03-24 22:01:35 2021-03-24 22:02:50
I then create two charts which I would like to combine with alt.layer
alt_st = (
alt.Chart(state_df)
.mark_rect()
.encode(
x=alt.X("Start", title="Time"),
x2=alt.X2("End", title="Time"),
y=alt.value(15),
y2=alt.value(0),
color=alt.Color("State:O", scale=get_state_scale(state_df.State.unique())),
)
# .add_selection(selection)
)
chart = (
alt.Chart(df)
.mark_line()
.encode(
alt.X("Time"),
alt.Y("Value"),
color="Trend",
)
)
Combining with alt.layer
:
alt.layer(chart, alt_st).resolve_legend("independent")
As can be seen, the combined chart has a messed up legend and the marks (lines) from the first chart) are gone.
What I tried so far:
The last thing I found out when trying to create a minimal example here.
I found a similar question (Altair: Layered Line Chart with Legend and Custom Colors) but couldn't work out how to apply the solution for my case.
My impression so far is that what I'm doing is very unidiomatic for Altair/Vega-Lite - if someone could point out the relevant concepts I'm missing I would be glad.
Upvotes: 3
Views: 100
Reputation: 48889
What you have at the end looks correct, but you would want to use resolve_scale(color='independent')
instead of resolve_legend('independent')
to separate the legends correctly:
import altair as alt
from vega_datasets import data
source = data.iowa_electricity()
# Create end year for mark_rect
source['end_year'] = source.groupby('source')['year'].shift(-1)
source = source.dropna()
line = alt.Chart(source).mark_line().encode(
x="year:T",
y="net_generation:Q",
color="source:N")
bar = alt.Chart(source).mark_rect().encode(
x="year:T",
x2="end_year",
color='year(year):O',
y=alt.value(15),
y2=alt.value(0)
)
(bar + line).resolve_scale(color='independent')
You can move the bar to the bottom with mark_rect(yOffset=270, y2Offset=300)
(offsets are in pixels rather than chart units, the same as when you use alt.value for y and y2):
Upvotes: 2