diff --git a/scripts/plotly_streamlit.py b/scripts/plotly_streamlit.py
index 2df1550..43269eb 100755
--- a/scripts/plotly_streamlit.py
+++ b/scripts/plotly_streamlit.py
@@ -2,19 +2,25 @@ import os
import streamlit as st
import pandas as pd
import numpy as np
+from numpy import ma
import plotly.graph_objects as go
from plotly.subplots import make_subplots
-from datetime import timedelta
+import plotly.io as pio
+from datetime import timedelta, datetime
+from pathlib import Path
import sqlite3
from sqlite3 import Connection
import plotly.express as px
+from sklearn.preprocessing import normalize
+
+pio.templates.default = "plotly_white"
userDir = os.path.expanduser('~')
URI_SQLITE_DB = userDir + '/BirdNET-Pi/scripts/birds.db'
st.set_page_config(layout='wide')
-# Remove whitespace from the top of the page and sidebar
+# Remove whitespace from the top of the page
st.markdown("""
',
+ unsafe_allow_html=True)
+st.write('',
+ unsafe_allow_html=True)
-filt = (df2.index >= pd.Timestamp(Date_Slider[0])) & (df2.index <= pd.Timestamp(Date_Slider[1] + timedelta(days=1)))
-df2 = df2[filt]
+# Select time period buttons
+# Disallow "Daily time period" for "Daily Chart"
+if start_date == end_date:
+ resample_sel = st.sidebar.radio(
+ "Resample Resolution",
+ ('Raw', '15 minutes', 'Hourly'), index=1, help= 'Select resolution for single day - larger times run faster' )
-st.write('', unsafe_allow_html=True)
-st.write('', unsafe_allow_html=True)
+ resample_times = {'Raw': 'Raw',
+ '1 minute': '1min',
+ '15 minutes': '15min',
+ 'Hourly': '1H'
+ }
+ resample_time = resample_times[resample_sel]
-resample_sel = cols2.radio(
- '''
- Select Resample Resolution - To downsample and make run faster select longer period,
- Daily provides a view on detections at 15 min intervals through the day
- ''',
- ('1 minute',
- '5 minutes',
- '10 minutes',
- 'Hourly',
- 'Daily'))
+else:
+ resample_sel = st.sidebar.radio(
+ "Resample Resolution",
+ ('Raw', '15 minutes', 'Hourly', 'DAILY'), index=1, help= 'Select resolution for species - DAILY provides time series')
-resample_times = {'1 minute': '1min',
- '5 minutes': '5min',
- '10 minutes': '10min',
- 'Hourly': '1H',
- 'Daily': '1D'
- }
-resample_time = resample_times[resample_sel]
+ resample_times = {'Raw': 'Raw',
+ '1 minute': '1min',
+ '15 minutes': '15min',
+ 'Hourly': '1H',
+ 'DAILY': '1D'
+ }
+ resample_time = resample_times[resample_sel]
-df5 = df2.resample(resample_time)['Com_Name'].aggregate('unique').explode()
+@st.cache()
+def time_resample(df, resample_time):
+ if resample_time == 'Raw':
+ df_resample = df['Com_Name']
+
+ else:
+ df_resample = df.resample(resample_time)['Com_Name'].aggregate('unique').explode()
+
+ return(df_resample)
+top_bird = df2['Com_Name'].mode()[0]
+df5 = time_resample(df2, resample_time)
# Create species count for selected date range
Specie_Count = df5.value_counts()
-# Create species treemap
-
# Create Hourly Crosstab
hourly = pd.crosstab(df5, df5.index.hour, dropna=False)
# Filter on species
species = list(hourly.index)
-cols1, cols2 = st.columns((1, 1))
-top_N = cols1.slider(
+#cols1, cols2 = st.columns((1, 1))
+top_N = st.sidebar.slider(
'Select Number of Birds to Show',
min_value=1,
+ max_value=len(Specie_Count),
value=min(10, len(Specie_Count))
)
top_N_species = (df5.value_counts()[:top_N])
-
-specie = cols2.selectbox('Which bird would you like to explore for the dates ' + str(Date_Slider[0]) + ' to ' + str(Date_Slider[1]) + '?', species,
- index=species.index(list(top_N_species.index)[0]))
-
-
font_size = 15
+if daily == False:
+ specie = st.selectbox(
+ 'Which bird would you like to explore for the dates '
+ + str(start_date) + ' to ' + str(end_date) + '?',
+ species,
+ index = species.index(top_bird))
-# specie filter
-filt = df2['Com_Name'] == specie
+ filt = df2['Com_Name'] == specie
-df_counts = sum(df5 == specie)
+ df_counts = sum(df5 == specie)
+ if resample_time != '1D':
-if resample_time != '1D':
- fig = make_subplots(
- rows=3, cols=2,
- specs=[[{"type": "xy", "rowspan": 3}, {"type": "polar", "rowspan": 2}], [{"rowspan": 1}, {"rowspan": 1}], [None, {"type": "xy", "rowspan": 1}]],
- subplot_titles=('Top ' +
- str(top_N) +
- ' Species in Date Range ' +
- str(Date_Slider[0]) +
- ' to ' +
- str(Date_Slider[1]) +
- ' for ' +
- str(resample_sel) +
- ' sampling interval.' +
- '',
- 'Total Detect:' + str('{:,}'.format(df_counts)) +
- ' Confidence Max:' + str('{:.2f}%'.format(max(df2[df2['Com_Name'] == specie]['Confidence']) * 100)) +
- ' ' + ' Median:' + str('{:.2f}%'.format(np.median(df2[df2['Com_Name'] == specie]['Confidence']) * 100))
- )
- )
- fig.layout.annotations[1].update(x=0.7, y=0.25, font_size=15)
+ fig = make_subplots(
+ rows=3, cols=2,
+ specs=[[{"type": "xy", "rowspan": 3}, {"type": "polar", "rowspan": 2}], [{"rowspan": 1}, {"rowspan": 1}],
+ [None, {"type": "xy", "rowspan": 1}]],
+ subplot_titles=('Top ' + str(top_N) + ' Species in Date Range ' + str(start_date) + ' to ' + str(
+ end_date) + ' for ' + str(resample_sel) + ' sampling interval.' + '',
+ 'Total Detect:' + str('{:,}'.format(df_counts)) +
+ ' Confidence Max:' + str(
+ '{:.2f}%'.format(max(df2[df2['Com_Name'] == specie]['Confidence']) * 100)) +
+ ' ' + ' Median:' + str(
+ '{:.2f}%'.format(np.median(df2[df2['Com_Name'] == specie]['Confidence']) * 100))
+ )
+ )
+ fig.layout.annotations[1].update(x=0.7, y=0.25, font_size=15)
- # Plot seen species for selected date range and number of species
- fig.add_trace(go.Bar(y=top_N_species.index, x=top_N_species, orientation='h'), row=1, col=1)
+ # Plot seen species for selected date range and number of species
+ fig.add_trace(go.Bar(y=top_N_species.index, x=top_N_species, orientation='h', marker_color='seagreen'), row=1, col=1)
- fig.update_layout(
- margin=dict(l=0, r=0, t=50, b=0),
- yaxis={'categoryorder': 'total ascending'})
+ fig.update_layout(
+ margin=dict(l=0, r=0, t=50, b=0),
+ yaxis={'categoryorder': 'total ascending'})
- # Set 360 degrees, 24 hours for polar plot
- theta = np.linspace(0.0, 360, 24, endpoint=False)
+ # Set 360 degrees, 24 hours for polar plot
+ theta = np.linspace(0.0, 360, 24, endpoint=False)
- specie_filt = df5 == specie
- df3 = df5[specie_filt]
+ specie_filt = df5 == specie
+ df3 = df5[specie_filt]
- detections2 = pd.crosstab(df3, df3.index.hour)
+ detections2 = pd.crosstab(df3, df3.index.hour)
- d = pd.DataFrame(np.zeros((23, 1))).squeeze()
- detections = hourly.loc[specie]
- detections = (d + detections).fillna(0)
- fig.add_trace(go.Barpolar(r=detections, theta=theta), row=1, col=2)
- fig.update_layout(
- autosize=False,
- width=1000,
- height=500,
- showlegend=False,
- polar=dict(
- radialaxis=dict(
- tickfont_size=font_size,
- showticklabels=False,
- hoverformat="#%{theta}:
Popularity: %{percent} %{r}"
+ d = pd.DataFrame(np.zeros((23, 1))).squeeze()
+ detections = hourly.loc[specie]
+ detections = (d + detections).fillna(0)
+ fig.add_trace(go.Barpolar(r=detections, theta=theta, marker_color='seagreen'), row=1, col=2)
+ fig.update_layout(
+ autosize=False,
+ width=1000,
+ height=500,
+ showlegend=False,
+ polar=dict(
+ radialaxis=dict(
+ tickfont_size=font_size,
+ showticklabels=False,
+ hoverformat="#%{theta}:
Popularity: %{percent} %{r}"
+ ),
+ angularaxis=dict(
+ tickfont_size=font_size,
+ rotation=-90,
+ direction='clockwise',
+ tickmode='array',
+ tickvals=[0, 15, 35, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240, 255, 270,
+ 285, 300, 315, 330, 345],
+ ticktext=['12am', '1am', '2am', '3am', '4am', '5am', '6am', '7am', '8am', '9am', '10am', '11am',
+ '12pm', '1pm', '2pm', '3pm', '4pm', '5pm', '6pm', '7pm', '8pm', '9pm', '10pm', '11pm'],
+ hoverformat="#%{theta}:
Popularity: %{percent} %{r}"
+ ),
),
- angularaxis=dict(
- tickfont_size=font_size,
- rotation=-90,
- direction='clockwise',
- tickmode='array',
- tickvals=[0, 15, 35, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240, 255, 270, 285, 300, 315, 330, 345],
- ticktext=['12am', '1am', '2am', '3am', '4am', '5am', '6am', '7am', '8am', '9am', '10am', '11am',
- '12pm', '1pm', '2pm', '3pm', '4pm', '5pm', '6pm', '7pm', '8pm', '9pm', '10pm', '11pm'],
- hoverformat="#%{theta}:
Popularity: %{percent} %{r}"
- ),
- ),
- )
+ )
- daily = pd.crosstab(df5, df5.index.date, dropna=False)
+ daily = pd.crosstab(df5, df5.index.date, dropna=False)
- fig.add_trace(go.Bar(x=daily.columns, y=daily.loc[specie]), row=3, col=2)
+ fig.add_trace(go.Bar(x=daily.columns, y=daily.loc[specie], marker_color='seagreen'), row=3, col=2)
+ else:
+ fig = st.container()
+ fig = make_subplots(
+ rows=1, cols =1)
+ # specs= [[{"type":"xy","rowspan":1},{"type":"heatmap","rowspan":1}]],
+
+
+ # subplot_titles=('Daily Top '+ str(top_N) + ' Species in Date Range '+ str(start_date) +' to '+ str(end_date) +'',
+ # 'Daily ' + specie+ ' Detections on 15 minute intervals '),
+ # # 'Total Detect:'+str('{:,}'.format(df_counts))+
+ # # ' Confidence Max:'+str('{:.2f}%'.format(max(df2[df2['Com_Name']==specie]['Confidence'])*100))+
+ # # ' '+' Median:'+str('{:.2f}%'.format(np.median(df2[df2['Com_Name']==specie]['Confidence'])*100))
+ # # )
+ # )
+
+# fig.add_trace(go.Bar(y=top_N_species.index, x=top_N_species, orientation='h'), row=1,col=1)
+ df4=df2['Com_Name'][df2['Com_Name']==specie].resample('15min').count()
+ df4.index=[df4.index.date, df4.index.time]
+ day_hour_freq=df4.unstack().fillna(0)
+
+ fig_x = [d.strftime('%d-%m-%Y') for d in day_hour_freq.index.tolist()]
+ fig_y = [h.strftime('%H:%M') for h in day_hour_freq.columns.tolist()]
+ fig_z = day_hour_freq.values.transpose()
+# fig_heatmap = go.Figure(data=go.Heatmap(x=fig_x,y=fig_y,z=fig_z))
+
+ # fig.update_layout(
+ # margin=dict(l=0, r=0, t=50, b=0),
+ # yaxis={'categoryorder':'total ascending'})
+ color_pals= px.colors.named_colorscales()
+ selected_pal = st.sidebar.selectbox('Select Color Pallet for Daily Detections', color_pals)
+ fig.add_trace(go.Heatmap(x=fig_x,y=fig_y,z=fig_z, autocolorscale = False, colorscale = selected_pal), row=1, col=1)
else:
fig = make_subplots(
rows=1, cols=2,
specs=[[{"type": "xy", "rowspan": 1}, {"type": "xy", "rowspan": 1}]],
-
-
- subplot_titles=('Daily Top ' + str(top_N) + ' Species in Date Range ' + str(Date_Slider[0]) + ' to ' + str(Date_Slider[1]) + '',
- 'Daily ' + specie + ' Detections on 15 minute intervals '),
- # 'Total Detect:'+str('{:,}'.format(df_counts))+
- # ' Confidence Max:'+str('{:.2f}%'.format(max(df2[df2['Com_Name']==specie]['Confidence'])*100))+
- # ' '+' Median:'+str('{:.2f}%'.format(np.median(df2[df2['Com_Name']==specie]['Confidence'])*100))
- # )
+ subplot_titles=('Top ' + str(top_N) + ' Species For ' + str(start_date) + '',
+ 'Daily ' + str(start_date) + ' Detections on ' + resample_sel + ' interval'),
+ shared_yaxes='all',
+ horizontal_spacing=0
)
- fig.add_trace(go.Bar(y=top_N_species.index, x=top_N_species, orientation='h'), row=1, col=1)
- df4 = df2['Com_Name'][df2['Com_Name'] == specie].resample('15min').count()
- df4.index = [df4.index.date, df4.index.time]
- day_hour_freq = df4.unstack().fillna(0)
+ df6 = df5.to_frame(name='Com_Name')
+ readings = top_N
- fig_x = [d.strftime('%d-%m-%Y') for d in day_hour_freq.index.tolist()]
- fig_y = [h.strftime('%H:%M') for h in day_hour_freq.columns.tolist()]
- fig_z = day_hour_freq.values.transpose()
- fig_heatmap = go.Figure(data=go.Heatmap(x=fig_x, y=fig_y, z=fig_z))
+ plt_topN_today = (df6['Com_Name'].value_counts()[:readings])
+ freq_order = pd.value_counts(df6['Com_Name']).iloc[:readings].index
+ # confmax = df6.groupby('Com_Name')['Confidence'].max()
+ # reorder confmax to detection frequency order
+ # confmax = confmax.reindex(freq_order)
+ # norm = plt.Normalize(confmax.values.min(), confmax.values.max())
+ #
+ # colors = plt.cm.Greens(norm(confmax))
+ fig.add_trace(go.Bar(y=plt_topN_today.index, x=plt_topN_today, marker_color='seagreen', orientation='h'), row=1,
+ col=1)
- fig.update_layout(
- margin=dict(l=0, r=0, t=50, b=0),
- yaxis={'categoryorder': 'total ascending'})
- color_pals = px.colors.named_colorscales()
- selected_pal = cols2.selectbox('Select Color Pallet for Daily Detections', color_pals)
- fig.add_trace(go.Heatmap(x=fig_x, y=fig_y, z=fig_z, autocolorscale=False, colorscale=selected_pal), row=1, col=2)
+ # plot=sns.countplot(y='Com_Name', data = df_plt_topN_today, palette = colors, order=freq_order, ax=axs[0])
+
+ df6['Hour of Day'] = [r.hour for r in df6.index.time]
+ heat = pd.crosstab(df6['Com_Name'], df6['Hour of Day'])
+ # Order heatmap Birds by frequency of occurrance
+ heat.index = pd.CategoricalIndex(heat.index, categories=freq_order)
+ heat.sort_index(level=0, inplace=True)
+
+ heat_plot_values = ma.log(heat.values).filled(0)
+
+ hours_in_day = pd.Series(data=range(0, 24))
+ heat_frame = pd.DataFrame(data=0, index=heat.index, columns=hours_in_day)
+
+ heat = (heat + heat_frame).fillna(0)
+ heat_values_normalized = normalize(heat.values, axis=1, norm='l1')
+
+ labels = heat.values.astype(int).astype('str')
+ labels[labels == '0'] = ""
+ fig.add_trace(go.Heatmap(x=heat.columns, y=heat.index, z=heat_values_normalized, # heat.values,
+ showscale=False,
+ text=labels, texttemplate="%{text}", colorscale='Blugrn'
+ ), row=1, col=2)
+ fig.update_yaxes(visible=True, autorange="reversed", ticks="inside", tickson="boundaries", ticklen=10000,
+ showgrid=True)
+ fig.update_layout(xaxis_ticks="inside",
+ margin=dict(l=0, r=0, t=50, b=0))
# container=st.container()
# config={'displayModelBar': False}
st.plotly_chart(fig, use_container_width=True) # , config=config)
# cols3,cols4=st.columns((1,1))
-#
+#
# extract_date=Date_Slider
-#
+#
# audio_file = open('/home/*/BirdSongs/Extracted/By_Date/2022-03-22/Yellow-streaked_Greenbul/Yellow-streaked_Greenbul-77-2022-03-22-birdnet-15:04:28.mp3', 'rb')
# audio_bytes = audio_file.read()
# cols4.audio(audio_bytes, format='audio/mp3')