geoJson mapping with bokeh, wrong axes - python

I want to map some locations which are stored in a geoJson format. The problem is that map axes (both x and y) goes from -2e7 to 2e7 instead of -180 to 180 (longtidue -x axis-) and -90 to 90 (for latitude -y axis-). Then, when I want to map my position {"longitude": 48.90314,"latitude":20.70890} I have to write {"longitude": 4890314,"latitude":2070890} otherwise it is located wrong in the map.
Does anyone knows why this happens or what I am doing wrong?
This is my python script:
from bokeh.io import output_file, show
from bokeh.models import GeoJSONDataSource, HoverTool
from bokeh.plotting import figure
from bokeh.tile_providers import CARTODBPOSITRON
import json
geo_source = GeoJSONDataSource(geojson=json.dumps(geoJson_file))
p = figure()
p.add_tile(CARTODBPOSITRON)
p.circle(x='x', y='y', alpha=0.9, size=10, source=geo_source)
p.add_tools(HoverTool(tooltips=[
("name", "#name"),
("(Long, Lat)", "(#x, #y)"),
]))
output_file("geojson.html")
show(p)
This is the geoJson file (geoJson_file in py script) I want to map:
{
"type": "FeatureCollection",
"features": [
{
"geometry": {
"type": "Point",
"coordinates": [
48.90314,
20.70890
]
},
"type": "Feature",
"properties": {
"name": "marker_1"
}
},
{
"geometry": {
"type": "Point",
"coordinates": [
-94.91849,
58.60959
]
},
"type": "Feature",
"properties": {
"name": "marker_2"
}
},
{
"geometry": {
"type": "Point",
"coordinates": [
81.03195,
38.94440
]
},
"type": "Feature",
"properties": {
"name": "marker_3"
}
}
]
}
And this is the map I get (but as you can see lon/lat is not the one it should be because I have to modify the lon/lat numbers from of the geoJson file (48.90314 to 4890314 and 20.70890 to 2070890) otherwise it is not properly located in the map)

Related

Exporting a file in .geojson format without T inside the date

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 ] } }
]
}

How to display a heatmap on a specific parameter with geopandas?

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

Delete polygons that have one or more side parts in common

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]
]
]
}
}
]
}

Visualize a generic GeoJson file with Plotly

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"]],
)
)

Not understanding how work with "urn:ogc:def:crs:OGC:1.3:CRS84" in geopandas

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.

Categories

Resources