Search code examples
pythonvisualizationaltairvega-liteparallel-coordinates

Parallel coordinates in Altair


I want to do a parallel coordinates plot with multiple y axis. I've found how to do it in Vega-Lite here but I haven't found the way to do it with Altair, there's only a very simple example where all the y axis are the same. Is there any way to do this plot in altair?


Solution

  • Note that this kind of chart is not "built-in" to Altair or Vega-Lite, so the only way to create it is with a manual sequence of transforms, and manually constructing your axes from tick and text marks.

    Here is an Altair version of the chart in the answer you linked to:

    import altair as alt
    from vega_datasets import data
    
    base = alt.Chart(
        data.iris.url
    ).transform_window(
        index="count()"
    ).transform_fold(
        ["petalLength", "petalWidth", "sepalLength", "sepalWidth"]
    ).transform_joinaggregate(
        min="min(value)",
        max="max(value)",
        groupby=["key"]
    ).transform_calculate(
        norm_val="(datum.value - datum.min) / (datum.max - datum.min)",
        mid="(datum.min + datum.max) / 2"
    ).properties(width=600, height=300)
    
    lines = base.mark_line(opacity=0.3).encode(
        x='key:N',
        y=alt.Y('norm_val:Q', axis=None),
        color="species:N",
        detail="index:N",
        tooltip=["petalLength:N", "petalWidth:N", "sepalLength:N", "sepalWidth:N"]
    )
    
    rules = base.mark_rule(
        color="#ccc", tooltip=None
    ).encode(
        x="key:N",
        detail="count():Q",
    )
    
    def ytick(yvalue, field):
        scale = base.encode(x='key:N', y=alt.value(yvalue), text=f"min({field}):Q")
        return alt.layer(
            scale.mark_text(baseline="middle", align="right", dx=-5, tooltip=None),
            scale.mark_tick(size=8, color="#ccc", orient="horizontal", tooltip=None)
        )
    
    alt.layer(
        lines, rules, ytick(0, "max"), ytick(150, "mid"), ytick(300, "min")
    ).configure_axisX(
        domain=False, labelAngle=0, tickColor="#ccc", title=None
    ).configure_view(
        stroke=None
    )
    

    enter image description here