Skip to content

PolygonLayer #330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Mar 28, 2024
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: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ gdf = gpd.GeoDataFrame(...)
viz(gdf)
```

Under the hood, this delegates to a [`ScatterplotLayer`](https://developmentseed.org/lonboard/latest/api/layers/scatterplot-layer/), [`PathLayer`](https://developmentseed.org/lonboard/latest/api/layers/path-layer/), or [`SolidPolygonLayer`](https://developmentseed.org/lonboard/latest/api/layers/solid-polygon-layer/). Refer to the [documentation](https://developmentseed.org/lonboard/) and [examples](https://developmentseed.org/lonboard/latest/examples/internet-speeds/) for more control over rendering.
Under the hood, this delegates to a [`ScatterplotLayer`](https://developmentseed.org/lonboard/latest/api/layers/scatterplot-layer/), [`PathLayer`](https://developmentseed.org/lonboard/latest/api/layers/path-layer/), or [`PolygonLayer`](https://developmentseed.org/lonboard/latest/api/layers/polygon-layer/). Refer to the [documentation](https://developmentseed.org/lonboard/) and [examples](https://developmentseed.org/lonboard/latest/examples/internet-speeds/) for more control over rendering.

## Documentation

Expand Down
5 changes: 5 additions & 0 deletions docs/api/layers/polygon-layer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# PolygonLayer

::: lonboard.PolygonLayer
options:
inherited_members: true
1 change: 1 addition & 0 deletions lonboard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
HeatmapLayer,
PathLayer,
PointCloudLayer,
PolygonLayer,
ScatterplotLayer,
SolidPolygonLayer,
)
Expand Down
263 changes: 257 additions & 6 deletions lonboard/_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
HeatmapLayerKwargs,
PathLayerKwargs,
PointCloudLayerKwargs,
PolygonLayerKwargs,
ScatterplotLayerKwargs,
SolidPolygonLayerKwargs,
)
Expand Down Expand Up @@ -606,6 +607,249 @@ def __init__(self, **kwargs: BitmapTileLayerKwargs):
"""


class PolygonLayer(BaseArrowLayer):
"""The `PolygonLayer` renders filled, stroked and/or extruded polygons.

!!! note

This layer is essentially a combination of a [`PathLayer`][lonboard.PathLayer]
and a [`SolidPolygonLayer`][lonboard.SolidPolygonLayer]. This has some overhead
beyond a `SolidPolygonLayer`, so if you're looking for the maximum performance
with large data, you may want to use a `SolidPolygonLayer` directly.

**Example:**

From GeoPandas:

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

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

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

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

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

def __init__(
self,
*,
table: pa.Table,
_rows_per_chunk: Optional[int] = None,
**kwargs: Unpack[PolygonLayerKwargs],
):
super().__init__(table=table, _rows_per_chunk=_rows_per_chunk, **kwargs)

@classmethod
def from_geopandas(
cls,
gdf: gpd.GeoDataFrame,
*,
auto_downcast: bool = True,
**kwargs: Unpack[PolygonLayerKwargs],
) -> Self:
return super().from_geopandas(gdf=gdf, auto_downcast=auto_downcast, **kwargs)

_layer_type = traitlets.Unicode("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.PolygonLayer.from_geopandas] instead.
"""

stroked = traitlets.Bool(None, allow_none=True).tag(sync=True)
"""Whether to draw an outline around the polygon (solid fill).

Note that both the outer polygon as well the outlines of any holes will be drawn.

- Type: `bool`, optional
- Default: `True`
"""

filled = traitlets.Bool(None, allow_none=True).tag(sync=True)
"""Whether to draw a filled polygon (solid fill).

Note that only the area between the outer polygon and any holes will be filled.

- Type: `bool`, optional
- Default: `True`
"""

extruded = traitlets.Bool(None, allow_none=True).tag(sync=True)
"""Whether to extrude the polygons.

Based on the elevations provided by the `getElevation` accessor.

If set to `false`, all polygons will be flat, this generates less geometry and is
faster than simply returning 0 from getElevation.

- Type: `bool`, optional
- Default: `False`
"""

wireframe = traitlets.Bool(None, allow_none=True).tag(sync=True)
"""
Whether to generate a line wireframe of the polygon. The outline will have
"horizontal" lines closing the top and bottom polygons and a vertical line
(a "strut") for each vertex on the polygon.

- Type: `bool`, optional
- Default: `False`

**Remarks:**

- These lines are rendered with `GL.LINE` and will thus always be 1 pixel wide.
- Wireframe and solid extrusions are exclusive, you'll need to create two layers
with the same data if you want a combined rendering effect.
"""

elevation_scale = traitlets.Float(None, allow_none=True, min=0).tag(sync=True)
"""Elevation multiplier.

The final elevation is calculated by `elevationScale * getElevation(d)`.
`elevationScale` is a handy property to scale all elevation without updating the
data.

- Type: `float`, optional
- Default: `1`
"""

line_width_units = traitlets.Unicode(None, allow_none=True).tag(sync=True)
"""
The units of the line width, one of `'meters'`, `'common'`, and `'pixels'`. See
[unit
system](https://deck.gl/docs/developer-guide/coordinate-systems#supported-units).

- Type: `str`, optional
- Default: `'meters'`
"""

line_width_scale = traitlets.Float(None, allow_none=True, min=0).tag(sync=True)
"""
The line width multiplier that multiplied to all outlines of `Polygon` and
`MultiPolygon` features if the `stroked` attribute is true.

- Type: `float`, optional
- Default: `1`
"""

line_width_min_pixels = traitlets.Float(None, allow_none=True, min=0).tag(sync=True)
"""
The minimum line width in pixels. This can be used to prevent the line from getting
too small when zoomed out.

- Type: `float`, optional
- Default: `0`
"""

line_width_max_pixels = traitlets.Float(None, allow_none=True, min=0).tag(sync=True)
"""
The maximum line width in pixels. This can be used to prevent the line from getting
too big when zoomed in.

- Type: `float`, optional
- Default: `None`
"""

line_joint_rounded = traitlets.Bool(None, allow_none=True).tag(sync=True)
"""Type of joint. If `true`, draw round joints. Otherwise draw miter joints.

- Type: `bool`, optional
- Default: `False`
"""

line_miter_limit = traitlets.Float(None, allow_none=True, min=0).tag(sync=True)
"""The maximum extent of a joint in ratio to the stroke width.

Only works if `line_joint_rounded` is false.

- Type: `float`, optional
- Default: `4`
"""

get_fill_color = ColorAccessor(None, allow_none=True)
"""
The fill color of each polygon in the format of `[r, g, b, [a]]`. Each channel is a
number between 0-255 and `a` is 255 if not supplied.

- Type: [ColorAccessor][lonboard.traits.ColorAccessor], optional
- If a single `list` or `tuple` is provided, it is used as the fill color for
all polygons.
- If a numpy or pyarrow array is provided, each value in the array will be used
as the fill color for the polygon at the same row index.
- Default: `[0, 0, 0, 255]`.
"""

get_line_color = ColorAccessor(None, allow_none=True)
"""
The line color of each polygon in the format of `[r, g, b, [a]]`. Each channel is a
number between 0-255 and `a` is 255 if not supplied.

Only applies if `extruded=True`.

- Type: [ColorAccessor][lonboard.traits.ColorAccessor], optional
- If a single `list` or `tuple` is provided, it is used as the line color for
all polygons.
- If a numpy or pyarrow array is provided, each value in the array will be used
as the line color for the polygon at the same row index.
- Default: `[0, 0, 0, 255]`.
"""

get_line_width = FloatAccessor(None, allow_none=True)
"""
The width of the outline of each polygon, in units specified by `line_width_units`
(default `'meters'`).

- Type: [FloatAccessor][lonboard.traits.FloatAccessor], optional
- If a number is provided, it is used as the outline width for all polygons.
- If an array is provided, each value in the array will be used as the outline
width for the polygon at the same row index.
- Default: `1`.
"""

get_elevation = FloatAccessor(None, allow_none=True)
"""
The elevation to extrude each polygon with, in meters.

Only applies if `extruded=True`.

- Type: [FloatAccessor][lonboard.traits.FloatAccessor], optional
- If a number is provided, it is used as the width for all polygons.
- If an array is provided, each value in the array will be used as the width for
the polygon at the same row index.
- Default: `1000`.
"""


class ScatterplotLayer(BaseArrowLayer):
"""The `ScatterplotLayer` renders circles at given coordinates.

Expand Down Expand Up @@ -1115,6 +1359,13 @@ class SolidPolygonLayer(BaseArrowLayer):
"""
The `SolidPolygonLayer` renders filled and/or extruded polygons.

!!! note

This layer is similar to the [`PolygonLayer`][lonboard.PolygonLayer] but will
not render an outline around polygons. In most cases, you'll want to use the
`PolygonLayer` directly, but for very large datasets not drawing the outline can
significantly improve performance, in which case you may want to use this layer.

**Example:**

From GeoPandas:
Expand Down Expand Up @@ -1210,6 +1461,12 @@ def from_geopandas(

- Type: `bool`, optional
- Default: `False`

**Remarks:**

- These lines are rendered with `GL.LINE` and will thus always be 1 pixel wide.
- Wireframe and solid extrusions are exclusive, you'll need to create two layers
with the same data if you want a combined rendering effect.
"""

elevation_scale = traitlets.Float(None, allow_none=True, min=0).tag(sync=True)
Expand All @@ -1220,12 +1477,6 @@ def from_geopandas(

- Type: `float`, optional
- Default: `1`

**Remarks:**

- These lines are rendered with `GL.LINE` and will thus always be 1 pixel wide.
- Wireframe and solid extrusions are exclusive, you'll need to create two layers
with the same data if you want a combined rendering effect.
"""

get_elevation = FloatAccessor(None, allow_none=True)
Expand Down
Loading