Related
I am trying to export a geodataframe in .geojson format. Before exporting, I print the geodataframe in the terminal and the dates appear as I wish:
After writing the line to export the file in .geojson format
predicted_events.to_file("predicted_events.geojson", driver='GeoJSON'),
I print from the terminal and a T appears in the date column:
When I export in .csv format, the T does not appear either.
It is correctly encoding the data type of the column. Convert from date to string and then the GEOJSON contains what you require.
import shapely.wkt
import pandas as pd
import geopandas as gpd
from pathlib import Path
gdf = gpd.GeoDataFrame(geometry=[shapely.wkt.loads(p) for p in ['POINT (6.493069295913722 55.7355541882027)',
'POINT (15.43828764139886 46.30211698572747)',
'POINT (12.60117419209274 43.69100105361232)',
'POINT (6.876712332538435 40.26684145530385)']], data={"date":pd.date_range("1-jan-2021",periods=4)})
f = Path.cwd().joinpath("predicted_events.geojson")
gdf.to_file(f, driver='GeoJSON')
with open(f) as fh:
text = fh.read()
print(text)
gdf["date"] = gdf["date"].astype(str)
gdf.to_file(f, driver='GeoJSON')
with open(f) as fh:
text = fh.read()
print(text)
output
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "date": "2021-01-01T00:00:00" }, "geometry": { "type": "Point", "coordinates": [ 6.493069295913722, 55.735554188202698 ] } },
{ "type": "Feature", "properties": { "date": "2021-01-02T00:00:00" }, "geometry": { "type": "Point", "coordinates": [ 15.43828764139886, 46.302116985727473 ] } },
{ "type": "Feature", "properties": { "date": "2021-01-03T00:00:00" }, "geometry": { "type": "Point", "coordinates": [ 12.60117419209274, 43.691001053612318 ] } },
{ "type": "Feature", "properties": { "date": "2021-01-04T00:00:00" }, "geometry": { "type": "Point", "coordinates": [ 6.876712332538435, 40.266841455303847 ] } }
]
}
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "date": "2021-01-01" }, "geometry": { "type": "Point", "coordinates": [ 6.493069295913722, 55.735554188202698 ] } },
{ "type": "Feature", "properties": { "date": "2021-01-02" }, "geometry": { "type": "Point", "coordinates": [ 15.43828764139886, 46.302116985727473 ] } },
{ "type": "Feature", "properties": { "date": "2021-01-03" }, "geometry": { "type": "Point", "coordinates": [ 12.60117419209274, 43.691001053612318 ] } },
{ "type": "Feature", "properties": { "date": "2021-01-04" }, "geometry": { "type": "Point", "coordinates": [ 6.876712332538435, 40.266841455303847 ] } }
]
}
In my very simple case I would like to display the heatmap of the points in the points GeoJSON file but not on the geographic density (lat, long). In the points file each point has a confidence property (a value from 0 to 1), how to display the heatmap on this parameter? weight=points.confidence don't seem to work.
for exemple:
#points.geojson
{
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": {"confidence": 0.67}, "geometry": { "type": "Point", "coordinates": [ 37.703471404215918, 26.541625492300192 ] } },
{ "type": "Feature", "properties": {"confidence": 0.76}, "geometry": { "type": "Point", "coordinates": [ 37.009744331225093, 26.710090585532761 ] } },
{ "type": "Feature", "properties": {"confidence": 0.94}, "geometry": { "type": "Point", "coordinates": [ 37.541708538306224, 26.160111944646022 ] } },
{ "type": "Feature", "properties": {"confidence": 0.52}, "geometry": { "type": "Point", "coordinates": [ 37.628566642215354, 25.917300595223857 ] } },
{ "type": "Feature", "properties": {"confidence": 0.46}, "geometry": { "type": "Point", "coordinates": [ 37.676499267124271, 26.653959791866598 ] } },
{ "type": "Feature", "properties": {"confidence": 0.55}, "geometry": { "type": "Point", "coordinates": [ 37.677033863264533, 26.654033815175087 ] } },
{ "type": "Feature", "properties": {"confidence": 0.12}, "geometry": { "type": "Point", "coordinates": [ 37.37522057234797, 26.353271000367258 ] } },
{ "type": "Feature", "properties": {"confidence": 0.62}, "geometry": { "type": "Point", "coordinates": [ 37.396556958266373, 26.459196264023291 ] } },
{ "type": "Feature", "properties": {"confidence": 0.21}, "geometry": { "type": "Point", "coordinates": [ 36.879775221618168, 26.901743663072878 ] } }
]
}
The image below shows my result but it is on the geographic density not confidence score density.
import geoplot as gplt
import geopandas as gpd
import geoplot.crs as gcrs
import matplotlib.pyplot as plt
points = gpd.read_file('points.geojson')
polygons = gpd.read_file('polygons.geojson')
ax = gplt.polyplot(polygons, projection=gcrs.AlbersEqualArea(), zorder=1)
gplt.kdeplot(points, cmap='Reds', shade=True, clip=polygons, ax=ax)
#weight=points.confidence don’t work inside kdeplot()
plt.show()
using your sample data for points
these points are in Saudi Arabia, so assumed that polygons are regional boundaries in Saudi Arabia. Downloaded this from http://www.naturalearthdata.com/downloads/10m-cultural-vectors/
polygon data is a shape file
loaded into geopandas to allow interface to GEOJSON __geo__interface
dynamically filtered this to Saudi using pandas .loc
confidence data is just a straight https://plotly.com/python/mapbox-density-heatmaps/
boundaries are https://plotly.com/python/mapbox-layers/
# fmt: off
points = {
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": {"confidence": 0.67}, "geometry": { "type": "Point", "coordinates": [ 37.703471404215918, 26.541625492300192 ] } },
{ "type": "Feature", "properties": {"confidence": 0.76}, "geometry": { "type": "Point", "coordinates": [ 37.009744331225093, 26.710090585532761 ] } },
{ "type": "Feature", "properties": {"confidence": 0.94}, "geometry": { "type": "Point", "coordinates": [ 37.541708538306224, 26.160111944646022 ] } },
{ "type": "Feature", "properties": {"confidence": 0.52}, "geometry": { "type": "Point", "coordinates": [ 37.628566642215354, 25.917300595223857 ] } },
{ "type": "Feature", "properties": {"confidence": 0.46}, "geometry": { "type": "Point", "coordinates": [ 37.676499267124271, 26.653959791866598 ] } },
{ "type": "Feature", "properties": {"confidence": 0.55}, "geometry": { "type": "Point", "coordinates": [ 37.677033863264533, 26.654033815175087 ] } },
{ "type": "Feature", "properties": {"confidence": 0.12}, "geometry": { "type": "Point", "coordinates": [ 37.37522057234797, 26.353271000367258 ] } },
{ "type": "Feature", "properties": {"confidence": 0.62}, "geometry": { "type": "Point", "coordinates": [ 37.396556958266373, 26.459196264023291 ] } },
{ "type": "Feature", "properties": {"confidence": 0.21}, "geometry": { "type": "Point", "coordinates": [ 36.879775221618168, 26.901743663072878 ] } }
]
}
# fmt: on
import geopandas as gpd
import plotly.express as px
import requests
from pathlib import Path
from zipfile import ZipFile
import urllib
# fmt: off
# download boundaries
url = "https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip"
f = Path.cwd().joinpath(urllib.parse.urlparse(url).path.split("/")[-1])
# fmt: on
if not f.exists():
r = requests.get(url, stream=True, headers={"User-Agent": "XY"})
with open(f, "wb") as fd:
for chunk in r.iter_content(chunk_size=128):
fd.write(chunk)
zfile = ZipFile(f)
zfile.extractall(f.stem)
# load downloaded boundaries
gdf2 = gpd.read_file(str(f.parent.joinpath(f.stem).joinpath(f"{f.stem}.shp")))
# confidence data
gdf = gpd.GeoDataFrame.from_features(points)
# now the simple bit, densitity plot data and Saudi Arabia regional boundaries as a layer
fig = px.density_mapbox(
gdf, lat=gdf.geometry.y, lon=gdf.geometry.x, z="confidence"
).update_layout(
mapbox={
"style": "carto-positron",
"zoom": 6,
"layers": [
{
"source": gdf2.loc[gdf2["iso_a2"].eq("SA")].geometry.__geo_interface__,
"type": "line",
}
],
},
margin={"l":0,"r":0,"t":0,"b":0}
)
fig
I am trying to solve a particular case of comparison of polygons to others. I have five polygons distributed as in the figure below. The black polygon is the one with the largest area.
There may be other similar cases, the main rule is to remove the smallest polygons among all those that have one or more side portions in common.
The data for this case are in a GeoJson file as follows:
{"type":"FeatureCollection","features":[
{"type":"Feature","properties":{"id":1},"geometry":{"type":"Polygon","coordinates":[[[3.4545135498046875,45.533288879467456],[3.4960556030273433,45.533288879467456],[3.4960556030273433,45.57055337226086],[3.4545135498046875,45.57055337226086],[3.4545135498046875,45.533288879467456]]]}},
{"type":"Feature","properties":{"id":2},"geometry":{"type":"Polygon","coordinates":[[[3.4545135498046875,45.52917023833511],[3.4960556030273433,45.52917023833511],[3.4960556030273433,45.53891018749409],[3.4545135498046875,45.53891018749409],[3.4545135498046875,45.52917023833511]]]}},
{"type":"Feature","properties":{"id":3},"geometry":{"type":"Polygon","coordinates":[[[3.4845542907714844,45.5298015824607],[3.5159683227539062,45.5298015824607],[3.5159683227539062,45.543388795387294],[3.4845542907714844,45.543388795387294],[3.4845542907714844,45.5298015824607]]]}},
{"type":"Feature","properties":{"id":4},"geometry":{"type":"Polygon","coordinates":[[[3.465328216552734,45.542667432984864],[3.4735679626464844,45.542667432984864],[3.4735679626464844,45.5478369923404],[3.465328216552734,45.5478369923404],[3.465328216552734,45.542667432984864]]]}},
{"type":"Feature","properties":{"id":5},"geometry":{"type":"Polygon","coordinates":[[[3.4545138850808144,45.56799974017372],[3.4588050842285156,45.56799974017372],[3.4588050842285156,45.57055290285386],[3.4545138850808144,45.57055290285386],[3.4545138850808144,45.56799974017372]]]}}]}
Is there a solution to delete only the two blue polygons(id 2 and 5)? In python.
By transforming the Polygons into LineString one could look if a Linestring is a portion of another Linestring ? But I don't see how to do it. Or maybe looking to see if the LineString of the black and blue polygons have more than two points in common ? But we can't convert a LineString into more than two points.
The following approach may work for you using shared_paths which correctly calls out the path overlap between polygons 1, 2 and 5:
import json
import shapely as sh
import shapely.ops as ops
import shapely.geometry as geo
with open('./test.json') as f:
features = json.load(f)['features']
for f1 in features:
for f2 in features:
id1 = f1['properties']['id']
id2 = f2['properties']['id']
if int(id1) > int(id2):
s1 = geo.shape(f1['geometry'])
s2 = geo.shape(f2['geometry'])
coll = ops.shared_paths(s1.boundary, s2.boundary)
if not coll.is_empty:
print(f"{id1} and {id2} have shared path")
# update your feature collection etc
I had to reduce the precision to 5 decimal places in your feature geometry for this to work as initially it only detects the overlap between polygon 1 and 2. The shared corner between polygon 1 and 5 is slightly out in your input FeatureCollection:
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"id": 1
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[3.45451, 45.53328],
[3.49605, 45.53328],
[3.49605, 45.57055],
[3.45451, 45.57055],
[3.45451, 45.53328]
]
]
}
},
{
"type": "Feature",
"properties": {
"id": 2
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[3.45451, 45.52917],
[3.49605, 45.52917],
[3.49605, 45.53891],
[3.45451, 45.53891],
[3.45451, 45.52917]
]
]
}
},
{
"type": "Feature",
"properties": {
"id": 3
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[3.48455, 45.52980],
[3.51596, 45.52980],
[3.51596, 45.54338],
[3.48455, 45.54338],
[3.48455, 45.52980]
]
]
}
},
{
"type": "Feature",
"properties": {
"id": 4
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[3.465328, 45.54266],
[3.473567, 45.54266],
[3.473567, 45.54783],
[3.465328, 45.54783],
[3.465328, 45.54266]
]
]
}
},
{
"type": "Feature",
"properties": {
"id": 5
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[3.454513, 45.56799],
[3.458805, 45.56799],
[3.458805, 45.57055],
[3.454513, 45.57055],
[3.454513, 45.56799]
]
]
}
}
]
}
I want to plot some polygons contained in a GeoJson file. Is it possible to visualize a GeoJson file in Plotly that is not linked directly to a real world location?
As example I can use GeoPandas to plot a generic GeoJson file:
import json
geodata = json.loads(
"""{ "type": "FeatureCollection",
"features": [
{ "type": "Feature",
"geometry": {"type": "Polygon", "coordinates": [[[0,0],[0,1],[1,1]]]},
"properties": {"id": "upper_left"}
},
{ "type": "Feature",
"geometry": {"type": "Polygon", "coordinates": [[[0,0],[1,1],[1,0]]]},
"properties": {"id": "lower_right"}
}
]
}""")
import geopandas as gpd
df_shapes = gpd.GeoDataFrame.from_features(geodata["features"])
df_shapes.plot(color="none")
The result displays the two polygons (triangles) contained in the GeoJson:
How would I plot the same map using Plotly? This answer suggests to use scope to limit the base map that is shown. What can be done if there is no base map?
(I am not asking how to plot a square with a line. The GeoJson is just a simplified example.)
plotly shapes can be drawn.
using traces
It's then a case of list / dict comprehensions to restructure geojson polygons to plotly structure
import json
geodata = json.loads(
"""{ "type": "FeatureCollection",
"features": [
{ "type": "Feature",
"geometry": {"type": "Polygon", "coordinates": [[[0,0],[0,1],[1,1]]]},
"properties": {"id": "upper_left"}
},
{ "type": "Feature",
"geometry": {"type": "Polygon", "coordinates": [[[0,0],[1,1],[1,0]]]},
"properties": {"id": "lower_right"}
}
]
}"""
)
go.Figure(
[
go.Scatter(
**{
"x": [p[0] for p in f["geometry"]["coordinates"][0]],
"y": [p[1] for p in f["geometry"]["coordinates"][0]],
"fill": "toself",
"name": f["properties"]["id"],
}
)
for f in geodata["features"]
]
).update_layout(height=200, width=200, showlegend=False, margin={"l":0,"r":0,"t":0,"b":0})
using shapes
use geopandas geometry to get SVG then extract path
add theses polygons as shapes onto layout
from bs4 import BeautifulSoup
# input to plotly is path. use shapely geometry svg path for this
df_shapes = df_shapes.assign(
svgpath=df_shapes["geometry"].apply(
lambda p: BeautifulSoup(p.svg()).find("path")["d"]
)
)
go.Figure(
layout=dict(
height=200,
width=200,
showlegend=False,
margin={"l": 0, "r": 0, "t": 0, "b": 0},
xaxis={"range": [0, 1]},
yaxis={"range": [0, 1]},
shapes=[{"type": "path", "path": p} for p in df_shapes["svgpath"]],
)
)
I have this geojason file
{
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "visit_date": "2013-03-27Z", "name": "Mayi-Tatu", "n_workers": 150.0, "mineral": "Gold" }, "geometry": { "type": "Point", "coordinates": [ 29.66033, 1.01089 ] } },
{ "type": "Feature", "properties": { "visit_date": "2013-03-27Z", "name": "Mabanga", "n_workers": 115.0, "mineral": "Gold" }, "geometry": { "type": "Point", "coordinates": [ 29.65862, 1.00308 ] } },
{ "type": "Feature", "properties": { "visit_date": "2013-03-27Z", "name": "Molende", "n_workers": 130.0, "mineral": "Gold" }, "geometry": { "type": "Point", "coordinates": [ 29.65629, 0.98563 ] } },
...
{ "type": "Feature", "properties": { "visit_date": "2017-08-31Z", "name": "Kambasha", "n_workers": 37.0, "mineral": "Cassiterite" }, "geometry": { "type": "Point", "coordinates": [ 29.05973167, -2.25938167 ] } }
]
}
I read this file, with the next code:
filename = "ipis_cod_mines.geojson"
df_congomines_crs84_geo = gpd.read_file(filename)
But when I check the crs property of df_congomines_crs84_geo,
df_congomines_crs84_geo.crs
I got "{'init': 'epsg:4326'}", I don't understand why i don't get the right crs. (first question)
After, I read another dataset for the same area (both data belongs to congo)
df_countries_4326_geo = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
This dataset has crs equal to {'init': 'epsg:4326'}.
When i plot both datasets (without change the crs),
ax = congo_df.plot(alpha=0.5, color='brown', figsize=(11,4))
df_congomines_crs84_geo.plot(ax=ax, column='mineral')
plt.show()
I got the next image:
Image result
Why both image are not overlaped if they belong to the same area??? How can I fix it??? Is this problem related to the UTM zone???(second question)
CRS84 is equivalent to WGS84 for which the standard EPSG code is EPSG:4326. CRS84 was defined in an old geojson spec (2008). Reading a geojson file gives EPSG:4326 as the CRS.