'How do you calculate indexed price changes interactively based on the date being moused over on the x-axis in Altair?
I am trying to create an Altair version of this Vega-Lite API Interactive Index Chart, which itself was adapted from this Vega-Lite JSON version.
In Altair, I cannot get the transform_lookup and transform_calculate to work with the mouseover selection, such that the indexed price values displayed on the y-axis for each of the symbols are calculated based on the date being moused over on the x-axis.
In Vega-Lite, the following transforms, i.e. lookup and calculate, calculate indexed price changes based on the date being moused over on the x-axis:
chart = {
const mouseover = vl
.selectSingle("index")
.on("mouseover")
.encodings("x")
.nearest(true)
.init({ x: { year: 2005, month: 1, date: 1 } });
const base = vl.mark().encode(
vl.x().fieldT("date").axis(null)
);
const hiddenPoints = base
.markPoint({ opacity: 0.1 })
.select(mouseover)
.encode(
// Let's color code it interactively to demonstrate it is working, but we will remove it later
vl.color().if(mouseover, vl.value("firebrick")).value("steelblue")
);
const line = base
.markLine()
.transform(
vl.lookup("symbol").from(mouseover.key("symbol")),
vl.calculate(
"datum.index && datum.index.price > 0 ? (datum.price - datum.index.price)/datum.index.price : 0"
).as("indexed_price")
)
.encode(
vl.y().fieldQ("indexed_price").axis({ format: "%" }),
vl.color().fieldN("symbol")
);
const tooltipBase = base
.transform(vl.filter(mouseover))
.encode(vl.color().value("firebrick"));
const tooltip = vl.layer(
tooltipBase.markRule({ strokeWidth: 0.5 }),
tooltipBase.markText({ align: "center", fontWeight: 100 }).encode(
vl.y().value(310),
vl.text().fieldT("date").timeUnit("yearmonth")
)
);
return vl
.layer(hiddenPoints, line, tooltip)
.data("data/stocks.csv")
.width(width - 150)
.height(300)
.render();
}
Vega-Lite API Interactive Index Chart
When I attempt to translate this code into Altair, I cannot get the mouseover event to lookup the date and symbols and compute the indexed price change values for each of the symbols correctly. The hiddenPoints appear, but the indexed price change lines for each of the symbols do not appear:
mouseover = alt.selection_single(name='index',
on='mouseover',
encodings=['x'],
nearest=True,
init={ 'x': { 'year': 2005, 'month': 1, 'date': 1 } })
base = alt.Chart(stocks).mark_line().encode(
x=alt.X('date:T', axis=None, title=None),
)
hiddenPoints = base.mark_point(opacity=0.1).add_selection(mouseover).encode(
color=alt.condition(mouseover, alt.value('firebrick'), alt.value('steelblue'))
)
line = base.mark_line().transform_lookup(
lookup='symbol',
from_=alt.LookupData(data='index', key='symbol', fields=['date', 'price'])
).transform_calculate(
indexed_price="datum.index && datum.index.price > 0 ? (datum.price - datum.index.price) / datum.index.price : 0"
).encode(
y=alt.Y('indexed_price:Q', title='Indexed Price', axis=alt.Axis(format='%')),
color=alt.Color('symbol:N', title='Symbol')
)
tooltipBase = base.transform_filter(mouseover).encode(
color=alt.value('firebrick')
)
tooltip = alt.layer(
tooltipBase.mark_rule(strokeWidth=0.5),
tooltipBase.mark_text(align='center', fontWeight=100).encode(
y=alt.value(310),
text='yearmonth(date):T'
)
)
alt.layer(hiddenPoints, line, tooltip).properties(
width=650,
height=300
)
Altair Interactive Index Chart
In Altair, how do I use the mouseover event with transform_lookup and transform_calculate to lookup the date and symbols and compute the indexed price change values for each of the symbols? Thank you for your help.
Solution 1:[1]
Here's roughly the equivalent in Altair:
from vega_datasets import data
import altair as alt
data = data.stocks.url
index = alt.selection_single(
name='index', on='mouseover', nearest=True, encodings=['x'],
init={"x": {"year": 2005, "month": 1, "date": 1}})
transparent_points = alt.Chart(data).mark_point(opacity=0).encode(
x='date:T'
).add_selection(index)
lines = alt.Chart(data).transform_lookup(
'symbol', from_=alt.LookupSelection('symbol', 'index')
).transform_calculate(
indexed_price="datum.index && datum.index.price > 0 ? "
"(datum.price - datum.index.price)/datum.index.price : 0"
).mark_line().encode(
x='date:T',
y='indexed_price:Q',
color='symbol:N'
)
rules = alt.Chart(data).transform_filter(
index
).mark_rule().encode(
x='date:T'
)
alt.layer(transparent_points, lines, rules).properties(width=600)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | jakevdp |