Skip to content

ArcLayer errors on Arrow input missing GeoArrow metadata #901

@AtelierLibre

Description

@AtelierLibre

Context

Thanks for the great library. I appreciate that the ArcLayer is clearly flagged as experimental but it is already very useful for visualising graphs of spatial data.

I've seen that there have been recent fixes to it but at the moment I can't get either the examples in the fixes, the main published example, or my own examples to work. I constantly run into KeyError: b'ARROW:extension:name'

I think this is a bug but it may be that I am not constructing my inputs properly (I have tried both Arrow and Numpy options). Might it be helpful to have a MWE with a clear example of what acceptable input to the ArcLayer looks like?

Resulting behaviour, error message or logs

The error that I get occurs at the moment of creating the ArcLayer and looks like this:

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[12], line 15
     11 target = np.array([(53.4808, 2.2426), (51.4545, 2.5879), (51.5072, 0.1276)])
     13 table = pa.table(data)
---> 15 lb.experimental.ArcLayer(
     16     table,
     17     get_source_position=source,
     18     get_target_position=target
     19 )

File [~/miniconda3/envs/sds/lib/python3.13/site-packages/lonboard/experimental/_layer.py:170](http://localhost:8888/home/nick/miniconda3/envs/sds/lib/python3.13/site-packages/lonboard/experimental/_layer.py#line=169), in ArcLayer.__init__(self, table, get_source_position, get_target_position, _rows_per_chunk, **kwargs)
    153 def __init__(
    154     self,
    155     table: ArrowStreamExportable,
   (...)    160     **kwargs: Unpack[ArcLayerKwargs],
    161 ) -> None:
    162     """Construct an ArcLayer from existing Arrow data.
    163 
    164     Keyword Args:
   (...)    168 
    169     """
--> 170     super().__init__(
    171         table=table,
    172         _rows_per_chunk=_rows_per_chunk,
    173         get_source_position=get_source_position,  # type: ignore
    174         get_target_position=get_target_position,  # type: ignore
    175         **kwargs,
    176     )

File [~/miniconda3/envs/sds/lib/python3.13/site-packages/lonboard/_layer.py:399](http://localhost:8888/home/nick/miniconda3/envs/sds/lib/python3.13/site-packages/lonboard/_layer.py#line=398), in BaseArrowLayer.__init__(self, table, _rows_per_chunk, **kwargs)
    395 self._rows_per_chunk = rows_per_chunk
    397 table_o3 = table_o3.rechunk(max_chunksize=rows_per_chunk)
--> 399 super().__init__(table=table_o3, **kwargs)

File [~/miniconda3/envs/sds/lib/python3.13/site-packages/lonboard/_layer.py:101](http://localhost:8888/home/nick/miniconda3/envs/sds/lib/python3.13/site-packages/lonboard/_layer.py#line=100), in BaseLayer.__init__(self, extensions, **kwargs)
     89 def __init__(
     90     self,
     91     *,
   (...)     96     # widgets where the layer is defined. We wish to allow extensions and their
     97     # properties to be passed in the layer constructor. _However_, if
     99     extension_kwargs = remove_extension_kwargs(extensions, kwargs)
--> 101     super().__init__(extensions=extensions, **kwargs)
    103     # Dynamically set layer traits from extensions after calling __init__
    104     self._add_extension_traits(extensions)

File [~/miniconda3/envs/sds/lib/python3.13/site-packages/lonboard/_base.py:25](http://localhost:8888/home/nick/miniconda3/envs/sds/lib/python3.13/site-packages/lonboard/_base.py#line=24), in BaseWidget.__init__(self, **kwargs)
     22     if provided_trait_name not in layer_trait_names:
     23         raise TypeError(msg.format(provided_trait_name=provided_trait_name))
---> 25 super().__init__(**kwargs)

File [~/miniconda3/envs/sds/lib/python3.13/site-packages/ipywidgets/widgets/widget.py:503](http://localhost:8888/home/nick/miniconda3/envs/sds/lib/python3.13/site-packages/ipywidgets/widgets/widget.py#line=502), in Widget.__init__(self, **kwargs)
    501 """Public constructor"""
    502 self._model_id = kwargs.pop('model_id', None)
--> 503 super().__init__(**kwargs)
    505 Widget._call_widget_constructed(self)
    506 self.open()

File [~/miniconda3/envs/sds/lib/python3.13/site-packages/traitlets/traitlets.py:1355](http://localhost:8888/home/nick/miniconda3/envs/sds/lib/python3.13/site-packages/traitlets/traitlets.py#line=1354), in HasTraits.__init__(self, *args, **kwargs)
   1353 for key, value in kwargs.items():
   1354     if self.has_trait(key):
-> 1355         setattr(self, key, value)
   1356         changes[key] = Bunch(
   1357             name=key,
   1358             old=None,
   (...)   1361             type="change",
   1362         )
   1363     else:
   1364         # passthrough args that don't set traits to super

File [~/miniconda3/envs/sds/lib/python3.13/site-packages/traitlets/traitlets.py:716](http://localhost:8888/home/nick/miniconda3/envs/sds/lib/python3.13/site-packages/traitlets/traitlets.py#line=715), in TraitType.__set__(self, obj, value)
    714 if self.read_only:
    715     raise TraitError('The "%s" trait is read-only.' % self.name)
--> 716 self.set(obj, value)

File [~/miniconda3/envs/sds/lib/python3.13/site-packages/traitlets/traitlets.py:690](http://localhost:8888/home/nick/miniconda3/envs/sds/lib/python3.13/site-packages/traitlets/traitlets.py#line=689), in TraitType.set(self, obj, value)
    689 def set(self, obj: HasTraits, value: S) -> None:
--> 690     new_value = self._validate(obj, value)
    691     assert self.name is not None
    692     try:

File [~/miniconda3/envs/sds/lib/python3.13/site-packages/traitlets/traitlets.py:722](http://localhost:8888/home/nick/miniconda3/envs/sds/lib/python3.13/site-packages/traitlets/traitlets.py#line=721), in TraitType._validate(self, obj, value)
    720     return value
    721 if hasattr(self, "validate"):
--> 722     value = self.validate(obj, value)
    723 if obj._cross_validation_lock is False:
    724     value = self._cross_validate(obj, value)

File [~/miniconda3/envs/sds/lib/python3.13/site-packages/lonboard/traits.py:588](http://localhost:8888/home/nick/miniconda3/envs/sds/lib/python3.13/site-packages/lonboard/traits.py#line=587), in PointAccessor.validate(self, obj, value)
    585     self.error(obj, value)
    587 assert isinstance(value, ChunkedArray)
--> 588 _, value = convert_struct_column_to_interleaved(field=value.field, column=value)
    590 if not DataType.is_fixed_size_list(value.type):
    591     self.error(obj, value, info="Point arrow array to be a FixedSizeList")

File [~/miniconda3/envs/sds/lib/python3.13/site-packages/lonboard/_geoarrow/ops/coord_layout.py:55](http://localhost:8888/home/nick/miniconda3/envs/sds/lib/python3.13/site-packages/lonboard/_geoarrow/ops/coord_layout.py#line=54), in convert_struct_column_to_interleaved(field, column)
     49 def convert_struct_column_to_interleaved(
     50     *,
     51     field: Field,
     52     column: ChunkedArray,
     53 ) -> tuple[Field, ChunkedArray]:
     54     """Convert a GeoArrow column from struct to interleaved coordinate layout."""
---> 55     extension_type_name = field.metadata[b"ARROW:extension:name"]
     57     new_chunked_array = _convert_column(column, extension_type_name=extension_type_name)
     58     return field.with_type(new_chunked_array.type), new_chunked_array

KeyError: b'ARROW:extension:name'

Environment

  • OS: Mac & Ubuntu
  • Browser: Chrome
  • Lonboard Version: 0.12.1

Steps to reproduce the bug

My MWE currently looks like this:

import numpy as np
import pyarrow as pa
import lonboard as lb

data = {
'source' : ['London', 'Manchester', 'Bristol'],
'target' : ['Manchester', 'Bristol', 'London']
}

source = np.array([(51.5072, 0.1276),(53.4808, 2.2426), (51.4545, 2.5879)])
target = np.array([(53.4808, 2.2426), (51.4545, 2.5879), (51.5072, 0.1276)])

table = pa.table(data)

lb.experimental.ArcLayer(
    table,
    get_source_position=source,
    get_target_position=target
)

I have been trying GeoArrow arrays as well but I haven't got those to work either.

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions