"""
This File contains the visualization that is a Radar Scatter plot showing how many
number of days around each Running Water Body has an individual element spent. It
is an interactive visualization as such the user can change the water body and check
the distribution of animals around it.
Warning
-------
The visualizations in this module are currently developed with a focus around the
starkey.csv data as it has been developed as a side project by the developers. It
will further be integrated into the library as a general class of visualizers in
the time to come. Some of the visualization types may or may not work with other
datasets.
| Authors: Yaksh J Haranwala
"""
import pandas as pd
from IPython.core.display import display
from ipywidgets import widgets, AppLayout
from ptrail.core.TrajectoryDF import PTRAILDataFrame
from ptrail.features.temporal_features import TemporalFeatures as temp
from ptrail.preprocessing.filters import Filters as filt
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
pd.options.mode.chained_assignment = None
[docs]class HydrationTrends:
# Class variables to store datasets and the widget.
__habitat_data = None
__traj_data = None
__point_dict = None
__list = None
[docs] @staticmethod
def show_hydration_trends(trajectories: PTRAILDataFrame, habitat: pd.DataFrame,
dist_from_water: int):
"""
Plot the interactive plotly Radar chart that shows the number of days spent
by animals around a specific water body.
Note
----
The water bodies in the original dataset do not have any specific names.
Hence, they are just given names such as Water-body #1, Water-body #2
and so on.
Parameters
----------
trajectories: PTRAILDataFrame
The dataframe containing the trajectory data.
habitat: pd.DataFrame
The dataframe containing the habitat data.
dist_from_water: int
The maximum distance from the water water body that the animal should
be in.
Returns
-------
None
"""
# Store the datasets in the class variables.
HydrationTrends.__habitat_data = habitat
HydrationTrends.__traj_data = trajectories
# First, create the date column on the trajectory dataset.
HydrationTrends.__traj_data = temp.create_date_column(HydrationTrends.__traj_data)
HydrationTrends.__traj_data = temp.create_time_of_day_column(HydrationTrends.__traj_data)
# Now, filter out the moving water bodies.
a = habitat[(habitat['EcoGener'] == 'WR')]
water_bodies = a.loc[(a['DistEWat'] == 0)]
# Add an extra column that has bounding boxes for all the water bodies.
bboxes = []
for i in range(len(water_bodies)):
lat = water_bodies.iloc[i]['lat']
lon = water_bodies.iloc[i]['lon']
bboxes.append(filt.get_bounding_box_by_radius(lat, lon, dist_from_water))
water_bodies['bbox'] = bboxes
# Name all the water bodies and store their respective data rows in a dictionary.
point_dict = dict()
for i in range(len(water_bodies)):
point_dict[f'WaterBody #{i + 1}'] = water_bodies.iloc[i]
HydrationTrends.__point_dict = point_dict
# Create the dropdown widget.
HydrationTrends.__list = widgets.Dropdown(options=list(point_dict.keys()),
value='WaterBody #1',
description='WaterBody: ',
disabled=False, continuous_update=False)
# Show the plot.
radar = widgets.interactive_output(HydrationTrends.__plot_radar,
{'body_name': HydrationTrends.__list})
bar = widgets.interactive_output(HydrationTrends.__plot_bar,
{'body_name': HydrationTrends.__list})
output = AppLayout(header=None, center=None, footer=None,
left_sidebar=bar, right_sidebar=radar,
pane_heights=[1, 1, '480px'])
# Display the widget and its output side-by-side.
display(HydrationTrends.__list, output)
@staticmethod
def __plot_radar(body_name):
# Get the water body data by its name.
point = HydrationTrends.__point_dict[body_name]
# Filter the trajectory dataset by the water body.
dataset = filt.filter_by_bounding_box(HydrationTrends.__traj_data, point['bbox'])
small_df = pd.DataFrame(columns=['traj_id', 'days', 'Species']).set_index('traj_id')
ids_ = dataset.reset_index()['traj_id'].unique()
for j in range(len(ids_)):
mini = dataset.reset_index().loc[dataset.reset_index()['traj_id'] == ids_[j]]
if 'D' in ids_[j]:
small_df.loc[ids_[j]] = [pd.to_datetime(mini.Date).nunique(), 'Deer']
elif 'E' in ids_[j]:
small_df.loc[ids_[j]] = [pd.to_datetime(mini.Date).nunique(), 'Elk']
else:
small_df.loc[ids_[j]] = [pd.to_datetime(mini.Date).nunique(), 'Cattle']
fig1 = px.scatter_polar(small_df, r='days', color='Species',
title=f'Number of Days Spent Around {body_name}',
template="ggplot2", color_discrete_sequence=px.colors.qualitative.Vivid, )
fig1.update_layout(
polar=dict(
radialaxis=dict(visible=True),
),
title=dict(
font={'size': 13}
),
margin=dict(l=20, r=20, t=30, b=20),
autosize=False,
width=540,
height=280,
paper_bgcolor="Gainsboro",
)
fig1.update_polars(
angularaxis_tickmode='array',
angularaxis_tickvals=[0, 90, 180, 270],
angularaxis_ticktext=['', '', '', ''],
)
fig1.show()
@staticmethod
def __plot_bar(body_name):
# Get the water body data by its name.
point = HydrationTrends.__point_dict[body_name]
# Filter the trajectory dataset by the water body.
dataset = filt.filter_by_bounding_box(HydrationTrends.__traj_data, point['bbox'])
new_species = []
for i in range(len(dataset)):
if dataset['Species'].iloc[i] == 0:
new_species.append('Deer')
elif dataset['Species'].iloc[i] == 1:
new_species.append('Elk')
else:
new_species.append('Cattle')
dataset['Species'] = new_species
# Order the dataset according to the times of day.
small_df = dataset.groupby(by=['Time_Of_Day', 'Species']).count().reset_index()
times = ['Early Morning', 'Morning', 'Noon', 'Evening', 'Night', 'Late Night']
small_df['Time_Of_Day'] = pd.Categorical(small_df['Time_Of_Day'],
categories=times,
ordered=True)
small_df = small_df.sort_values(by='Time_Of_Day', ascending=True)
# Plot the barplot from the data above.
fig, ax = plt.subplots(figsize=(7, 5))
sns.barplot(x='Time_Of_Day', y='lat', hue='Species', hue_order=['Deer', 'Elk', 'Cattle'], data=small_df, ax=ax)
# Set the description of the text.
fig.text(-0.4, 0.5,
f"{body_name} Description\n\n"
f"Pasture Name: {point['CowPast']}\n"
f"Coordinates: {round(point['lat'], 2), round(point['lon'], 2)} \n"
f"Elevation: {point['Elev']} m \n"
f"Canopy Cover: {point['Canopy']}%"
, fontdict={'size': 13})
fig.set_facecolor('lightgray')
ax.set_xlabel('TIME OF THE DAY')
ax.set_ylabel('NUMBER OS TIMES VISITED')
ax.set_title('Hydration trend of Species throughout the day')
fig.tight_layout()