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.
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.
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()