vega / altair

Declarative statistical visualization library for Python
https://altair-viz.github.io/
BSD 3-Clause "New" or "Revised" License
9.27k stars 793 forks source link

How do I apply a gradient to an area under a graph? #1043

Closed tweakimp closed 1 year ago

tweakimp commented 6 years ago

I want to color the area under a graph based on the value of the graph on that point, with the middle point of the gradient at 0, even if the min and max of the data have different absolute values. So I want it to be redder the more negative a value is and greener the more positive a value is. Currently I do it like this:

import altair as alt
import pandas as pd

df = pd.DataFrame([[x, x ** 2 - 1000] for x in range(-50, 50)], columns=["time", "money"])
df.set_index("time", drop=True, inplace=True)

# used to set the middle of the gradient to 0
maxval = int(max(abs(df["money"].min()), abs(df["money"].max()))) 

chart = (
    alt.Chart(df.reset_index())
    .mark_bar()
    .encode(
        alt.X("time"),
        alt.Y("money:Q"),
        alt.Color("money", scale=alt.Scale(domain=(-maxval, maxval), scheme="redyellowgreen")),
    )
)

image

This is exactly what I what, except that the curve consists of bars and is not smooth. I cant get it to work with mark_area().

jakevdp commented 6 years ago

I don't think that is supported. @domoritz or @kanitw may have suggestions

domoritz commented 6 years ago

Not in Vega-Lite, no.

tweakimp commented 6 years ago

Ok, thats too bad... why do i always want to have the stuff i cant have? :)

HalukaMB commented 5 years ago

If I understand it correctly, this is also not supported for colors in area charts. They turn to whatever the value at the end of the charts, is, right?

maxvalue=200
step = 60
overlap = 1
widthX=400

ridgeline_fem = alt.Chart(height=step, width=widthX).mark_area(
     fillOpacity=1, stroke="black", strokeWidth=0.5, fill="#6C43C0"

).encode(
    alt.X(
        "Lohnklasse | Geschlecht:Q",
    ),
    alt.Y(
        "more_female:Q",
        scale=alt.Scale(domain=[0,maxvalue],range=[step, -step * overlap]), 

        axis=None
    ),
    color=alt.condition(
        alt.datum.more_female > -1,
        alt.value("steelblue"),  # The positive color
        alt.value("orange")  # The negative color
    )

)

combined=alt.layer(ridgeline_fem, data=reduced).facet(
    row='Departement:O' 

)
combined.properties(
    bounds="flush"
).configure_facet(
    spacing=0
)

visualization (5)

jakevdp commented 5 years ago

Yes, area charts can only have one color per area mark. I can't run your code because it has undefined variables, but perhaps you could use a bar chart instead?

domoritz commented 5 years ago

Vega-Lite supports gradients now: https://vega.github.io/vega-lite/examples/area_gradient.html. However, it will be tricky to use this feature to encode data since we don't add a legend automatically.

joelostblom commented 1 year ago

As mentioned above, there is now support for non-data encoded gradient in VL. Any additional functionality would need to be added in VL before it is available in altair so closing this issue