Skip to content

Commit

Permalink
Add support for DeckGL ArcLayer (#877)
Browse files Browse the repository at this point in the history
  • Loading branch information
giswqs committed Aug 22, 2024
1 parent 4df81f9 commit 39b9c91
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 0 deletions.
40 changes: 40 additions & 0 deletions leafmap/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -14297,3 +14297,43 @@ def create_polyline(row):
gdf = gdf.set_geometry("geometry")
gdf.crs = crs
return gdf


def read_file(data: str, **kwargs: Any) -> Union[pd.DataFrame, "gpd.GeoDataFrame"]:
"""
Reads a file and returns a DataFrame or GeoDataFrame.
Args:
data (str): The file path or a DataFrame/GeoDataFrame.
**kwargs (Any): Additional arguments passed to the file reading function.
Returns:
Union[pd.DataFrame, gpd.GeoDataFrame]: The read data as a DataFrame or GeoDataFrame.
Raises:
ValueError: If the data type is unsupported.
"""
import geopandas as gpd

if isinstance(data, str):
if data.endswith(".parquet"):
df = pd.read_parquet(data, **kwargs)
elif data.endswith(".csv"):
df = pd.read_csv(data, **kwargs)
elif data.endswith(".json"):
df = pd.read_json(data, **kwargs)
elif data.endswith(".xlsx"):
df = pd.read_excel(data, **kwargs)
else:
df = gpd.read_file(data, **kwargs)
elif isinstance(data, dict) or isinstance(data, list):
df = pd.DataFrame(data, **kwargs)

elif isinstance(data, pd.DataFrame) or isinstance(data, gpd.GeoDataFrame):
df = data
else:
raise ValueError(
"Unsupported data type. Please provide a file path or a DataFrame."
)

return df
97 changes: 97 additions & 0 deletions leafmap/maplibregl.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,103 @@ def remove_layer(self, name: str) -> None:
if name in self.layer_dict:
self.layer_dict.pop(name)

def add_deck_layers(self, layers: list[dict], tooltip: str | dict = None) -> None:
"""Add Deck.GL layers to the layer stack
Args:
layers (list[dict]): A list of dictionaries containing the Deck.GL layers to be added.
tooltip (str | dict): Either a single mustache template string applied to all layers
or a dictionary where keys are layer ids and values are mustache template strings.
"""
super().add_deck_layers(layers, tooltip)

for layer in layers:

self.layer_dict[layer["id"]] = {
"layer": layer,
"opacity": layer.get("opacity", 1.0),
"visible": layer.get("visible", True),
"type": layer.get("@@type", "deck"),
"color": layer.get("getFillColor", "#ffffff"),
}

def add_arc_layer(
self,
data: Union[str, pd.DataFrame],
src_lon: str,
src_lat: str,
dst_lon: str,
dst_lat: str,
src_color: List[int] = [255, 0, 0],
dst_color: List[int] = [255, 255, 0],
line_width: int = 2,
layer_id: str = "arc_layer",
pickable: bool = True,
tooltip: Optional[Union[str, List[str]]] = None,
**kwargs: Any,
) -> None:
"""
Add a DeckGL ArcLayer to the map.
Args:
data (Union[str, pd.DataFrame]): The file path or DataFrame containing the data.
src_lon (str): The source longitude column name.
src_lat (str): The source latitude column name.
dst_lon (str): The destination longitude column name.
dst_lat (str): The destination latitude column name.
src_color (List[int]): The source color as an RGB list.
dst_color (List[int]): The destination color as an RGB list.
line_width (int): The width of the lines.
layer_id (str): The ID of the layer.
pickable (bool): Whether the layer is pickable.
tooltip (Optional[Union[str, List[str]]], optional): The tooltip content or list of columns. Defaults to None.
**kwargs (Any): Additional arguments for the layer.
Returns:
None
"""

df = read_file(data)
if "geometry" in df.columns:
df = df.drop(columns=["geometry"])

arc_data = [
{
"source_position": [row[src_lon], row[src_lat]],
"target_position": [row[dst_lon], row[dst_lat]],
**row.to_dict(), # Include other columns
}
for _, row in df.iterrows()
]

# Generate tooltip template dynamically based on the columns
if tooltip is None:
columns = df.columns
elif isinstance(tooltip, list):
columns = tooltip
tooltip_content = "<br>".join([f"{col}: {{{{ {col} }}}}" for col in columns])

deck_arc_layer = {
"@@type": "ArcLayer",
"id": layer_id,
"data": arc_data,
"getSourcePosition": "@@=source_position",
"getTargetPosition": "@@=target_position",
"getSourceColor": src_color,
"getTargetColor": dst_color,
"getWidth": line_width,
"pickable": pickable,
}

deck_arc_layer.update(kwargs)

self.add_deck_layers(
[deck_arc_layer],
tooltip={
layer_id: tooltip_content,
},
)

def add_control(
self, control: Union[str, Any], position: str = "top-right", **kwargs: Any
) -> None:
Expand Down

0 comments on commit 39b9c91

Please sign in to comment.