Choroplethmapbox with discrete colors (in clientside Dash callback)

Hello!

I am attempting to plot a choropleth chart using mapbox… and I am actually able to, but it is a heatmap and I wanted it to be a discrete color map. The way I implemented it is working, but I wanted to have a legend and not a colorscale.

The two alternatives I think make sense are:

  1. actually figure out how to create a streets-style choroplethmapbox with discrete colors;
  2. Draw the legend over the map.

Alternative 2 could work, but the legend becomes awkward when the user pans about the map. So, if there is no way to fix a drawing on the plot window, the only real alternative is 1.

For a reduced example of what I have now, all inside a Dash callback:

window.dash_client.plot_color_map{
    quality_map: {
        'Bad': 0.0,
        'Normal': 0.5,
        'Good': 1.0,
    },
    color_map: [
        [0.0, '#ec4035'],
        [0.5, '#f8cf32'],
        [1.0, '#55b848'],
    ],
    color_code: {
        'Bad': '#ec4035',
        'Normal': '#f8cf32',
        'Good': '#55b848',
    },
    create_plot: function (data_cache) {
        const cache = JSON.parse(data_cache);
        let colors = [];
        for (const q of cache.quality){
            colors.push(this.quality_map[q]);
        }
        var Figure = {'data': [], 'layout': {}};
        Figure['layout'] = {
            'mapbox': {
                'style':'streets',
                'uirevision':true,
                'accesstoken':'my access token',
                'zoom':9,
                'center':cache.center,
            },
            'margin':{
                'l':0,
                't':45,
                'b':0,
                'r':0
            },
            'showlegend':true,
            'hovermode':'closest',
        };
        Figure['data'] = [{
            'marker':{'opacity': 0.5},
            'type':'choroplethmapbox',
            'geojson':cache.geoJSON,
            'locations':cache.locations,
            'z':colors,
            'customdata':cache.value,
            'hovertemplate': '%{location}<br>Value: %{customdata}<extra></extra>',
            'colorscale':this.color_map,
            'showscale':false, // Don't show colorscale. I need a discrete legend!
        }];
        Figure.layout['title'] = {
            'text':'My map',
            'x': .5,
            'y': .95,
            'xanchor': 'center',
            'yanchor': 'top'
        };
        Figure.layout['titlefont'] = {
            'size': 24
        };
        return [Figure];
    }
}

data_cache is a stringified JSON containing:

*geoJSON, array of geoJSONs to determine each region’s poligon;
*locations, array with the locations’s names;
*quality, array with the tags for determining the colors;
*value, array with values for the hover;
*center, JSON with lat and lon values;

I wanted to use color_code instead, following what I understood from plotly’s documentation, but it just fails to draw the polygons or uses a default colorscale whenever I do anything different from the code above.

Any help would be appreciated! :slight_smile:

Just found out that Choropleth charts with discrete color should have a data element for each value, so you have to push to your Figure.data array the good, the normal and the bad objects, something like:

for (var color in color_code) {
    Figure['data'].push(
            'marker':{'opacity': 0.5},
            'type':'choroplethmapbox',
            'geojson':cache.geoJSON,
            'colorscale': [[0.0, color_code[color]], [1.0, color_code[color]]],
            'locations': filter(cache.locations, color), // FILTER THE LOCATIONS
            'z': [1, 1, ..., 1], // AS MANY 1 AS THE SIZE OF THE LOCATIONS
    )
}

in this snipper im assuming that there is a function filter(array, string) that filters from the locations array the elements that doesn’t belong to the color

1 Like