I want to change the stroke used for a line in an Altair chart, based on a condition on the x-value. For example, in the cartoon below, for point pairs where the left-hand point is less than the red line's value, we use solid dashing, and stroked otherwise:
Based on this discussion, I figured the following might work:
import altair as alt
from vega_datasets import data
source = data.wheat()
alt.Chart(source).mark_line().encode(
x="year:O",
y="wheat:Q",
strokeDash=alt.condition(
alt.datum.year > 1750,
alt.value([0]), # solid line
alt.value([5, 5]), # dashed line: 5 pixels dash + 5 pixels space
),
)
However, I confusingly get a dashed line for all points:
The following workaround produces a result I'd like:
import altair as alt
from vega_datasets import data
source = data.wheat()
base = alt.Chart(source).encode(
x="year:O",
y="wheat:Q",
)
solid = base.transform_filter(alt.datum.year <= 1750)
dash = base.encode(strokeDash=alt.value([5, 5])).transform_filter(
alt.datum.year >= 1750
)
solid.mark_line() + dash.mark_line()
But it is---perhaps?---not "as nice" as being able to conditionally stroke?
I want to change the stroke used for a line in an Altair chart, based on a condition on the x-value. For example, in the cartoon below, for point pairs where the left-hand point is less than the red line's value, we use solid dashing, and stroked otherwise:
Based on this discussion, I figured the following might work:
import altair as alt
from vega_datasets import data
source = data.wheat()
alt.Chart(source).mark_line().encode(
x="year:O",
y="wheat:Q",
strokeDash=alt.condition(
alt.datum.year > 1750,
alt.value([0]), # solid line
alt.value([5, 5]), # dashed line: 5 pixels dash + 5 pixels space
),
)
However, I confusingly get a dashed line for all points:
The following workaround produces a result I'd like:
import altair as alt
from vega_datasets import data
source = data.wheat()
base = alt.Chart(source).encode(
x="year:O",
y="wheat:Q",
)
solid = base.transform_filter(alt.datum.year <= 1750)
dash = base.encode(strokeDash=alt.value([5, 5])).transform_filter(
alt.datum.year >= 1750
)
solid.mark_line() + dash.mark_line()
But it is---perhaps?---not "as nice" as being able to conditionally stroke?
Share Improve this question edited Jan 20 at 20:50 bzm3r asked Jan 20 at 20:01 bzm3rbzm3r 4,5967 gold badges38 silver badges78 bronze badges 3- 1 This is a limitation of vega-lite, it is not possible to change a line along the path (size, shape, color, dash, etc). You can use the trail mark to change the size along the path, but not the strokeDash. I think your solution with layers is the best way. – kgoodrick Commented Jan 22 at 0:16
- @kgoodrick well, I did come across this example, where we can change the stroke width? altair-viz.github.io/gallery/trail_marker.html – bzm3r Commented Jan 22 at 20:01
- So if we want to "conditionally stroke dash", then we might have to have a relevant data column called "strokeDash"? I'm not sure what format this data column should have... – bzm3r Commented Jan 22 at 20:02
1 Answer
Reset to default 1As @kgoodrick mentions, we cannot change the dash style in an individual line. This is a constraint at the Vega level, not just for Vega-Lite.
We can get close to the effect you want without needing layers by using a Vega-Lite expression to create two lines, one before and after.
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": { "url": "data/wheat.json"},
"mark": "line",
"encoding": {
"x": {"field": "year", "type": "ordinal"},
"y": {"field": "wheat", "type": "quantitative"},
"strokeDash": {"field": "dashStyle", "scale": null}
},
"transform": [{
"calculate": "datum.year < 1750 ? [0] : [5, 5]",
"as": "dashStyle"
}]
}
See live editor
In altair
terms, you can use
chart = alt.Chart(source).mark_line().encode(
x=alt.X("year:O"),
y=alt.Y("wheat:Q"),
strokeDash=alt.StrokeDash("dashStyle:N")
).transform_calculate(
dashStyle="datum.year < 1750 ? [0] : [5, 5]"
)
Note the similar example in the Vega-Lite gallery. To avoid the gap between the two lines, you need to repeat the "boundary" year (1750) to appear once more in the data, as in the gallery example.