|
8 | 8 |
|
9 | 9 | from lonboard._geoarrow.ops import Bbox, WeightedCentroid |
10 | 10 | from lonboard._utils import auto_downcast as _auto_downcast |
11 | | -from lonboard.layer._base import BaseArrowLayer |
12 | | -from lonboard.traits import ArrowTableTrait, ColorAccessor, FloatAccessor, H3Accessor |
| 11 | +from lonboard.layer._polygon import PolygonLayer |
| 12 | +from lonboard.traits import ArrowTableTrait, H3Accessor |
13 | 13 |
|
14 | 14 | if TYPE_CHECKING: |
15 | 15 | import sys |
@@ -82,37 +82,38 @@ def default_h3_viewport(ca: ChunkedArray) -> tuple[Bbox, WeightedCentroid] | Non |
82 | 82 | ) |
83 | 83 |
|
84 | 84 |
|
85 | | -class H3HexagonLayer(BaseArrowLayer): |
86 | | - """The `H3HexagonLayer` renders H3 hexagons. |
| 85 | +class H3HexagonLayer(PolygonLayer): |
| 86 | + """The `H3HexagonLayer` renders hexagons from the [H3](https://h3geo.org/) geospatial indexing system. |
87 | 87 |
|
88 | 88 | **Example:** |
89 | 89 |
|
90 | | - From GeoPandas: |
| 90 | + From Pandas: |
91 | 91 |
|
92 | 92 | ```py |
93 | | - import geopandas as gpd |
| 93 | + import pandas as pd |
94 | 94 | from lonboard import Map, H3HexagonLayer |
95 | 95 |
|
96 | | - # A GeoDataFrame with Polygon or MultiPolygon geometries |
97 | | - gdf = gpd.GeoDataFrame() |
98 | | - layer = H3HexagonLayer.from_geopandas( |
99 | | - gdf, |
100 | | - get_fill_color=[255, 0, 0], |
| 96 | + # A DataFrame with H3 cell identifiers |
| 97 | + df = pd.DataFrame({ |
| 98 | + "h3_index": ["8928308280fffff", "8928308280bffff", ...], |
| 99 | + "other_attributes": [...], |
| 100 | + }) |
| 101 | + layer = H3HexagonLayer.from_pandas( |
| 102 | + df, |
| 103 | + get_hexagon=df["h3_index"], |
101 | 104 | ) |
102 | 105 | m = Map(layer) |
103 | 106 | ``` |
104 | 107 |
|
105 | | - From an Arrow-compatible source like [pyogrio][pyogrio] or [geoarrow-rust](https://geoarrow.github.io/geoarrow-rs/python/latest): |
| 108 | + Or, you can pass in an Arrow table directly |
106 | 109 |
|
107 | 110 | ```py |
108 | | - from geoarrow.rust.io import read_flatgeobuf |
109 | 111 | from lonboard import Map, H3HexagonLayer |
110 | 112 |
|
111 | | - # Example: A FlatGeobuf file with Polygon or MultiPolygon geometries |
112 | | - table = read_flatgeobuf("path/to/file.fgb") |
| 113 | + # Example: An Arrow table with H3 identifiers as a column |
113 | 114 | layer = H3HexagonLayer( |
114 | 115 | table, |
115 | | - get_fill_color=[255, 0, 0], |
| 116 | + get_hexagon=table["h3_index"], |
116 | 117 | ) |
117 | 118 | m = Map(layer) |
118 | 119 | ``` |
@@ -162,11 +163,11 @@ def from_pandas( |
162 | 163 | """Create a new H3HexagonLayer from a pandas DataFrame. |
163 | 164 |
|
164 | 165 | Args: |
165 | | - df: _description_ |
| 166 | + df: a Pandas DataFrame with properties to associate with H3 hexagons. |
166 | 167 |
|
167 | 168 | Keyword Args: |
168 | | - get_hexagon: _description_ |
169 | | - auto_downcast: _description_. Defaults to True. |
| 169 | + get_hexagon: H3 cell identifier of each H3 hexagon. |
| 170 | + auto_downcast: Whether to save memory on input by casting to smaller types. Defaults to True. |
170 | 171 | kwargs: Extra args passed down as H3HexagonLayer attributes. |
171 | 172 |
|
172 | 173 | Raises: |
@@ -194,173 +195,46 @@ def from_pandas( |
194 | 195 | _layer_type = t.Unicode("h3-hexagon").tag(sync=True) |
195 | 196 |
|
196 | 197 | table = ArrowTableTrait(geometry_required=False) |
| 198 | + """An Arrow table with properties to associate with the H3 hexagons. |
197 | 199 |
|
198 | | - get_hexagon = H3Accessor() |
199 | | - """ |
200 | | - todo |
201 | | - """ |
202 | | - |
203 | | - high_precision = t.Bool(None, allow_none=True).tag(sync=True) |
204 | | - |
205 | | - stroked = t.Bool(None, allow_none=True).tag(sync=True) |
206 | | - """Whether to draw an outline around the polygon (solid fill). |
207 | | -
|
208 | | - Note that both the outer polygon as well the outlines of any holes will be drawn. |
209 | | -
|
210 | | - - Type: `bool`, optional |
211 | | - - Default: `True` |
212 | | - """ |
213 | | - |
214 | | - filled = t.Bool(None, allow_none=True).tag(sync=True) |
215 | | - """Whether to draw a filled polygon (solid fill). |
216 | | -
|
217 | | - Note that only the area between the outer polygon and any holes will be filled. |
218 | | -
|
219 | | - - Type: `bool`, optional |
220 | | - - Default: `True` |
| 200 | + If you have a Pandas `DataFrame`, use |
| 201 | + [`from_pandas`][lonboard.H3HexagonLayer.from_pandas] instead. |
221 | 202 | """ |
222 | 203 |
|
223 | | - extruded = t.Bool(None, allow_none=True).tag(sync=True) |
224 | | - """Whether to extrude the polygons. |
225 | | -
|
226 | | - Based on the elevations provided by the `getElevation` accessor. |
227 | | -
|
228 | | - If set to `false`, all polygons will be flat, this generates less geometry and is |
229 | | - faster than simply returning 0 from getElevation. |
230 | | -
|
231 | | - - Type: `bool`, optional |
232 | | - - Default: `False` |
233 | | - """ |
234 | | - |
235 | | - wireframe = t.Bool(None, allow_none=True).tag(sync=True) |
236 | | - """ |
237 | | - Whether to generate a line wireframe of the polygon. The outline will have |
238 | | - "horizontal" lines closing the top and bottom polygons and a vertical line |
239 | | - (a "strut") for each vertex on the polygon. |
240 | | -
|
241 | | - - Type: `bool`, optional |
242 | | - - Default: `False` |
243 | | -
|
244 | | - **Remarks:** |
245 | | -
|
246 | | - - These lines are rendered with `GL.LINE` and will thus always be 1 pixel wide. |
247 | | - - Wireframe and solid extrusions are exclusive, you'll need to create two layers |
248 | | - with the same data if you want a combined rendering effect. |
249 | | - """ |
250 | | - |
251 | | - elevation_scale = t.Float(None, allow_none=True, min=0).tag(sync=True) |
252 | | - """Elevation multiplier. |
| 204 | + get_hexagon = H3Accessor() |
| 205 | + """The cell identifier of each H3 hexagon. |
253 | 206 |
|
254 | | - The final elevation is calculated by `elevationScale * getElevation(d)`. |
255 | | - `elevationScale` is a handy property to scale all elevation without updating the |
256 | | - data. |
| 207 | + Accepts either an array of strings or uint64 integers representing H3 cell IDs. |
257 | 208 |
|
258 | | - - Type: `float`, optional |
259 | | - - Default: `1` |
| 209 | + - Type: [H3Accessor][lonboard.traits.H3Accessor] |
260 | 210 | """ |
261 | 211 |
|
262 | | - line_width_units = t.Unicode(None, allow_none=True).tag(sync=True) |
263 | | - """ |
264 | | - The units of the outline width, one of `'meters'`, `'common'`, and `'pixels'`. See |
265 | | - [unit |
266 | | - system](https://deck.gl/docs/developer-guide/coordinate-systems#supported-units). |
267 | | -
|
268 | | - - Type: `str`, optional |
269 | | - - Default: `'meters'` |
270 | | - """ |
| 212 | + high_precision = t.Bool(None, allow_none=True).tag(sync=True) |
| 213 | + """Whether to render H3 hexagons in high-precision mode. |
271 | 214 |
|
272 | | - line_width_scale = t.Float(None, allow_none=True, min=0).tag(sync=True) |
273 | | - """ |
274 | | - The outline width multiplier that multiplied to all outlines of `Polygon` and |
275 | | - `MultiPolygon` features if the `stroked` attribute is true. |
| 215 | + Each hexagon in the H3 indexing system is [slightly different in shape](https://h3geo.org/docs/core-library/coordsystems). To draw a large number of hexagons efficiently, the `H3HexagonLayer` may choose to use instanced drawing by assuming that all hexagons within the current viewport have the same shape as the one at the center of the current viewport. The discrepancy is usually too small to be visible. |
276 | 216 |
|
277 | | - - Type: `float`, optional |
278 | | - - Default: `1` |
279 | | - """ |
| 217 | + There are several cases in which high-precision mode is required. In these cases, `H3HexagonLayer` may choose to switch to high-precision mode, where it trades performance for accuracy: |
280 | 218 |
|
281 | | - line_width_min_pixels = t.Float(None, allow_none=True, min=0).tag(sync=True) |
282 | | - """ |
283 | | - The minimum outline width in pixels. This can be used to prevent the outline from |
284 | | - getting too small when zoomed out. |
| 219 | + * The input set contains a pentagon. There are 12 pentagons world wide at each resolution, and these cells and their immediate neighbors have significant differences in shape. |
| 220 | + * The input set is at a coarse resolution (res `0` through res `5`). These cells have larger differences in shape, particularly when using a Mercator projection. |
| 221 | + * The input set contains hexagons with different resolutions. |
285 | 222 |
|
286 | | - - Type: `float`, optional |
287 | | - - Default: `0` |
288 | | - """ |
| 223 | + Possible values: |
289 | 224 |
|
290 | | - line_width_max_pixels = t.Float(None, allow_none=True, min=0).tag(sync=True) |
291 | | - """ |
292 | | - The maximum outline width in pixels. This can be used to prevent the outline from |
293 | | - getting too big when zoomed in. |
| 225 | + * `None`: The layer chooses the mode automatically. High-precision rendering is only used if an edge case is encountered in the data. |
| 226 | + * `True`: Always use high-precision rendering. |
| 227 | + * `False`: Always use instanced rendering, regardless of the characteristics of the data. |
294 | 228 |
|
295 | | - - Type: `float`, optional |
| 229 | + - Type: `bool | None`, optional |
296 | 230 | - Default: `None` |
297 | 231 | """ |
298 | 232 |
|
299 | | - line_joint_rounded = t.Bool(None, allow_none=True).tag(sync=True) |
300 | | - """Type of joint. If `true`, draw round joints. Otherwise draw miter joints. |
301 | | -
|
302 | | - - Type: `bool`, optional |
303 | | - - Default: `False` |
304 | | - """ |
| 233 | + coverage = t.Float(None, allow_none=True, min=0, max=1).tag(sync=True) |
| 234 | + """Hexagon radius multiplier, between 0 - 1. |
305 | 235 |
|
306 | | - line_miter_limit = t.Float(None, allow_none=True, min=0).tag(sync=True) |
307 | | - """The maximum extent of a joint in ratio to the stroke width. |
308 | | -
|
309 | | - Only works if `line_joint_rounded` is false. |
| 236 | + When coverage = 1, hexagon is rendered with actual size, by specifying a different value (between 0 and 1) hexagon can be scaled down. |
310 | 237 |
|
311 | 238 | - Type: `float`, optional |
312 | | - - Default: `4` |
313 | | - """ |
314 | | - |
315 | | - get_fill_color = ColorAccessor(None, allow_none=True) |
316 | | - """ |
317 | | - The fill color of each polygon in the format of `[r, g, b, [a]]`. Each channel is a |
318 | | - number between 0-255 and `a` is 255 if not supplied. |
319 | | -
|
320 | | - - Type: [ColorAccessor][lonboard.traits.ColorAccessor], optional |
321 | | - - If a single `list` or `tuple` is provided, it is used as the fill color for |
322 | | - all polygons. |
323 | | - - If a numpy or pyarrow array is provided, each value in the array will be used |
324 | | - as the fill color for the polygon at the same row index. |
325 | | - - Default: `[0, 0, 0, 255]`. |
326 | | - """ |
327 | | - |
328 | | - get_line_color = ColorAccessor(None, allow_none=True) |
329 | | - """ |
330 | | - The outline color of each polygon in the format of `[r, g, b, [a]]`. Each channel is |
331 | | - a number between 0-255 and `a` is 255 if not supplied. |
332 | | -
|
333 | | - Only applies if `stroked=True`. |
334 | | -
|
335 | | - - Type: [ColorAccessor][lonboard.traits.ColorAccessor], optional |
336 | | - - If a single `list` or `tuple` is provided, it is used as the outline color for |
337 | | - all polygons. |
338 | | - - If a numpy or pyarrow array is provided, each value in the array will be used |
339 | | - as the outline color for the polygon at the same row index. |
340 | | - - Default: `[0, 0, 0, 255]`. |
341 | | - """ |
342 | | - |
343 | | - get_line_width = FloatAccessor(None, allow_none=True) |
344 | | - """ |
345 | | - The width of the outline of each polygon, in units specified by `line_width_units` |
346 | | - (default `'meters'`). |
347 | | -
|
348 | | - - Type: [FloatAccessor][lonboard.traits.FloatAccessor], optional |
349 | | - - If a number is provided, it is used as the outline width for all polygons. |
350 | | - - If an array is provided, each value in the array will be used as the outline |
351 | | - width for the polygon at the same row index. |
352 | | - - Default: `1`. |
353 | | - """ |
354 | | - |
355 | | - get_elevation = FloatAccessor(None, allow_none=True) |
356 | | - """ |
357 | | - The elevation to extrude each polygon with, in meters. |
358 | | -
|
359 | | - Only applies if `extruded=True`. |
360 | | -
|
361 | | - - Type: [FloatAccessor][lonboard.traits.FloatAccessor], optional |
362 | | - - If a number is provided, it is used as the width for all polygons. |
363 | | - - If an array is provided, each value in the array will be used as the width for |
364 | | - the polygon at the same row index. |
365 | | - - Default: `1000`. |
| 239 | + - Default: `1` |
366 | 240 | """ |
0 commit comments