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
2 changes: 2 additions & 0 deletions docs/api/traits.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# lonboard.traits

::: lonboard.traits.PyarrowTableTrait

::: lonboard.traits.ColorAccessor

::: lonboard.traits.FloatAccessor
116 changes: 111 additions & 5 deletions lonboard/_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,25 +411,51 @@ class ScatterplotLayer(BaseArrowLayer):

**Example:**

From GeoPandas:

```py
import geopandas as gpd
from lonboard import Map, ScatterplotLayer

# A GeoDataFrame with Point geometries
# A GeoDataFrame with Point or MultiPoint geometries
gdf = gpd.GeoDataFrame()
layer = ScatterplotLayer.from_geopandas(
gdf,
get_fill_color=[255, 0, 0],
)
m = Map(layers=[layer])
```

From [geoarrow-rust](https://geoarrow.github.io/geoarrow-rs/python/latest):

```py
from geoarrow.rust.core import read_parquet
from lonboard import Map, ScatterplotLayer

# Example: A GeoParquet file with Point or MultiPoint geometries
table = read_parquet("path/to/file.parquet")
layer = ScatterplotLayer(
table=table,
get_fill_color=[255, 0, 0],
)
m = Map(layers=[layer])
```
"""

_layer_type = traitlets.Unicode("scatterplot").tag(sync=True)

table = PyarrowTableTrait(
allowed_geometry_types={EXTENSION_NAME.POINT, EXTENSION_NAME.MULTIPOINT}
)
"""A GeoArrow table with a Point or MultiPoint column.

This is the fastest way to plot data from an existing GeoArrow source, such as
[geoarrow-rust](https://geoarrow.github.io/geoarrow-rs/python/latest) or
[geoarrow-pyarrow](https://geoarrow.github.io/geoarrow-python/main/index.html).

If you have a GeoPandas `GeoDataFrame`, use
[`from_geopandas`][lonboard.ScatterplotLayer.from_geopandas] instead.
"""

radius_units = traitlets.Unicode("meters", allow_none=True).tag(sync=True)
"""
Expand Down Expand Up @@ -605,11 +631,13 @@ class PathLayer(BaseArrowLayer):

**Example:**

From GeoPandas:

```py
import geopandas as gpd
from lonboard import Map, PathLayer

# A GeoDataFrame with LineString geometries
# A GeoDataFrame with LineString or MultiLineString geometries
gdf = gpd.GeoDataFrame()
layer = PathLayer.from_geopandas(
gdf,
Expand All @@ -618,6 +646,22 @@ class PathLayer(BaseArrowLayer):
)
m = Map(layers=[layer])
```

From [geoarrow-rust](https://geoarrow.github.io/geoarrow-rs/python/latest):

```py
from geoarrow.rust.core import read_parquet
from lonboard import Map, PathLayer

# Example: A GeoParquet file with LineString or MultiLineString geometries
table = read_parquet("path/to/file.parquet")
layer = PathLayer(
table=table,
get_color=[255, 0, 0],
width_min_pixels=2,
)
m = Map(layers=[layer])
```
"""

_layer_type = traitlets.Unicode("path").tag(sync=True)
Expand All @@ -628,6 +672,15 @@ class PathLayer(BaseArrowLayer):
EXTENSION_NAME.MULTILINESTRING,
}
)
"""A GeoArrow table with a LineString or MultiLineString column.

This is the fastest way to plot data from an existing GeoArrow source, such as
[geoarrow-rust](https://geoarrow.github.io/geoarrow-rs/python/latest) or
[geoarrow-pyarrow](https://geoarrow.github.io/geoarrow-python/main/index.html).

If you have a GeoPandas `GeoDataFrame`, use
[`from_geopandas`][lonboard.PathLayer.from_geopandas] instead.
"""

width_units = traitlets.Unicode(allow_none=True).tag(sync=True)
"""
Expand Down Expand Up @@ -738,25 +791,51 @@ class SolidPolygonLayer(BaseArrowLayer):

**Example:**

From GeoPandas:

```py
import geopandas as gpd
from lonboard import Map, SolidPolygonLayer

# A GeoDataFrame with Polygon geometries
# A GeoDataFrame with Polygon or MultiPolygon geometries
gdf = gpd.GeoDataFrame()
layer = SolidPolygonLayer.from_geopandas(
gdf,
get_fill_color=[255, 0, 0],
)
m = Map(layers=[layer])
```

From [geoarrow-rust](https://geoarrow.github.io/geoarrow-rs/python/latest):

```py
from geoarrow.rust.core import read_parquet
from lonboard import Map, SolidPolygonLayer

# Example: A GeoParquet file with Polygon or MultiPolygon geometries
table = read_parquet("path/to/file.parquet")
layer = SolidPolygonLayer(
table=table,
get_fill_color=[255, 0, 0],
)
m = Map(layers=[layer])
```
"""

_layer_type = traitlets.Unicode("solid-polygon").tag(sync=True)

table = PyarrowTableTrait(
allowed_geometry_types={EXTENSION_NAME.POLYGON, EXTENSION_NAME.MULTIPOLYGON}
)
"""A GeoArrow table with a Polygon or MultiPolygon column.

This is the fastest way to plot data from an existing GeoArrow source, such as
[geoarrow-rust](https://geoarrow.github.io/geoarrow-rs/python/latest) or
[geoarrow-pyarrow](https://geoarrow.github.io/geoarrow-python/main/index.html).

If you have a GeoPandas `GeoDataFrame`, use
[`from_geopandas`][lonboard.SolidPolygonLayer.from_geopandas] instead.
"""

filled = traitlets.Bool(allow_none=True).tag(sync=True)
"""
Expand Down Expand Up @@ -857,17 +936,35 @@ def _validate_accessor_length(self, proposal):
class HeatmapLayer(BaseArrowLayer):
"""The `HeatmapLayer` visualizes the spatial distribution of data.

**Example:**
**Example**

From GeoPandas:

```py
import geopandas as gpd
from lonboard import Map, HeatmapLayer

# A GeoDataFrame with Point geometries
gdf = gpd.GeoDataFrame()
layer = HeatmapLayer.from_geopandas(gdf,)
layer = HeatmapLayer.from_geopandas(gdf)
m = Map(layers=[layer])
```

From [geoarrow-rust](https://geoarrow.github.io/geoarrow-rs/python/latest):

```py
from geoarrow.rust.core import read_parquet
from lonboard import Map, HeatmapLayer

# Example: A GeoParquet file with Point geometries
table = read_parquet("path/to/file.parquet")
layer = HeatmapLayer(
table=table,
get_fill_color=[255, 0, 0],
)
m = Map(layers=[layer])
```

"""

_layer_type = traitlets.Unicode("heatmap").tag(sync=True)
Expand All @@ -880,6 +977,15 @@ def _default_rows_per_chunk(self):
return len(self.table)

table = PyarrowTableTrait(allowed_geometry_types={EXTENSION_NAME.POINT})
"""A GeoArrow table with a Point column.

This is the fastest way to plot data from an existing GeoArrow source, such as
[geoarrow-rust](https://geoarrow.github.io/geoarrow-rs/python/latest) or
[geoarrow-pyarrow](https://geoarrow.github.io/geoarrow-python/main/index.html).

If you have a GeoPandas `GeoDataFrame`, use
[`from_geopandas`][lonboard.HeatmapLayer.from_geopandas] instead.
"""

radius_pixels = traitlets.Float(allow_none=True).tag(sync=True)
"""Radius of the circle in pixels, to which the weight of an object is distributed.
Expand Down
10 changes: 10 additions & 0 deletions lonboard/_viewport.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ def bbox_to_zoom_level(bbox: Bbox) -> int:
def compute_view(tables: List[pa.Table]):
"""Automatically computes a view state for the data passed in."""
bbox, center = get_bbox_center(tables)

if center.x is not None and (center.x < 180 or center.x > 180):
msg = "Longitude of data's center is outside of WGS84 bounds.\n"
msg += "Is data in WGS84 projection?"
raise ValueError(msg)
if center.y is not None and (center.y < 90 or center.y > 90):
msg = "Latitude of data's center is outside of WGS84 bounds.\n"
msg += "Is data in WGS84 projection?"
raise ValueError(msg)

# When no geo column is found, bbox will have inf values
try:
zoom = bbox_to_zoom_level(bbox)
Expand Down
11 changes: 11 additions & 0 deletions lonboard/_viz.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,17 @@ class GeoInterfaceProtocol(Protocol):
def __geo_interface__(self) -> dict:
...

class ArrowStreamExportable(Protocol):
def __arrow_c_stream__(self, requested_schema: object | None = None) -> object:
...

VizDataInput = Union[
gpd.GeoDataFrame,
gpd.GeoSeries,
pa.Table,
NDArray[np.object_],
shapely.geometry.base.BaseGeometry,
ArrowStreamExportable,
GeoInterfaceProtocol,
Dict[str, Any],
]
Expand Down Expand Up @@ -121,6 +126,11 @@ def create_layer_from_data_input(
if isinstance(data, shapely.geometry.base.BaseGeometry):
return _viz_shapely_scalar(data, **kwargs)

# Anything with __arrow_c_stream__
if hasattr(data, "__arrow_c_stream__"):
data = cast(ArrowStreamExportable, data)
return _viz_geoarrow_table(pa.table(data.__arrow_c_stream__()), **kwargs)

# Anything with __geo_interface__
if hasattr(data, "__geo_interface__"):
data = cast(GeoInterfaceProtocol, data)
Expand Down Expand Up @@ -236,6 +246,7 @@ def _viz_geo_interface(
def _viz_geoarrow_table(
table: pa.Table, **kwargs
) -> Union[ScatterplotLayer, PathLayer, SolidPolygonLayer]:
# TODO: don't hard-code "geometry"
geometry_ext_type = table.schema.field("geometry").metadata.get(
b"ARROW:extension:name"
)
Expand Down
18 changes: 18 additions & 0 deletions lonboard/experimental/_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ class ArcLayer(BaseLayer):
_layer_type = traitlets.Unicode("arc").tag(sync=True)

table = PyarrowTableTrait()
"""A GeoArrow table.

This is the fastest way to plot data from an existing GeoArrow source, such as
[geoarrow-rust](https://geoarrow.github.io/geoarrow-rs/python/latest) or
[geoarrow-pyarrow](https://geoarrow.github.io/geoarrow-python/main/index.html).

If you have a GeoPandas `GeoDataFrame`, use
[`from_geopandas`][lonboard.ScatterplotLayer.from_geopandas] instead.
"""

great_circle = traitlets.Bool(allow_none=True).tag(sync=True)
"""If `True`, create the arc along the shortest path on the earth surface.
Expand Down Expand Up @@ -132,6 +141,15 @@ class TextLayer(BaseLayer):
_layer_type = traitlets.Unicode("text").tag(sync=True)

table = PyarrowTableTrait(allowed_geometry_types={EXTENSION_NAME.POINT})
"""A GeoArrow table with a Point or MultiPoint column.

This is the fastest way to plot data from an existing GeoArrow source, such as
[geoarrow-rust](https://geoarrow.github.io/geoarrow-rs/python/latest) or
[geoarrow-pyarrow](https://geoarrow.github.io/geoarrow-python/main/index.html).

If you have a GeoPandas `GeoDataFrame`, use
[`from_geopandas`][lonboard.ScatterplotLayer.from_geopandas] instead.
"""

billboard = traitlets.Bool().tag(sync=True)
"""If `true`, the text always faces camera. Otherwise the text faces up (z).
Expand Down
Loading