Skip to content

Commit

Permalink
Merge branch 'master' into 223/event_dates
Browse files Browse the repository at this point in the history
  • Loading branch information
atmorling committed Aug 5, 2024
2 parents 4d4aa0e + 083814d commit 36ca033
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ jobs:
name: pip-dist
path: dist/
- name: Sign the dists with Sigstore
uses: sigstore/gh-action-sigstore-python@v2.1.1
uses: sigstore/gh-action-sigstore-python@v3.0.0
with:
inputs: >-
./dist/*.tar.gz
Expand Down
9 changes: 7 additions & 2 deletions ecoscope/io/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
from ecoscope.io import earthranger, eetools, raster, utils
from ecoscope.io.earthranger import EarthRangerIO
from ecoscope.io.async_earthranger import AsyncEarthRangerIO
from ecoscope.io.utils import download_file

__all__ = [
"earthranger",
"EarthRangerIO",
"AsyncEarthRangerIO",
"download_file",
"earthranger_utils",
"eetools",
"raster",
"utils",
]

try:
from ecoscope.io.async_earthranger import AsyncEarthRangerIO

__all__ += ["AsyncEarthRangerIO"]
except ImportError:
pass
11 changes: 9 additions & 2 deletions ecoscope/io/async_earthranger.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@
import geopandas as gpd
import pandas as pd
import asyncio
from erclient.client import AsyncERClient

import ecoscope
from ecoscope.io.utils import to_hex
from ecoscope.io.earthranger_utils import clean_kwargs, to_gdf, clean_time_cols

import ecoscope
try:
from erclient.client import AsyncERClient
except ModuleNotFoundError:
raise ModuleNotFoundError(
'Missing optional dependencies required by this module. \
Please run pip install ecoscope["async_earthranger"]'
)


class AsyncEarthRangerIO(AsyncERClient):
Expand Down
13 changes: 12 additions & 1 deletion ecoscope/plotting/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@
plot_seasonal_dist,
speed,
stacked_bar_chart,
pie_chart,
)

__all__ = ["EcoPlotData", "add_seasons", "ecoplot", "mcp", "nsd", "speed", "plot_seasonal_dist", "stacked_bar_chart"]
__all__ = [
"EcoPlotData",
"add_seasons",
"ecoplot",
"mcp",
"nsd",
"speed",
"plot_seasonal_dist",
"stacked_bar_chart",
"pie_chart",
]
39 changes: 39 additions & 0 deletions ecoscope/plotting/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,3 +325,42 @@ def stacked_bar_chart(data: EcoPlotData, agg_function: str, stack_column: str, l

fig.update_layout(barmode="stack")
return fig


def pie_chart(
data: pd.DataFrame, value_column: str, label_column: str = None, style_kwargs: dict = {}, layout_kwargs: dict = None
):
"""
Creates a pie chart from the provided dataframe
Parameters
----------
data: pd.Dataframe
The data to plot
value_column: str
The name of the dataframe column to pull slice values from
If the column contains non-numeric values, it is assumed to be categorical
and the pie slices will be a count of the occurrences of the category
label_column: str
The name of the dataframe column to label slices with, required if the data in value_column is numeric
style_kwargs: dict
Additional style kwargs passed to go.Pie()
layout_kwargs: dict
Additional kwargs passed to plotly.go.Figure(layout)
Returns
-------
fig : plotly.graph_objects.Figure
The plotly bar chart
"""

if pd.api.types.is_numeric_dtype(data[value_column]):
if label_column is not None:
labels = data[label_column]
values = data[value_column]
else:
raise ValueError("numerical values require a label column to")
else: # assume categorical
labels = data[value_column].unique()
values = data[value_column].value_counts()

fig = go.Figure(data=go.Pie(labels=labels, values=values, **style_kwargs), layout=layout_kwargs)
return fig
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ classifiers=[
dependencies = [
"backoff",
"earthengine-api",
"earthranger-client @ git+https://github.com/PADAS/er-client@v1.2.3",
"earthranger-client",
"geopandas<=0.14.2",
"pyproj",
"rasterio",
Expand All @@ -50,6 +50,9 @@ analysis = [
"scikit-image",
"scikit-learn",
]
async_earthranger = [
"earthranger-client @ git+https://github.com/PADAS/er-client@v1.2.3",
]
mapping = [
"lonboard @ git+https://github.com/wildlife-dynamics/lonboard@77c56d30a9c2dd96fd863e910bf62952cfa36da8",
"matplotlib",
Expand Down
69 changes: 45 additions & 24 deletions tests/test_ecoplot.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
import pytest
import numpy as np
import pandas as pd
from ecoscope.plotting.plot import EcoPlotData, ecoplot, mcp, nsd, speed, stacked_bar_chart
from ecoscope.plotting.plot import EcoPlotData, ecoplot, mcp, nsd, speed, stacked_bar_chart, pie_chart
from ecoscope.base import Trajectory


@pytest.fixture
def chart_df():
df = pd.DataFrame(
{
"id": [1, 2, 3, 4],
"category": ["A", "B", "B", "B"],
"type": ["A", "B", "C", "D"],
"value": [25, 40, 65, 150],
"time": ["2024-07-22", "2024-07-22", "2024-07-22", "2024-07-21"],
}
)
df.set_index("id", inplace=True)
return df


def test_ecoplot(movebank_relocations):
traj = Trajectory.from_relocations(movebank_relocations)
epd = EcoPlotData(traj.groupby("groupby_col"), "segment_start", "speed_kmhr", line=dict(color="blue"))
Expand Down Expand Up @@ -48,21 +64,12 @@ def test_speed(movebank_relocations):
len(figure.data[0].y) == len(traj) * 4


def test_stacked_bar_chart_categorical():
df = pd.DataFrame(
{
"id": [1, 2, 3, 4],
"category": ["A", "B", "B", "B"],
"time": ["2024-07-22", "2024-07-22", "2024-07-22", "2024-07-21"],
}
)
df.set_index("id", inplace=True)

def test_stacked_bar_chart_categorical(chart_df):
groupby_style = {"A": {"marker_color": "red"}, "B": {"marker_color": "blue"}}
style = {"marker_line_color": "black", "xperiodalignment": "middle"}
layout_kwargs = {"plot_bgcolor": "gray", "xaxis_dtick": 86400000}

gb = df.groupby(["time", "category"])
gb = chart_df.groupby(["time", "category"])
epd = EcoPlotData(gb, "time", "category", groupby_style=groupby_style, **style)
chart = stacked_bar_chart(epd, agg_function="count", stack_column="category", layout_kwargs=layout_kwargs)

Expand All @@ -81,22 +88,12 @@ def test_stacked_bar_chart_categorical():
assert chart.data[1].marker.color == "blue"


def test_stacked_bar_chart_numerical():
df = pd.DataFrame(
{
"id": [1, 2, 3, 4],
"category": ["A", "B", "B", "B"],
"value": [25, 40, 65, 150],
"time": ["2024-07-22", "2024-07-22", "2024-07-22", "2024-07-21"],
}
)
df.set_index("id", inplace=True)

def test_stacked_bar_chart_numerical(chart_df):
groupby_style = {"A": {"marker_color": "yellow"}, "B": {"marker_color": "green"}}
style = {"marker_line_color": "black", "xperiodalignment": "middle"}
layout_kwargs = {"plot_bgcolor": "gray", "xaxis_dtick": 86400000}

gb = df.groupby(["time", "category"])
gb = chart_df.groupby(["time", "category"])
epd = EcoPlotData(gb, "time", "value", groupby_style=groupby_style, **style)
chart = stacked_bar_chart(epd, agg_function="sum", stack_column="category", layout_kwargs=layout_kwargs)

Expand All @@ -112,3 +109,27 @@ def test_stacked_bar_chart_numerical():
assert chart.data[0].xperiodalignment == chart.data[1].xperiodalignment == "middle"
assert chart.data[0].marker.line.color == chart.data[1].marker.line.color == "black"
assert chart.data[1].marker.color == "green"


def test_pie_chart_categorical(chart_df):
layout = {"piecolorway": ["red", "green", "blue"]}
style = {"marker_line_color": "#000000", "marker_line_width": 2, "textinfo": "value"}
chart = pie_chart(chart_df, value_column="category", style_kwargs=style, layout_kwargs=layout)

assert chart.layout["piecolorway"] == ("red", "green", "blue")
assert set(chart.data[0].labels) == set(["A", "B"])
assert set(chart.data[0].values) == set([1, 3])
assert chart.data[0].marker.line.color == "#000000"
assert chart.data[0].marker.line.width == 2


def test_pie_chart_numerical(chart_df):
layout = {"piecolorway": ["red", "green", "blue"]}
style = {"marker_line_color": "#000000", "marker_line_width": 2, "textinfo": "value"}
chart = pie_chart(chart_df, value_column="value", label_column="type", style_kwargs=style, layout_kwargs=layout)

assert chart.layout["piecolorway"] == ("red", "green", "blue")
assert set(chart.data[0].labels) == set(chart_df.type)
assert set(chart.data[0].values) == set(chart_df.value)
assert chart.data[0].marker.line.color == "#000000"
assert chart.data[0].marker.line.width == 2

0 comments on commit 36ca033

Please sign in to comment.