Polygons/Multipolygons refusing to display

I am trying to get the polygons/multipolygons from this dataset (geo-countries/data/countries.geojson at cd9e0635901eac20294a57ee3b3ce0684d5e3f1a · datasets/geo-countries · GitHub) and I am having some trouble. I don’t know how to get the polygons to appear on a Plotly Express map and my goal is to have all of the countries on the map appear in a polygon. I am using Plotly Express, Pandas, and JSON to get the data out of the file and into a list. I got all of the properties (name, iso a3/a2) out of the file, but the polygons are refusing to show. Nothing on the map appears, and I want the map to eventually be interactive. Any help with this one thing (getting the polygons to appear) would be greatly appreciated!

with open('gdata.geojson') as f:
    gdata = json.load(f)

features = gdata['features']
for feature in gdata["features"]:
    feature["id"] = feature["properties"]["ADMIN"]

gjsn = []
for feature in features:
    gjsn.append(feature['geometry'])
print(gjsn)

fig = px.choropleth_mapbox(df, geojson=gjsn, locations='ISO_A3', hover_name='ADMIN',  center={'lat': 0, "lon": -0},  mapbox_style='carto-positron', zoom=4)
fig.show()

(I removed some unrelated and already functional code)

I don’t know if I should be using different values or whatnot for geojson, locations, and to display the name.

Hi @apicem
:wave: welcome to the community.

Can you please share a minimal reproducible example code with us so we can try to run it on our computer and see the same thing you’re seeing?

@topaccina you recently did some work with polygons. Was that with Dash Leaflet or Plotly? Do you know what @apicem could do?

Hi, here’s the code that I do have so far:

import json
import pandas as pd
import plotly.express as px
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets

# Open the .geojson file
with open('countries.geojson') as f:
    gjd = json.load(f)

# Assuming geojson_data is your GeoJSON data
features = gjd['features']
for feature in gjd["features"]:
    feature["id"] = feature["properties"]["ADMIN"]

# Extracting properties from properties and creating a DataFrame
data = []
for feature in features:
    properties = feature['properties']
    data.append(properties)
print(data)

# Creating a DataFrame
df = pd.DataFrame(data)
print(df)

# Locating coordinates
geojson = []
for feature in features:
    geojson.append(feature['geometry'])
print(geojson)

# Plotting the map
fig = px.choropleth_mapbox(df,
                           locations='ISO_A3', hover_name='ADMIN',
                           center={'lat': 45.5517, "lon": -73.7073},
                           mapbox_style='carto-positron', zoom=9)
fig.update_layout(margin={'r': 0, 't': 0, 'l': 0, 'b': 0})
fig.show()


class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.button = QtWidgets.QPushButton('Plot', self)
        self.browser = QtWebEngineWidgets.QWebEngineView(self)

        vlayout = QtWidgets.QVBoxLayout(self)
        vlayout.addWidget(self.button, alignment=QtCore.Qt.AlignHCenter)
        vlayout.addWidget(self.browser)

        self.button.clicked.connect(self.show_graph)
        self.resize(1000, 800)

    def show_graph(self):
        df = pd.DataFrame(data)
        print(df)
        # Plotting
        fig = px.choropleth_mapbox(data_frame=df, geojson=gjd,
                                   locations='ADMIN', featureidkey='properties.id',
                                   center={'lat': 45.5517, "lon": -73.7073},
                                   mapbox_style='carto-positron', zoom=9)
        fig.update_layout(margin={'r': 0, 't': 0, 'l': 0, 'b': 0})
        self.browser.setHtml(fig.to_html(include_plotlyjs='cdn'))


if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    widget = Widget()
    widget.show()
    app.exec()

As of now, the goal is to open the PyQt5 window and display the chart. I do not need any CSV data as I want to get where the user clicked on the map and within which polygon. The goal of the project would be a sort of flag quiz (like the Mapbox flag quiz you can look up on Google). I am unsure if you can add images and a score counter to the plot, and if so, I would add the flag image to the top right and the score to the top left. If not, I would add it to a separate area of the PyQt5 window. So, if you click the right country you gain a point, but lose one if you click the wrong country.

The reason why the program opens 2 instances of the same plot is so I could see what was going on. The PyQt5 window appeared to work for some time with several edits I made a while back but doesn’t work with the browser plot version only showing the map but not the polygons.

