0

How do you convert number 1.425887B to 1.4 in plotly choropleth ?

data2022 = dict(type = 'choropleth',
            colorscale = 'agsunset',
            reversescale = True,
            locations = df['Country/Territory'],
            locationmode = 'country names',
            z = df['2022 Population'],
            text = df['CCA3'    ],
            marker = dict(line = dict(color = 'rgb(12, 12, 12)', width=1)),
            colorbar = {'title': 'Population'})

layout2022 = dict(title = '<b>World Population 2022<b>',
               geo = dict(showframe = True,
                          showland = True, landcolor = 'rgb(198, 197, 198)',
                          showlakes = True, lakecolor = 'rgb(85, 173, 240)',
                          showrivers = True, rivercolor = 'rgb(173, 216, 230)', 
                          showocean = True, oceancolor = 'rgb(173, 216, 230)',
                          projection = {'type': 'natural earth'}))

choromap2022 = go.Figure(data=[data2022], layout=layout2022) 

choromap2022.update_geos(lataxis_showgrid = True, lonaxis_showgrid = True)

choromap2022.update_layout(height = 600,
                       title_x = 0.5, 
                       title_font_color = 'red',
                       title_font_family = 'Times New Roman',
                       title_font_size = 30,
                       margin=dict(t=80, r=50,  l=50))

iplot(choromap2022)

This is the image of the result I got, I want to convert the population of China from 1.425887B to 1.4B

I try to look up on the plotly document but cannot find anything.

