Related
Is there any way to convert a pandas dataframe into a json with different levels, I have this dataframe:
df = pd.DataFrame([
{"type":"Feature","Id":319,"Departament":"1 DE MAYO","State":"CHACO","coordinates":[[[-58.95370956800002, -26.87059472200002]]]},
{"type":"Feature","Id":320,"Departament":"12 DE OCTUBRE","State":"CHACO","coordinates":[[[-58.95370956800002, -26.87059472200002]]]},
{"type":"Feature","Id":314,"Departament":"2 DE ABRIL","State":"CHACO","coordinates":[[[-58.95370956800002, -26.87059472200002]]]},
{"type":"Feature","Id":308,"Departament":"25 DE MAYO","State":"CHACO","coordinates":[[[-58.95370956800002, -26.87059472200002]]]},
{"type":"Feature","Id":100,"Departament":"25 DE MAYO","State":"CHACO","coordinates":[[[-58.95370956800002, -26.87059472200002]]]}])
I really want an output like so:
"features": [
{
"type": "Feature",
"properties": {
"id": 319,
"Departament": "1 DE MAYO",
"State": "CHACO"
},
"geometry": {
"coordinates": [
[
[
-58.32487869300002,
-30.838373183999977
]
]
]
}
}
]
}
Thanks for your help i hope i was clear.
You can use:
import json
def to_json(row):
return {'type': row.iloc[0],
'properties': row.iloc[1:-1].to_dict(),
'geometry': row.iloc[-1]}
data = {'features': df.apply(to_json, axis=1).to_list()}
print(json.dumps(data, indent=2))
Output:
{
"features": [
{
"type": "Feature",
"properties": {
"Id": 319,
"Departament": "1 DE MAYO",
"State": "CHACO"
},
"geometry": [
[
[
-58.95370956800002,
-26.87059472200002
]
]
]
},
{
"type": "Feature",
"properties": {
"Id": 320,
"Departament": "12 DE OCTUBRE",
"State": "CHACO"
},
"geometry": [
[
[
-58.95370956800002,
-26.87059472200002
]
]
]
},
{
"type": "Feature",
"properties": {
"Id": 314,
"Departament": "2 DE ABRIL",
"State": "CHACO"
},
"geometry": [
[
[
-58.95370956800002,
-26.87059472200002
]
]
]
},
{
"type": "Feature",
"properties": {
"Id": 308,
"Departament": "25 DE MAYO",
"State": "CHACO"
},
"geometry": [
[
[
-58.95370956800002,
-26.87059472200002
]
]
]
},
{
"type": "Feature",
"properties": {
"Id": 100,
"Departament": "25 DE MAYO",
"State": "CHACO"
},
"geometry": [
[
[
-58.95370956800002,
-26.87059472200002
]
]
]
}
]
}
You can use the dataframes’ .to_json() method.
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 have a Geojson as follows:
data = {
"type": "FeatureCollection",
"name": "entities",
"features": [
{
"type": "Feature",
"properties": {
"Layer": "0",
"SubClasses": "AcDbEntity:AcDbBlockReference",
"EntityHandle": "3C8",
"area": "141.81",
"type": "p",
"Text": "area:141.81;type:p"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2721.1572741014097,
1454.3223948456648
],
[
2720.121847266826,
1454.3223948456648
],
[
2720.121847266826,
1452.6092152478227
],
[
2710.5679254269344,
1452.6092152478227
],
[
2721.1572741014097,
1430.1478385206133
],
[
2721.1572741014097,
1454.3223948456648
]
]
]
}
},
{
"type": "Feature",
"properties": {
"Layer": "0",
"SubClasses": "AcDbEntity:AcDbBlockReference",
"EntityHandle": "3CE",
"area": "44.79",
"type": "h",
"Text": "area:44.79;type:h"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2710.723323781393,
1450.3320226620049
],
[
2720.0654518264787,
1450.3320226620049
],
[
2720.0654518264787,
1445.537183875705
],
[
2710.723323781393,
1445.537183875705
],
[
2710.723323781393,
1450.3320226620049
]
]
]
}
},
{
"type": "Feature",
"properties": {
"Layer": "0",
"SubClasses": "AcDbEntity:AcDbBlockReference",
"EntityHandle": "610",
"name": "706",
"area": "92.28",
"type": "o",
"Text": "name:706;area:92.28;type:o"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2714.603212251531,
1462.7249212430308
],
[
2711.7289360797,
1462.7249212430308
],
[
2711.7289360797,
1464.852506681824
],
[
2705.7302059101926,
1460.6840827804538
],
[
2710.567925426934,
1454.3223948456637
],
[
2710.567925426934,
1453.838838298367
],
[
2714.603212251531,
1453.838838298367
],
[
2714.603212251531,
1462.7249212430308
]
]
]
}
}
]
}
I want to insert "name": "" if name does not exist in properties, and delete "Text" object since it's duplicated, how can I do that in Python?
Thanks a lot at advance!
Expected result:
data = {
"type": "FeatureCollection",
"name": "entities",
"features": [
{
"type": "Feature",
"properties": {
"Layer": "0",
"SubClasses": "AcDbEntity:AcDbBlockReference",
"EntityHandle": "3C8",
"name": "",
"area": "141.81",
"type": "p"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2721.1572741014097,
1454.3223948456648
],
[
2720.121847266826,
1454.3223948456648
],
[
2720.121847266826,
1452.6092152478227
],
[
2710.5679254269344,
1452.6092152478227
],
[
2721.1572741014097,
1430.1478385206133
],
[
2721.1572741014097,
1454.3223948456648
]
]
]
}
},
{
"type": "Feature",
"properties": {
"Layer": "0",
"SubClasses": "AcDbEntity:AcDbBlockReference",
"EntityHandle": "3CE",
"name": "",
"area": "44.79",
"type": "h"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2710.723323781393,
1450.3320226620049
],
[
2720.0654518264787,
1450.3320226620049
],
[
2720.0654518264787,
1445.537183875705
],
[
2710.723323781393,
1445.537183875705
],
[
2710.723323781393,
1450.3320226620049
]
]
]
}
},
{
"type": "Feature",
"properties": {
"Layer": "0",
"SubClasses": "AcDbEntity:AcDbBlockReference",
"EntityHandle": "610",
"name": "706",
"area": "92.28",
"type": "o"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
2714.603212251531,
1462.7249212430308
],
[
2711.7289360797,
1462.7249212430308
],
[
2711.7289360797,
1464.852506681824
],
[
2705.7302059101926,
1460.6840827804538
],
[
2710.567925426934,
1454.3223948456637
],
[
2710.567925426934,
1453.838838298367
],
[
2714.603212251531,
1453.838838298367
],
[
2714.603212251531,
1462.7249212430308
]
]
]
}
}
]
}
UPDATE:
My solution so far, it seems works.
import json
features = data["features"]
for i in features:
d = i["properties"]
if "name" not in d:
d["name"] = ""
if i["properties"]["Text"] is not None:
del i["properties"]["Text"]
I define it as a function, but in some cases I get an error as follows. Does someone know how to fix it? Thanks.
Traceback (most recent call last):
File "<ipython-input-1-8e3095f67c57>", line 138, in <module>
modify_geojson(output_file)
File "<ipython-input-1-8e3095f67c57>", line 102, in modify_geojson
if i["properties"]["Text"] is not None:
KeyError: 'Text'
In each property 'Text' is only present once. Please explain where it's duplicated?
My solution so far, it seems works.
import json
features = data["features"]
for i in features:
d = i["properties"]
if "name" not in d:
d["name"] = ""
if i["properties"]["Text"] is not None:
del i["properties"]["Text"]
I define it as a function, but in some cases I get an error as follows. Does someone know how to fix it? Thanks.
Traceback (most recent call last):
File "<ipython-input-1-8e3095f67c57>", line 138, in <module>
modify_geojson(output_file)
File "<ipython-input-1-8e3095f67c57>", line 102, in modify_geojson
if i["properties"]["Text"] is not None:
KeyError: 'Text'
I have geojson file as follows:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": [
[
57.45849609375,
57.36801461845934
],
[
57.10693359375,
56.31044317134597
],
[
59.205322265625,
56.20059291588374
],
[
59.4140625,
57.29091812634045
],
[
57.55737304687501,
57.36801461845934
]
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": [
[
59.40307617187499,
57.29685437021898
],
[
60.8203125,
57.314657355733274
],
[
60.74340820312499,
56.26776108757582
],
[
59.227294921875,
56.21281407174654
],
[
59.447021484375,
57.29091812634045
]
]
}
}
]
}
I want to replace LineString in "type": "LineString" with Polygon, and also, replace coordinates last point of each linestring by coordinates of first point to make it close if it has more than 3 points.
How can I do it in Python with geopandas or pandas? Thanks.
Here is expected output:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
57.45849609375,
57.36801461845934
],
[
57.10693359375,
56.31044317134597
],
[
59.205322265625,
56.20059291588374
],
[
59.4140625,
57.29091812634045
],
[
57.45849609375,
57.36801461845934
]
]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
59.40307617187499,
57.29685437021898
],
[
60.8203125,
57.314657355733274
],
[
60.74340820312499,
56.26776108757582
],
[
59.227294921875,
56.21281407174654
],
[
59.40307617187499,
57.29685437021898
]
]
}
}
]
}
Script to get type and coordinates of first LineString:
import json
from pprint import pprint
with open('data.geojson') as f:
data = json.load(f)
pprint(data)
data["features"][0]["geometry"]['type']
data["features"][0]["geometry"]['coordinates']
You can achieve that with the json module:
file_line = 'file.json'
file_poly = 'file_poly.json'
import json
with open(file_line, 'r') as f:
data = json.load(f)
for feature in data['features']:
if (feature['geometry']['type'] == 'LineString') & (len(feature['geometry']['coordinates']) >= 3):
feature['geometry']['type'] = 'Polygon'
feature['geometry']['coordinates'].append(feature['geometry']['coordinates'][0])
with open(file_poly, 'w+') as f:
json.dump(data, f, indent=2)