How to create maps in Plotly with non-US locations | by Kerry Halupka | Towards Data Science

Plotly makes it really easy to display geospatial data in an interactive choropleth map, particularly if your data pertains to the US. Unfortunately, if the location of your data is outside of the US, and more granular than country-level, things get a bit murky. You might feel like the poor cousin when sifting through the depths of Stack Overflow and GitHub Issues to find clues to achieving your mapping goals. I’m here to say I’ve been there, I feel your pain, and there is a solution. Let’s jump in!
For this tutorial, I’m going to display unemployment data from Victoria, Australia. I got my data from the Australian Bureau of Statistics Stat portal. This portal allows you to select the geospatial granularity of your data. I selected to download “Census 2016, G43 Labour force status by age by sex (LGA)”, where LGA refers to Local Government Area, which is the spatial granularity of the data. Let’s load it in and reshape it a bit:
The column “LGA_2016” is referring to the ID or code for each Local Government Area (LGA). By pivoting the data we’ve created one row, and therefore one unemployment rate, for each LGA. This is important since when we create our map we will need one value for each geospatial area we show.
The key to creating a Plotly choropleth with data outside of the US is to have a GeoJSON with geometries corresponding to your data. While sometimes you may already have a GeoJSON, it’s more likely you’ll have to create one, which is the case for me.
I’m using The Australian Bureau of Statistics again to access geometries of my data in ESRI Shapefile format, via this link (I downloaded “Local Government Areas ASGS Ed 2020 Digital Boundaries in ESRI Shapefile Format”). This format can be loaded in to Python using Geopandas, by pointing it at the ‘.shp’ file:
Now we can see that both the data frames have a column containing a code for each LGA, which is what we will be joining on. Each row also has a “geometry” value, which is the geospatial outline of the LGA.
Side note: For plotting of Australian data the ABS will be your best bet for acquiring a shape file. I’m not as well versed in data for other countries (please leave a comment if you know of websites providing geo data from your country), but if you’re stuck http://www.diva-gis.org/gdata contains shape files, free to download, for most countries.
If both of your data frames have matching keys like mine, then it’s a simple matter to join them on that column, and drop rows with no data in the required columns.
I also like to display my data frame at this point using Geopandas as a sanity check, and to know what my plotly map should end up looking like.
NOTE: Merging the data frames isn’t strictly necessary for choropleths in Plotly, but it does serve to align the geometries with the data to be plotted. If you don’t do this merging step you will need to make sure that the data frame containing your data and the shapefile/geoJSON containing the geometries have corresponding and identically sorted rows.
So now we’ve got a Geo Dataframe with all of the info in it that we need to map it using Plotly. Except for one little detail: Plotly wants it in GeoJSON format. Luckily, Geopandas can easily convert from data frame to GeoJSON, as below. First though, you will want to make sure your geometries are in lat/long format (EPSG:4236), which is what Plotly is expecting.
Your GeoJSON should look something like this:
{'type': 'FeatureCollection', 'features': [{'id': '20110',   'type': 'Feature',   'properties': {'LGA_2016': '20110',    'LGA_CODE20': '20110',    'LGA_NAME20': 'Alpine (S)',    'percent_unemployed': 0.037868162692847124},   'geometry': {'type': 'Polygon',    'coordinates': (((146.67057224400003, -36.56828108499997),      (146.670555271, -36.568038086999934),      (146.67051924600003, -36.567766081999935),      (146.67051924600003, -36.56750909899995),      (146.6704312810001, -36.56723709299996),      ...
You can see that this dictionary contains a nested dictionary called ‘features’, in which the index of each of your data frames rows is stored as ‘id’. If you didn’t create your geoJSON using this method then make sure yours has a similar format.
There’s a couple of things of note in the code below. First up, you need a Mapbox access token. You can get this by creating a Mapbox account here. For personal use levels, accessing the API will be free. Secondly, we assign the data for the map, using the geoJSON for the geometries, and the merged data frame for the colors and text.Finally, we set some parameters to define the layout of the map, including the title, centre lat/long, and zoom level.
This will make a beautiful, interactive map, showing the unemployment rate in Victoria. Nice!
You can customise this tutorial using your own data and shapefiles. To see the code on GitHub click here.