This is the output of df.head().to_dict()

 'CCA3': {0: 'AFG', 1: 'ALB', 2: 'DZA', 3: 'ASM', 4: 'AND'},
 'Country/Territory': {0: 'Afghanistan',
  1: 'Albania',
  2: 'Algeria',
  3: 'American Samoa',
  4: 'Andorra'},
 'Capital': {0: 'Kabul',
  1: 'Tirana',
  2: 'Algiers',
  3: 'Pago Pago',
  4: 'Andorra la Vella'},
 'Continent': {0: 'Asia', 1: 'Europe', 2: 'Africa', 3: 'Oceania', 4: 'Europe'},
 '2022 Population': {0: 41128771, 1: 2842321, 2: 44903225, 3: 44273, 4: 79824},
 '2020 Population': {0: 38972230, 1: 2866849, 2: 43451666, 3: 46189, 4: 77700},
 '2015 Population': {0: 33753499, 1: 2882481, 2: 39543154, 3: 51368, 4: 71746},
 '2010 Population': {0: 28189672, 1: 2913399, 2: 35856344, 3: 54849, 4: 71519},
 '2000 Population': {0: 19542982, 1: 3182021, 2: 30774621, 3: 58230, 4: 66097},
 '1990 Population': {0: 10694796, 1: 3295066, 2: 25518074, 3: 47818, 4: 53569},
 '1980 Population': {0: 12486631, 1: 2941651, 2: 18739378, 3: 32886, 4: 35611},
 '1970 Population': {0: 10752971, 1: 2324731, 2: 13795915, 3: 27075, 4: 19860},
 'Area (km²)': {0: 652230, 1: 28748, 2: 2381741, 3: 199, 4: 468},
 'Density (per km²)': {0: 63.0587,
  1: 98.8702,
  2: 18.8531,
  3: 222.4774,
  4: 170.5641},
 'Growth Rate': {0: 1.0257, 1: 0.9957, 2: 1.0164, 3: 0.9831, 4: 1.01},
 'World Population Percentage': {0: 0.52, 1: 0.04, 2: 0.56, 3: 0.0, 4: 0.0}}```
  • where is the number appearing? do you mean in the `hovertext`? an image of your output showing where the number is appearing with `4,700,000,000` would be helpful. also a sample dataframe would be helpful too – can you copy and paste the output from `df.head().to_dict()` into your question? thank you – Derek O Dec 31 '22 at 05:14
  • 1
    @DerekO, hi thanks for replying, I just edited the question and added more information, might be helpful. – Đạt Dương Dec 31 '22 at 15:47

1 Answers1

0

This is trickier than it appears because plotly uses d3-format, but I believe they are using additional metric abbreviations in their formatting to have the default display numbers larger than 1000 in the format 1.425887B.

My original idea was to round to the nearest 2 digits in the hovertemplate with something like:

data2022 = dict(..., hovertemplate = "%{z:.2r}<br>%{text}<extra></extra>")

However, this removes the default metric abbreviation and causes the entire long form decimal to display. The population of China should show up as 1400000000 instead of 1.4B.

So one possible workaround would be to create a new column in your DataFrame called "2022 Population Text" and format the number using a custom function to round and abbreviate your number (credit goes to @rtaft for their function which does exactly that). Then you can pass this column to customdata, and display customdata in your hovertemplate (instead of z).

import pandas as pd
import plotly.graph_objects as go

data =  {'CCA3': {0: 'AFG', 1: 'ALB', 2: 'DZA', 3: 'ASM', 4: 'AND'},
 'Country/Territory': {0: 'Afghanistan',
  1: 'Albania',
  2: 'Algeria',
  3: 'American Samoa',
  4: 'Andorra'},
 'Capital': {0: 'Kabul',
  1: 'Tirana',
  2: 'Algiers',
  3: 'Pago Pago',
  4: 'Andorra la Vella'},
 'Continent': {0: 'Asia', 1: 'Europe', 2: 'Africa', 3: 'Oceania', 4: 'Europe'},
 '2022 Population': {0: 1412000000, 1: 2842321, 2: 44903225, 3: 44273, 4: 79824},
 '2020 Population': {0: 38972230, 1: 2866849, 2: 43451666, 3: 46189, 4: 77700},
 '2015 Population': {0: 33753499, 1: 2882481, 2: 39543154, 3: 51368, 4: 71746},
 '2010 Population': {0: 28189672, 1: 2913399, 2: 35856344, 3: 54849, 4: 71519},
 '2000 Population': {0: 19542982, 1: 3182021, 2: 30774621, 3: 58230, 4: 66097},
 '1990 Population': {0: 10694796, 1: 3295066, 2: 25518074, 3: 47818, 4: 53569},
 '1980 Population': {0: 12486631, 1: 2941651, 2: 18739378, 3: 32886, 4: 35611},
 '1970 Population': {0: 10752971, 1: 2324731, 2: 13795915, 3: 27075, 4: 19860},
 'Area (km²)': {0: 652230, 1: 28748, 2: 2381741, 3: 199, 4: 468},
 'Density (per km²)': {0: 63.0587,
  1: 98.8702,
  2: 18.8531,
  3: 222.4774,
  4: 170.5641},
 'Growth Rate': {0: 1.0257, 1: 0.9957, 2: 1.0164, 3: 0.9831, 4: 1.01},
 'World Population Percentage': {0: 0.52, 1: 0.04, 2: 0.56, 3: 0.0, 4: 0.0}
}

## rounds a number to the specified precision, and adds metrics abbreviations
## i.e. 14230000000 --> 14B
## reference: https://stackoverflow.com/a/45846841/5327068
def human_format(num):
    num = float('{:.2g}'.format(num))
    magnitude = 0
    while abs(num) >= 1000:
        magnitude += 1
        num /= 1000.0
    return '{}{}'.format('{:f}'.format(num).rstrip('0').rstrip('.'), ['', 'K', 'M', 'B', 'T'][magnitude])

df = pd.DataFrame(data=data)
df['2022 Population Text'] = df['2022 Population'].apply(lambda x: human_format(x))

data2022 = dict(type = 'choropleth',
            colorscale = 'agsunset',
            reversescale = True,
            locations = df['Country/Territory'],
            locationmode = 'country names',
            z = df['2022 Population'],
            text = df['CCA3'],
            customdata = df['2022 Population Text'],
            marker = dict(line = dict(color = 'rgb(12, 12, 12)', width=1)),
            colorbar = {'title': 'Population'},
            hovertemplate = "%{customdata}<br>%{text}<extra></extra>"
            )

layout2022 = dict(title = '<b>World Population 2022<b>',
               geo = dict(showframe = True,
                          showland = True, landcolor = 'rgb(198, 197, 198)',
                          showlakes = True, lakecolor = 'rgb(85, 173, 240)',
                          showrivers = True, rivercolor = 'rgb(173, 216, 230)', 
                          showocean = True, oceancolor = 'rgb(173, 216, 230)',
                          projection = {'type': 'natural earth'}))

choromap2022 = go.Figure(data=[data2022], layout=layout2022) 

choromap2022.update_geos(lataxis_showgrid = True, lonaxis_showgrid = True)

choromap2022.update_layout(height = 600,
                       title_x = 0.5, 
                       title_font_color = 'red',
                       title_font_family = 'Times New Roman',
                       title_font_size = 30,
                       margin=dict(t=80, r=50,  l=50),
                       )

choromap2022.show()

Note: Since China wasn't included in your sample data, I changed the population of AFG to 1412000000 to test that the hovertemplate would display it as '1.4B'.

enter image description here

Derek O
  • 16,770
  • 4
  • 24
  • 43
  • Hi Derek, I really appreciated, this helps me a lot. I have one more question, do format ```1412000000``` and display it as ```1.4B``` is a good way and keep information concise, or should I keep it as default ? – Đạt Dương Dec 31 '22 at 19:51
  • @ĐạtDương that is your choice – I think it's a good way to keep it concise because `1.4B` will be quickly understood by everyone, but `1412000000` requires people to count the number of digits. you could add commas so that it is formatted `1,412,000,000` but it also just takes up more room and I think `1.4B` looks better in the hover – Derek O Dec 31 '22 at 21:00