Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lonboard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@
BitmapLayer,
BitmapTileLayer,
ColumnLayer,
GeohashLayer,
H3HexagonLayer,
HeatmapLayer,
PathLayer,
PointCloudLayer,
PolygonLayer,
S2Layer,
ScatterplotLayer,
SolidPolygonLayer,
TripsLayer,
Expand All @@ -29,11 +32,14 @@
"BitmapLayer",
"BitmapTileLayer",
"ColumnLayer",
"GeohashLayer",
"H3HexagonLayer",
"HeatmapLayer",
"Map",
"PathLayer",
"PointCloudLayer",
"PolygonLayer",
"S2Layer",
"ScatterplotLayer",
"SolidPolygonLayer",
"TripsLayer",
Expand Down
4 changes: 4 additions & 0 deletions lonboard/layer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
from ._base import BaseArrowLayer, BaseLayer
from ._bitmap import BitmapLayer, BitmapTileLayer
from ._column import ColumnLayer
from ._geohash import GeohashLayer
from ._h3 import H3HexagonLayer
from ._heatmap import HeatmapLayer
from ._path import PathLayer
from ._point_cloud import PointCloudLayer
from ._polygon import PolygonLayer, SolidPolygonLayer
from ._s2 import S2Layer
from ._scatterplot import ScatterplotLayer
from ._trips import TripsLayer

Expand All @@ -28,11 +30,13 @@
"BitmapLayer",
"BitmapTileLayer",
"ColumnLayer",
"GeohashLayer",
"H3HexagonLayer",
"HeatmapLayer",
"PathLayer",
"PointCloudLayer",
"PolygonLayer",
"S2Layer",
"ScatterplotLayer",
"SolidPolygonLayer",
"TripsLayer",
Expand Down
7 changes: 6 additions & 1 deletion lonboard/layer/_a5.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@


class A5Layer(PolygonLayer):
"""The `A5Layer` renders filled and/or stroked polygons based on the [A5](https://a5geo.org) geospatial indexing system."""
"""The `A5Layer` renders filled and/or stroked polygons based on the [A5](https://a5geo.org) geospatial indexing system.

!!! warning
This layer does not currently support auto-centering the map view based on the
extent of the input.
"""