I believe the error is coming from the lack of ids, although I could be wrong. I am trying to work out an implementation of identifying/keying the features[‘geometry’] of the geojson file as described here: b'Tips to extract data from a geojson di | empet | Plotly'. Currently, I am still struggling, but will update you when something works! Do let me know what I should try, though.

UPDATE:

import json
import pandas as pd
import plotly.express as px
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets


# Open the .geojson file
with open('countries.geojson') as f:
    gjdata = json.load(f)

# Assuming geojson_data is your GeoJSON data
features = gjdata['features']
for feature in gjdata["features"]:
    feature["id"] = feature["properties"]["ADMIN"]

# Extracting properties from properties and creating a DataFrame
data = []
for feature in features:
    properties = feature['properties']
    data.append(properties)
print(data)

# Creating a DataFrame
df = pd.DataFrame(data)
print(df)

# Locating coordinates
geojson = []
for feature in features:
    geojson.append(feature['geometry'])
# print(geojson)

print(gjdata.keys())
gjdata['features'][0].keys()
print(gjdata['features'][0].keys())

for k in range(len(gjdata['features'])):
    gjdata['features'][k]['id'] = k
    df['id'] = k
    print(k)

# Plotting the map
fig = px.choropleth_mapbox(df, geojson=gjdata, locations='id',
                           hover_name='ADMIN', hover_data=all,
                           mapbox_style='carto-positron', zoom=4)
fig.update_layout(margin={'r': 0, 't': 0, 'l': 0, 'b': 0})
fig.show()

I have tried to create a new column to the dataframe to identify the data for the locations= part of the required data for the graph. The printout to the terminal appears somewhat promising according to the following link: b'Tips to extract data from a geojson di | empet | Plotly'. I received the following error:

Traceback (most recent call last):
  File "C:\#####\geoquiz_app\Limited Project (Map Quiz)\main2.py", line 68, in <module>
    fig = px.choropleth_mapbox(df, geojson=gjdata, locations='id',
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\#####\geoquiz_app\.venv\Lib\site-packages\plotly\express\_chart_types.py", line 1284, in choropleth_mapbox
    return make_figure(args=locals(), constructor=go.Choroplethmapbox)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\#####\geoquiz_app\.venv\Lib\site-packages\plotly\express\_core.py", line 2090, in make_figure
    args = build_dataframe(args, constructor)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\#####\geoquiz_app\.venv\Lib\site-packages\plotly\express\_core.py", line 1319, in build_dataframe
    args[field] = list(args[field])
                  ^^^^^^^^^^^^^^^^^
TypeError: 'builtin_function_or_method' object is not iterable

hello @apicem @adamschroeder ,
if I understood correctly the goal is just to have the shape plotted on the map.
If this is correct… I think that gjdata has already all the info you need.
you can get the proper geometries starting from gjdata[“features”] and create a geopandas dataframe.

Here the code I tested (please note I plot only the tail of the geopandas dataframe to save time)
I commented out what I did not need to get the map with the shapes…
(tested with python 10)

import json
#import pandas as pd
import plotly.express as px
#from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
import geopandas as gpd

# Open the .geojson file
with open('countries.geojson') as f:
    gjdata = json.load(f)

# Assuming geojson_data is your GeoJSON data
features = gjdata['features']
for feature in gjdata["features"]:
    feature["id"] = feature["properties"]["ADMIN"]

# Extracting properties from properties and creating a DataFrame
data = []
for feature in features:
    properties = feature['properties']
    data.append(properties)
print(data)

# Creating a DataFrame
#df = pd.DataFrame(data)
#print(df)

# Locating coordinates
geojson = []
for feature in features:
    geojson.append(feature['geometry'])
# print(geojson)

print(gjdata.keys())
gjdata['features'][0].keys()
print(gjdata['features'][0].keys())

# for k in range(len(gjdata['features'])):
#     gjdata['features'][k]['id'] = k
#     df['id'] = k
#     print(k)

##!!!!! plot only the tail to save time"
geo_df= gpd.GeoDataFrame.from_features(
    gjdata["features"]
).set_index("ADMIN").tail(5)
#Plotting the map
fig = px.choropleth_mapbox(geo_df, geojson=geo_df.geometry,
                          locations=geo_df.index,
                           color=geo_df.index,
                           center={"lat": -37, "lon": 53.7073},
                          mapbox_style='carto-positron', zoom=2)
fig.update_layout(margin={'r': 0, 't': 0, 'l': 0, 'b': 0})
fig.show()

1 Like

Thank you! Makes much more sense now as to why it was not working initially. Again, thank you for your help!

1 Like