vega
vega copied to clipboard
Allow per-segment and gradient coloring (line, trail, area-style marks)
The trail mark allows each segment to be sized dynamically, but it does not seem to allow the fill parameter to be used dynamically, even when placed inside the update encoding channel. There are some cases when each segment of a line/trail may need to have a different color.
There are several ways for the stroke and fill color to be dynamic for the connected shapes (line, trail, area). This setting could in theory be different for the fill and the stroke.
- segment's color is a gradient from the starting to ending color
- segment's color is based on
startingpoint (similar tostep-beforeinterpolation) - segment's color is based on the
endingpoint (similar tostep-afterinterpolation) - all segments have the same static color as determined at the beginning of the mark drawing (current behavior)
P.S. as a theoretical workaround for this limitation, I might be able to wrap the trail mark inside a group, and make the group execute it once for each segment, but it seems overcomplicated and might have large performance implications.
Implementation ideas:
- Define two additional encoding parameters:
strokeColorStyleandfillColorStyle, with these allowed values:static- default, same as current behaviorstarting- segment color is set from the starting pointending- set from the ending pointgradient-segment- for each segment of the line, create a new gradient between the pair of points, with the start and end colors. This method might be slow but needed in some cases.gradient- TBD: create one big gradient per mark run, using the first and the last points as gradient rectangle, and adding each point color as a stop. In a way, imagine a straight line that goes from the first to the last data point, and for each point in between, project point's coordinates to the line, and add it as a color stop.gradient-N(e.g. gradient-0) - TBD: same asgradient, but force the gradient to go in predetermined direction, where N is a number of degrees from 0 for horizontal.
Reading over the points above, it becomes clear that this kind of functionality would be pretty trick to implement properly in vega.
That said, I would just like to note that the lack of this functionality has made for some weird 'gotchas' downstream in packages that depend on vega (e.g., altair/issues/931).
+1 I think this would be great as well
There has not been any progress on this to-date as we don't have someone with the spare cycles to work on it. If anyone is interested, the vega-scenegraph package would be the place to start. Once the scenegraph model and rendering decisions are worked out (which may require significant effort), integration with the rest of Vega could proceed quickly.
Please, any news on this? Need point to point gradient with lines
Also asked on Stack Overflow.
Here is a hacky way of creating a gradient line. Far from perfect but could be useful for some use cases until there is native support.

{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "A basic stacked area chart example.",
"width": 500,
"height": 200,
"padding": 5,
"data": [
{
"name": "table",
"values": [
{"x": 0, "y": 28},
{"x": 1, "y": 43},
{"x": 2, "y": 81},
{"x": 3, "y": 19},
{"x": 4, "y": 52},
{"x": 5, "y": 24},
{"x": 6, "y": 87},
{"x": 7, "y": 17},
{"x": 8, "y": 68},
{"x": 9, "y": 49}
],
"transform": [{"type": "formula", "as": "y2", "expr": "datum.y-1"}]
}
],
"scales": [
{
"name": "x",
"type": "point",
"range": "width",
"domain": {"data": "table", "field": "x"}
},
{
"name": "y",
"type": "linear",
"range": "height",
"nice": true,
"zero": true,
"domain": {"data": "table", "field": "y"}
},
{"name": "color", "type": "sequential", "range": {"scheme": "rainbow"}}
],
"axes": [
{"orient": "bottom", "scale": "x", "zindex": 1},
{"orient": "left", "scale": "y", "zindex": 1}
],
"marks": [
{
"type": "area",
"from": {"data": "table"},
"encode": {
"enter": {
"interpolate": {"value": "monotone"},
"x": {"scale": "x", "field": "x"},
"y": {"scale": "y", "field": "y"},
"y2": {"scale": "y", "field": "y2"},
"fill": {"signal": "gradient('color', [0,1], [1,1])"}
}
}
}
]
}