vega-litealtairchoropleth

Trouble sorting legend when using transform_calculate linked to a new category in Altair


I'm trying to order the legend of two and more concatenated choropleth maps which are labeled by using a dictionary of strings. They share the legend. However when concatenating them, the legend gets unsorted, and what's supposed to be the first category, ends up being the last one. When making just one map, the code works fine.enter image description here How should i fix this?

import altair as alt
import geopandas as gpd
import pickle
import requests


resp = requests.get("https://raw.githubusercontent.com/ccsuehara/cfi/main/mapping.pickle")
mapping = pickle.loads(resp.content)
srcs = gpd.read_file("https://raw.githubusercontent.com/ccsuehara/cfi/main/example.geojson")


base = alt.Chart(srcs).mark_geoshape().properties(
    width=400,
    height=400
).project(
    type='mercator'  
)

g_ = alt.concat(
    base.encode(
    color=alt.Color(
        'disp_2010:N',
        scale=alt.Scale(scheme='greens'),
        title = "% Change (winsor)",
        sort=alt.EncodingSortField('class_2010_win',  order='ascending')
       ),
    ).transform_filter(
        'isValid(datum.class_2010_win)'
    ).transform_calculate(
        disp_2010=f"{mapping}[datum.class_2010_win]"
    ).properties(
        title="Δ 2005 - 2010(%)"
    )    | base.encode(
    color=alt.Color(
        'disp_2015:N',
        scale=alt.Scale(scheme='greens'),
      title = "% Change (winsor)",
     #sort=alt.EncodingSortField('class_2010_win',  order='ascending')
      ),
    ).transform_filter(
        'isValid(datum.class_2015_win)'
    ).transform_calculate(
        disp_2015=f"{mapping}[datum.class_2015_win]",
    ).properties(
        title="Δ 2010 - 2015(%)"
    )
)

g_

Solution

  • The easiest way to do this is to transform your data into long form and then use faceting to create the two charts. Unfortunately, there is currently a vega-lite bug that prevents faceting from working with mark_geoshape plots, but we can still achieve what you want with concatenation and long form data.

    I have done the transformation to long form in pandas, but it is also possible in altair with the transform_fold function.

    import altair as alt
    import geopandas as gpd
    import pickle
    import requests
    
    resp = requests.get(
        "https://raw.githubusercontent.com/ccsuehara/cfi/main/mapping.pickle"
    )
    mapping = pickle.loads(resp.content)
    srcs = gpd.read_file(
        "https://raw.githubusercontent.com/ccsuehara/cfi/main/example.geojson"
    )
    
    new_srcs = srcs.melt(id_vars=["geometry"], var_name="year", value_name="win").dropna()
    new_srcs["Period"] = new_srcs["year"].map(
        {"class_2010_win": "Δ 2005 - 2010(%)", "class_2015_win": "Δ 2010 - 2015(%)"}
    )
    new_srcs["Change"] = new_srcs["win"].map(mapping)
    
    new_base = (
        alt.Chart(new_srcs)
        .mark_geoshape()
        .encode(
            color=alt.Color(
                "Change:N",
                scale=alt.Scale(scheme="greens"),
                title="% Change (winsor)",
                sort=alt.EncodingSortField("win", order="ascending"),
            )
        ).project("mercator")
    )
    
    new_base.transform_filter(alt.datum.year == "class_2010_win").properties(
        title="Δ 2005 - 2010(%)"
    ) | new_base.transform_filter(alt.datum.year == "class_2015_win").properties(
        title="Δ 2010 - 2015(%)"
    )
    

    enter image description here