最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

vega lite - Conditionally change the stroke of a line based on x-axis value? - Stack Overflow

programmeradmin4浏览0评论

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
Add a comment  | 

1 Answer 1

Reset to default 1

As @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.

发布评论

评论列表(0)

  1. 暂无评论