✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
⚡️ Concerned about the grid? Kyle Baranko teaches how to predicting peak loads using XGBoost. Register for the August webinar!

Plotly Express in Python: Is it possible to manually label your legend in px.choropleth()?

Hi all,

I hope everything is well.

The code below is using the data source from Oxford University Government Respond Tracker.
For your convenience, here is the example of the data source contents;

CountryName|CountryCode| Date    | C1_School_Closing |...|EconomicSupportIndexForDisplay
Algeria    |   DZA     |20200101 | 0                 |...| 0
Algeria    |   DZA     |20200102 | 0                 |...| 0
.............................................................
Algeria    |   DZA     |20200724 | 3                 |...| 50
............................................................

So, I am making a standard choropleth graph in plotly.express with the following code:

import psycopg2
import pandas as pd
import plotly.express as px

''' PostgreSQL Variables '''
# PostgreSQL Login Variables (edited out)

''' PostgreSQL Connection '''
# PostgreSQL DB Connection code (edited out)

African_Query = pd.read_sql_query(
'''
# SQL Query to pull all African countries from the DB (e.g. 'Algeria, 'Angola', 'Benin', 'etc')
''', conn)
# except ('Comoros', 'Equatorial Guinea', 'Guinea Bissau', and 'Sao Tome and Principe')
# those countries were not exist in the datasource

''' Load SQL Queries into Pandas DataFrame '''
African = pd.DataFrame(African_Query,
                       columns=['all column names from the datasource'])

''' Color Scale '''
# HTML/HEX code: '#4c5c73'
faux_black = [[0.0, '#4c5c73'], [0.1, '#5D6C81'], [0.2, '#6F7C8F'], [0.3, '#818C9D'], [0.4, '#939DAB'],
             [0.5, '#A5ADB9'], [0.6, '#B7BDC7'], [0.7, '#C9CED5'], [0.8, '#DBDEE3'], [0.9, '#EDEEF1'],
             [1.0, '#FFFFFF']]


''' Plotly graph '''
# Government Respond - School Closing
african_figure1 = px.choropleth(African,
                                locations='countrycode',
                                color='c1_school_closing',
                                color_continuous_scale=faux_black,
                                range_color=[0, 3],
                                hover_data={'c1_school_closing': False,
                                            'countrycode': False,
                                            'countryname': False},
                                hover_name='countryname',
                                labels={'c1_school_closing': 'SCALE'})

african_figure1.update_layout(geo_scope='africa',
                              coloraxis_reverscale=True,
                              title_text='Government Respond - SCHOOL CLOSING <br> '
                                         'Source: <a href="https://www.bsg.ox.ac.uk/research/research-projects'
                                         '/coronavirus-government-response-tracker#data"> Oxford University '
                                         'CORONAVIRUS '
                                         'Government Respond Tracker</a>')

# african_figure1.show()
# african_figure1.write_html('file/path/file_name.html')

This code made me the following plot and please pay attention to the red rectangle;

In one of the examples, particularly the followings;

It seemed to be possible to manually label the legend.
However, in the example, it uses graph-objects and using go.Scatter().

So, I would like to know if this possible in px.choropleth()?
If it’s possible; I would like to define the indicators in legend into something like this:

blank (NaN) - no data
0           - no measures
1           - recommend closing
2           - require closing (only some levels)
3           - require closing all levels

EDIT:
I added the last part type of categorical scale that I forgot to include (NaN; or blank in the original dataset).
I apologise for this inconvenience to the readers and the problem solvers!

Many thanks for your time!

Hey @Aldy_Abe you can manually set the tick values and labels:

african_figure1.update_layout(
    coloraxis_colorbar=dict(
        title="SCALE",
        tickvalues=[0, 1, 2, 3],
        ticklabels=[
            "No measures", 
            "Recommend closing",
            "Require closing (only some levels)",
            "Require closing all levels",
        ],
    )
)

And I believe that you can also use categorical data for the color attribute of px.choropleth:

African["categories"] = African["c1_school_closing"].map(dict(
    0="No measures",
    1="Recommend closing",
    2="Require closing (only some levels)",
    3="Require closing all levels",
))
african_figure1 = px.choropleth(
    African,
    locations="countryside",
    color="categories",
    # ...
)
1 Like

Hi @RenaudLN ,

Thank you for this. Unfortunately, your suggested solution for the px.choropleth() is not working.
It gave me these error messages on my PyCharm:

(a) If I hover my mouse over the "c1_school_closing", I received this message 'Can't assign function to call'.

(b) Then, if I hover my mouse over the “No measures” etc, the message read this 'Can't assign to literal'.

This might be because I forgot to include the NaN values as one of the categorical variables.
So, it was suppose to be something like these instead (I have edit out my categorical variables in the original question).

blank (NaN) - no data
0           - no measures
1           - recommend closing
2           - require closing (only some levels)
3           - require closing all levels

Edit:

  • Out of curiosity, did plotly.express omit the NaN in the dataset automatically?
  • Correct me if I am wrong on that remark, this my 2nd-week using Plotly.

Apology for this inconvenience and to all other readers as well!

@RenaudLN

I have a quick update for you about the code.
One of your suggested solutions was not working
(particularly the one for px.choropleth part where I define a new list outside the choropleth code to use as a reference later)

This one particularly

Now, I have successfully made it work following your solution.
The first suggested solution does the trick.

I was not paying attention, because I thought the first solution only worked on plotly.graph_objects.

Many thanks for your time and apology for this inconvenience!

Glad I could help :slight_smile:

1 Like