Skip to content
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

Add historic time series plot #368

Merged
merged 6 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
11 changes: 5 additions & 6 deletions ecoscope/io/earthranger.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,24 @@
import math
import typing

import ecoscope
import geopandas as gpd
import numpy as np
import pandas as pd
import pytz
import requests
from erclient.client import ERClient, ERClientException, ERClientNotFound
from shapely.geometry import shape
from tqdm.auto import tqdm

import ecoscope
from ecoscope.io.earthranger_utils import (
clean_kwargs,
clean_time_cols,
dataframe_to_dict,
format_iso_time,
pack_columns,
to_gdf,
to_hex,
pack_columns,
)
from erclient.client import ERClient, ERClientException, ERClientNotFound
from shapely.geometry import shape
from tqdm.auto import tqdm


class EarthRangerIO(ERClient):
Expand Down
97 changes: 96 additions & 1 deletion ecoscope/plotting/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
from ecoscope.base.utils import color_tuple_to_css

try:
from sklearn.neighbors import KernelDensity
import plotly.graph_objs as go
from plotly.subplots import make_subplots
from sklearn.neighbors import KernelDensity
except ModuleNotFoundError:
raise ModuleNotFoundError(
'Missing optional dependencies required by this module. \
Expand Down Expand Up @@ -386,3 +386,98 @@ def pie_chart(

fig = go.Figure(data=go.Pie(labels=labels, values=values, **style_kwargs), layout=layout_kwargs)
return fig


def draw_historic_timeseries(
df: pd.DataFrame,
current_value_column: str,
current_value_title: str,
historic_min_column: str = None,
historic_max_column: str = None,
historic_band_title: str = "Historic Min-Max",
historic_mean_column: str = None,
historic_mean_title: str = "Historic Mean",
layout_kwargs: dict = None,
):
"""
Creates a timeseries plot compared with historical values
Parameters
----------
df: pd.Dataframe
The data to plot
current_value_column: str
The name of the dataframe column to pull slice values from
current_value_title: str
The title shown in the plot legend for current value
historic_min_column: str
The name of the dataframe column to pull historic min values from. historic_min_column and historic_max_column should exist together.
historic_max_column: str
The name of the dataframe column to pull historic max values from. historic_min_column and historic_max_column should exist together.
historic_band_title: str
The title shown in the plot legend for historic band
historic_mean_column: str
The name of the dataframe column to pull historic mean values from
current_value_title: str
The title shown in the plot legend for historic mean values
layout_kwargs: dict
Additional kwargs passed to plotly.go.Figure(layout)
Returns
-------
fig : plotly.graph_objects.Figure
The plotly bar chart
"""

fig = go.Figure(layout=layout_kwargs)

if historic_max_column and historic_min_column:
# add the upper bound
fig.add_trace(
go.Scatter(
x=df.img_date,
y=df[historic_max_column],
fill=None,
mode="lines",
line_color="green",
name="",
showlegend=False,
)
)

# lower band
fig.add_trace(
go.Scatter(
x=df.img_date,
y=df[historic_min_column],
fill="tonexty",
mode="lines",
line_color="green",
name=historic_band_title,
)
)

if historic_mean_column:
# add the historic mean
fig.add_trace(
go.Scatter(
x=df.img_date,
y=df[historic_mean_column],
fill=None,
mode="lines",
line=dict(color="green", dash="dot"),
name=historic_mean_title,
)
)

# add current NDVI values
fig.add_trace(
go.Scatter(
x=df.img_date,
y=df[current_value_column],
fill=None,
mode="lines",
line_color="navy",
name=current_value_title,
)
)

return fig
Yun-Wu marked this conversation as resolved.
Show resolved Hide resolved
52 changes: 49 additions & 3 deletions tests/test_ecoplot.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import pytest
import numpy as np
import pandas as pd
from ecoscope.plotting.plot import EcoPlotData, ecoplot, mcp, nsd, speed, stacked_bar_chart, pie_chart
from ecoscope.base import Trajectory
import pytest

from ecoscope.analysis.classifier import apply_color_map
from ecoscope.base import Trajectory
from ecoscope.plotting.plot import (
EcoPlotData,
draw_historic_timeseries,
ecoplot,
mcp,
nsd,
pie_chart,
speed,
stacked_bar_chart,
)


@pytest.fixture
Expand Down Expand Up @@ -175,3 +185,39 @@ def test_pie_chart_numerical(chart_df):
"rgba(0, 0, 255, 1.0)",
"rgba(255, 255, 255, 1.0)",
)


def test_draw_historic_timeseries():
df = pd.DataFrame(
{
"min": [0.351723, 0.351723, 0.303219, 0.303219, 0.342149, 0.342149],
"max": [0.667335, 0.667335, 0.708183, 0.708183, 0.727095, 0.727095],
"mean": [0.472017, 0.472017, 0.543062, 0.543062, 0.555547, 0.555547],
"NDVI": [0.609656, 0.671868, 0.680008, 0.586662, 0.612170, np.nan],
"img_date": pd.to_datetime(
[
"2023-11-09",
"2023-11-25",
"2023-12-11",
"2023-12-27",
"2024-01-09",
"2024-01-25",
]
),
}
)

chart = draw_historic_timeseries(
df,
current_value_column="NDVI",
current_value_title="NDVI",
historic_min_column="min",
historic_max_column="max",
historic_mean_column="mean",
)

assert len(chart.data) == 4
assert chart.data[0].showlegend is False
assert chart.data[1].name == "Historic Min-Max"
assert chart.data[2].name == "Historic Mean"
assert chart.data[3].name == "NDVI"
Loading