def __init__(
self,
Expand Down
115 changes: 115 additions & 0 deletions lonboard/layer/_geohash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
from __future__ import annotations

from typing import TYPE_CHECKING

import traitlets as t

from lonboard._utils import auto_downcast as _auto_downcast

# Important to import from ._polygon to avoid circular imports
from lonboard.layer._polygon import PolygonLayer
from lonboard.traits import ArrowTableTrait, TextAccessor

if TYPE_CHECKING:
import sys

import pandas as pd
from arro3.core.types import ArrowStreamExportable

from lonboard.types.layer import GeohashLayerKwargs, TextAccessorInput

if sys.version_info >= (3, 11):
from typing import Self
else:
from typing_extensions import Self

if sys.version_info >= (3, 12):
from typing import Unpack
else:
from typing_extensions import Unpack


class GeohashLayer(PolygonLayer):
"""The `GeohashLayer` renders filled and/or stroked polygons based on the [Geohash](https://en.wikipedia.org/wiki/Geohash) geospatial indexing system.

!!! warning
This layer does not currently support auto-centering the map view based on the
extent of the input.
"""

def __init__(
self,
table: ArrowStreamExportable,
*,
get_geohash: TextAccessorInput,
_rows_per_chunk: int | None = None,
**kwargs: Unpack[GeohashLayerKwargs],
) -> None:
"""Create a new GeohashLayer.

Args:
table: An Arrow table with properties to associate with the geohashes.

Keyword Args:
get_geohash: The identifier of each geohash.
kwargs: Extra args passed down as GeohashLayer attributes.

"""
super().__init__(
table=table,
get_geohash=get_geohash,
_rows_per_chunk=_rows_per_chunk,
**kwargs,
)

@classmethod
def from_pandas(
cls,
df: pd.DataFrame,
*,
get_geohash: TextAccessorInput,
auto_downcast: bool = True,
**kwargs: Unpack[GeohashLayerKwargs],
) -> Self:
"""Create a new GeohashLayer from a pandas DataFrame.

Args:
df: a Pandas DataFrame with properties to associate with geohashes.

Keyword Args:
get_geohash: geohash identifiers.
auto_downcast: Whether to save memory on input by casting to smaller types. Defaults to True.
kwargs: Extra args passed down as GeohashLayer attributes.

"""
try:
import pyarrow as pa
except ImportError as e:
raise ImportError(
"pyarrow required for converting GeoPandas to arrow.\n"
"Run `pip install pyarrow`.",
) from e

if auto_downcast:
# Note: we don't deep copy because we don't need to clone geometries
df = _auto_downcast(df.copy()) # type: ignore

table = pa.Table.from_pandas(df)
return cls(table, get_geohash=get_geohash, **kwargs)

_layer_type = t.Unicode("geohash").tag(sync=True)

table = ArrowTableTrait(geometry_required=False)
"""An Arrow table with properties to associate with the geohashes.

If you have a Pandas `DataFrame`, use
[`from_pandas`][lonboard.GeohashLayer.from_pandas] instead.
"""

get_geohash = TextAccessor()
"""The cell identifier of each geohash.

Accepts either an array of strings or uint64 integers representing geohash IDs.

- Type: [TextAccessor][lonboard.traits.TextAccessor]
"""
115 changes: 115 additions & 0 deletions lonboard/layer/_s2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
from __future__ import annotations

from typing import TYPE_CHECKING

import traitlets as t

from lonboard._utils import auto_downcast as _auto_downcast

# Important to import from ._polygon to avoid circular imports
from lonboard.layer._polygon import PolygonLayer
from lonboard.traits import ArrowTableTrait, TextAccessor

if TYPE_CHECKING:
import sys

import pandas as pd
from arro3.core.types import ArrowStreamExportable

from lonboard.types.layer import S2LayerKwargs, TextAccessorInput

if sys.version_info >= (3, 11):
from typing import Self
else:
from typing_extensions import Self

if sys.version_info >= (3, 12):
from typing import Unpack
else:
from typing_extensions import Unpack


class S2Layer(PolygonLayer):
"""The `S2Layer` renders filled and/or stroked polygons based on the [S2](http://s2geometry.io/) geospatial indexing system.

!!! warning
This layer does not currently support auto-centering the map view based on the
extent of the input.
"""

def __init__(
self,
table: ArrowStreamExportable,
*,
get_s2_token: TextAccessorInput,
_rows_per_chunk: int | None = None,
**kwargs: Unpack[S2LayerKwargs],
) -> None:
"""Create a new S2Layer.

Args:
table: An Arrow table with properties to associate with the S2 cells.

Keyword Args:
get_s2_token: The identifier of each S2 cell.
kwargs: Extra args passed down as S2Layer attributes.

"""
super().__init__(
table=table,
get_s2_token=get_s2_token,
_rows_per_chunk=_rows_per_chunk,
**kwargs,
)

@classmethod
def from_pandas(
cls,
df: pd.DataFrame,
*,
get_s2_token: TextAccessorInput,
auto_downcast: bool = True,
**kwargs: Unpack[S2LayerKwargs],
) -> Self:
"""Create a new S2Layer from a pandas DataFrame.

Args:
df: a Pandas DataFrame with properties to associate with S2 cells.

Keyword Args:
get_s2_token: S2 cell identifier of each S2 hexagon.
auto_downcast: Whether to save memory on input by casting to smaller types. Defaults to True.
kwargs: Extra args passed down as S2Layer attributes.

"""
try:
import pyarrow as pa
except ImportError as e:
raise ImportError(
"pyarrow required for converting GeoPandas to arrow.\n"
"Run `pip install pyarrow`.",
) from e

if auto_downcast:
# Note: we don't deep copy because we don't need to clone geometries
df = _auto_downcast(df.copy()) # type: ignore

table = pa.Table.from_pandas(df)
return cls(table, get_s2_token=get_s2_token, **kwargs)

_layer_type = t.Unicode("s2").tag(sync=True)

table = ArrowTableTrait(geometry_required=False)
"""An Arrow table with properties to associate with the S2 cells.

If you have a Pandas `DataFrame`, use
[`from_pandas`][lonboard.S2Layer.from_pandas] instead.
"""

get_s2_token = TextAccessor()
"""The cell identifier of each S2 cell.

Accepts either an array of strings or uint64 integers representing S2 cell IDs.

- Type: [TextAccessor][lonboard.traits.TextAccessor]
"""
8 changes: 8 additions & 0 deletions lonboard/types/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,14 @@ class A5LayerKwargs(PolygonLayerKwargs, total=False):
pass


class S2LayerKwargs(PolygonLayerKwargs, total=False):
pass


class GeohashLayerKwargs(PolygonLayerKwargs, total=False):
pass


class ScatterplotLayerKwargs(BaseLayerKwargs, total=False):
radius_units: Units
radius_scale: IntFloat
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"@deck.gl/mapbox": "^9.2.2",
"@deck.gl/mesh-layers": "^9.2.2",
"@deck.gl/react": "^9.2.2",
"@geoarrow/deck.gl-layers": "^0.4.0-beta.5",
"@geoarrow/deck.gl-layers": "^0.4.0-beta.6",
"@geoarrow/geoarrow-js": "^0.3.2",
"@nextui-org/react": "^2.4.8",
"@xstate/react": "^6.0.0",
Expand Down
10 changes: 10 additions & 0 deletions src/model/layer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import { PathModel } from "./path.js";
import { PointCloudModel } from "./point-cloud.js";
import {
A5Model,
GeohashModel,
H3HexagonModel,
PolygonModel,
S2Model,
SolidPolygonModel,
} from "./polygon.js";
import { ScatterplotModel } from "./scatterplot.js";
Expand Down Expand Up @@ -62,6 +64,10 @@ export async function initializeLayer(
layerModel = new ColumnModel(model, updateStateCallback);
break;

case GeohashModel.layerType:
layerModel = new GeohashModel(model, updateStateCallback);
break;

case H3HexagonModel.layerType:
layerModel = new H3HexagonModel(model, updateStateCallback);
break;
Expand All @@ -82,6 +88,10 @@ export async function initializeLayer(
layerModel = new PolygonModel(model, updateStateCallback);
break;

case S2Model.layerType:
layerModel = new S2Model(model, updateStateCallback);
break;

case ScatterplotModel.layerType:
layerModel = new ScatterplotModel(model, updateStateCallback);
break;
Expand Down
Loading