here.inspector.keplergl.utils
Source code for here.inspector.keplergl.utils
Copyright (C) 2022-2023 HERE Global B.V. and its affiliate(s).
All rights reserved.
This software and other materials contain proprietary information
controlled by HERE and are protected by applicable copyright legislation.
Any use and utilization of this software and other materials and
disclosure to any third parties is conditional upon having a separate
agreement with HERE for the access, use, utilization or disclosure of this
software. In the absence of such agreement, the use of the software is not
allowed.
"""
Helper utilities for the Kepler-based inspector
"""
import json
from typing import Dict, Union
import geojson
import geopandas as gpd
from geopandas import GeoDataFrame
from here.inspector.utils import Features
from mapquadlib import HereQuad
def _geojson_with_longkey(tile_id: int) -> dict:
"""
Return GeoJSON geometry for given mapquad with its long key as parameter.
The quad's "long key" (an integer) will appear as "tile_id" in the
properties.
:param tile_id: Tile id
:returns: A dict representing a GeoJSON geometry (polygon) for the mapquad.
"""
quad = HereQuad.from_long_key(tile_id)
gj: dict = quad.bounding_box._geojson()
if gj:
fix_coordinates(gj)
feature = {"type": "Feature", "geometry": gj, "properties": {"tile_id": tile_id}}
return feature
[docs]
def fix_coordinates(geometry: Dict) -> Dict:
"""
fix_coordinates modifies any coordinate values of (180, 90) or (-180, -90)
in a geometry dict to (179.999, 89.999) or (-179.999, -89.999) respectively.
The function takes in a single argument:
:param geometry: A dictionary representing a geometry in GeoJSON format.
It should contain a 'coordinates' key with list of coordinates.
:returns: modified geometry dictionary.
"""
for i, coord in enumerate(geometry["coordinates"][0]):
if coord[0] == 180.0:
geometry["coordinates"][0][i][0] = 179.999
elif coord[0] == -180.0:
geometry["coordinates"][0][i][0] = -179.999
if coord[1] == 90.0:
geometry["coordinates"][0][i][1] = 89.999
elif coord[1] == -90.0:
geometry["coordinates"][0][i][1] = -89.999
return geometry
[docs]
def convert_to_2d_2(gdf: Union[Features, GeoDataFrame]) -> Union[Features, GeoDataFrame]:
"""
Convert the feature object from 3D to 2D
by removing the z coordinates from the geometry.
If a GeoDataFrame is passed, it will convert all
the geometries of all the features in the dataframe.
:param gdf: A Feature object or GeoDataFrame with geometry and coordinates in 3D.
:return: A Feature object or GeoDataFrame
with the same properties but in 2D by removing the z coordinates.
"""
Define a recursive function to convert nested coordinates to 2D
def convert_nested_coords_to_2d(coords):
for coord in coords:
if isinstance(coord[0], list):
convert_nested_coords_to_2d(coord)
else:
coord[0] = (
179.9999
if coord[0] == 180.0
else -179.9999
if coord[0] == -180.0
else coord[0]
)
coord[1] = (
89.9999 if coord[1] == 90.0 else -89.9999 if coord[1] == -90.0 else coord[1]
)
coord[:] = coord[:2]
def conversion(geom):
Check if the object is a Feature
if geom["type"] == "Feature":
Get the geometry of the feature
geometry = geom["geometry"]
Check if the geometry is a Point
if geometry["type"] == "Point":
Convert the coordinates to 2D
geometry["coordinates"] = geometry["coordinates"][:2]
Check if the geometry is a LineString or Polygon
elif geometry["type"] in ["LineString", "Polygon"]:
Convert the coordinates to 2D
convert_nested_coords_to_2d(geometry["coordinates"])
Check if the geometry is a MultiPoint, MultiLineString, or MultiPolygon
elif geometry["type"] in ["MultiPoint", "MultiLineString", "MultiPolygon"]:
Convert the coordinates to 2D
for subcoords in geometry["coordinates"]:
convert_nested_coords_to_2d(subcoords)
Check if the object is a FeatureCollection
elif geom["type"] == "FeatureCollection":
Loop through the features in the collection
for feature in geom["features"]:
Convert the feature to 2D
convert_to_2d_2(feature)
return geom
if isinstance(gdf, gpd.GeoDataFrame):
features = json.loads(gdf.to_json())
for feature in features["features"]:
conversion(feature["geometry"])
gdf.set_geometry(gpd.GeoDataFrame.from_features(features).geometry)
elif isinstance(gdf, (dict, geojson.feature.Feature, geojson.feature.FeatureCollection)):
geom = gdf
conversion(geom)
return gdf
[docs]
def process_dataframe(new_df_feature: Features):
"""
Convert the Feature object from GeoJSON format to a Python dictionary.
This function is useful when the add data method
doesn't accept FeatureCollection object.
:param new_df_feature: a Feature object in GeoJSON format.
:return: a Python dictionary containing the same
information as the input Feature object.
"""
Serialize the FeatureCollection to a JSON string
json_string = geojson.dumps(new_df_feature)
Parse the JSON string into a dictionary
new_json_string = json.loads(json_string)
return new_json_string
HEIGHT = 600