From e3591e0823bbd8ff2e1447eceafbe745d91b23ad Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:25:54 +0100 Subject: [PATCH] Full annotated code --- scripts/dynamic_plot.py | 115 ++++++++++++++++++++++++---------------- 1 file changed, 68 insertions(+), 47 deletions(-) diff --git a/scripts/dynamic_plot.py b/scripts/dynamic_plot.py index dd256aadd..9f3fd9aa6 100644 --- a/scripts/dynamic_plot.py +++ b/scripts/dynamic_plot.py @@ -4,19 +4,36 @@ import numpy as np from datetime import datetime import os -from utils.helpers import get_settings # Import to access COLOR_SCHEME - -# Define custom colorscales for light and dark modes -COLOR_SCALES = { - "light": [ - [0.0, '#E0F2E9'], [0.2, '#A3D8A1'], [0.4, '#70BD70'], - [0.6, '#46A846'], [0.8, '#2E7D2E'], [1.0, '#004D00'] - ], - "dark": [ - [0.0, '#F0F0F0'], [0.2, '#BDBDBD'], [0.4, '#969696'], - [0.6, '#737373'], [0.8, '#525252'], [1.0, '#252525'] - ] -} +from utils.helpers import get_settings # Import if needed for other settings + +# Fetch color scheme setting and choose corresponding colorscale and text color +conf = get_settings() +color_scheme = conf.get('COLOR_SCHEME', 'light') + +if color_scheme == 'dark': + PLOT_BGCOLOR='#F0F0F0' + PAPER_BGCOLOR='#7F7F7F' + CUSTOM_COLOR_SCALE = [ + [0.0, PLOT_BGCOLOR], + [0.2, '#BDBDBD'], + [0.4, '#969696'], + [0.6, '#737373'], + [0.8, '#525252'], + [1.0, '#252525'] + ] +else: + PLOT_BGCOLOR='#FFFFFF' + PAPER_BGCOLOR='#7BC58A' + CUSTOM_COLOR_SCALE = [ + [0.0, PLOT_BGCOLOR], + [0.1, '#E0F2E9'], + [0.2, '#A3D8A1'], + [0.4, '#70BD70'], + [0.6, '#46A846'], + [0.8, '#2E7D2E'], + [1.0, '#004D00'] + ] + ALL_HOURS = list(range(24)) @@ -28,9 +45,9 @@ def normalize_logarithmic(arr): return np.log(arr / min_val) / np.log(np.max(arr) / min_val) if np.max(arr) > min_val else arr - min_val -def determine_text_color(z, threshold=0.5): - """Determines text color (black or white) based on normalized value of z.""" - return np.where(z > threshold, 'white', 'black') +def determine_text_color(z, threshold=0.8): + """Determines text color (darkgrey or white) based on normalized value of z.""" + return np.where(z == 0, PLOT_BGCOLOR, np.where(z > threshold, PLOT_BGCOLOR, '#1A1A1A')) def add_annotations(fig, text_array, text_colors, col, row, species_list, all_hours, annotations): @@ -41,7 +58,7 @@ def add_annotations(fig, text_array, text_colors, col, row, species_list, all_ho if current_text: annotations.append(dict( x=0, y=species, text=current_text, showarrow=False, - font=dict(color=current_color, size=10), + font=dict(color=current_color, size=12), xref=f'x{col}', yref=f'y{col}', xanchor='center', yanchor='middle' )) elif col == 3: # Multi-column heatmap @@ -51,7 +68,7 @@ def add_annotations(fig, text_array, text_colors, col, row, species_list, all_ho if current_text: annotations.append(dict( x=hour, y=species, text=current_text, showarrow=False, - font=dict(color=current_color, size=10), + font=dict(color=current_color, size=12), xref='x3', yref='y3', xanchor='center', yanchor='middle' )) @@ -74,11 +91,6 @@ def create_plotly_heatmap(df_birds, now): Conf=('Confidence', 'max') ).reset_index().fillna({'Conf': 0, 'Count': 0}) - # Fetch color scheme setting and choose corresponding colorscale and text color - conf = get_settings() - color_scheme = conf.get('COLOR_SCHEME', 'light') - color_scale = COLOR_SCALES.get(color_scheme, COLOR_SCALES["light"]) - # Summarize data for heatmap axes df_birds_summary = plot_dataframe.groupby('Com_Name').agg( Count=('Count', 'sum'), @@ -89,58 +101,70 @@ def create_plotly_heatmap(df_birds, now): species_list = df_birds_summary['Com_Name'].tolist() # Normalize values and prepare text annotations - z_confidence = normalize_logarithmic(df_birds_summary['Conf'].values.reshape(-1, 1) * 100) - text_confidence = np.char.add(np.round(df_birds_summary['Conf'].values).astype(int).astype(str), ' %') + z_confidence = normalize_logarithmic(df_birds_summary['Conf'].values.reshape(-1, 1)) * 100 + text_confidence = np.char.add((df_birds_summary['Conf'].values * 100).round().astype(int).astype(str), ' %') z_detections = normalize_logarithmic(df_birds_summary['Count'].values.reshape(-1, 1)) text_detections = df_birds_summary['Count'].astype(str).values # Use actual counts for annotations - text_color_detections = determine_text_color(z_detections, threshold=0.5, color_scheme=color_scheme) + text_color_detections = determine_text_color(z_detections, threshold=0.5) # Removed color_scheme df_hourly = plot_dataframe.pivot_table(index='Com_Name', columns='Hour', values='Count', aggfunc='sum').fillna(0) df_hourly = df_hourly.reindex(species_list).fillna(0).reindex(columns=ALL_HOURS, fill_value=0) z_hourly = normalize_logarithmic(df_hourly.values) text_hourly = df_hourly.astype(int).astype(str).values # Use actual counts for hourly annotations - text_color_hourly = determine_text_color(z_hourly, threshold=0.5, color_scheme=color_scheme) + text_color_hourly = determine_text_color(z_hourly, threshold=0.5) # Removed color_scheme # Create subplots fig = make_subplots(rows=1, cols=3, shared_yaxes=True, column_widths=[0.1, 0.1, 0.7], horizontal_spacing=0.02) - # Heatmap Traces + # Prepare structured customdata arrays for each heatmap trace + custom_data_confidence = np.array([{'confidence': conf * 100} for conf in df_birds_summary['Conf'].values]).reshape(-1, 1) + custom_data_count = np.array([{'count': count} for count in df_birds_summary['Count'].values]).reshape(-1, 1) + + # Add traces with updated customdata structure and hovertemplate fig.add_trace(go.Heatmap( - z=z_confidence, customdata=df_birds_summary['Conf'].values, x=['Confidence'], y=species_list, - colorscale=color_scale, showscale=False, hovertemplate='Species: %{y}
Max Confidence: %{customdata:.0f}%', + z=z_confidence, customdata=custom_data_confidence, x=['Confidence'], y=species_list, + colorscale=CUSTOM_COLOR_SCALE, showscale=False, + hovertemplate='Species: %{y}
Max Confidence: %{customdata.confidence:.0f}%', xgap=1, ygap=1, zmin=0, zmax=1 ), row=1, col=1) - + fig.add_trace(go.Heatmap( - z=z_detections, customdata=df_birds_summary['Count'].values, x=['Count'], y=species_list, - colorscale=color_scale, showscale=False, hovertemplate='Species: %{y}
Total Counts: %{customdata}', + z=z_detections, customdata=custom_data_count, x=['Count'], y=species_list, + colorscale=CUSTOM_COLOR_SCALE, showscale=False, + hovertemplate='Species: %{y}
Total Counts: %{customdata.count}', xgap=1, ygap=1, zmin=0, zmax=1 ), row=1, col=2) fig.add_trace(go.Heatmap( z=z_hourly, customdata=df_hourly.values, x=ALL_HOURS, y=species_list, - colorscale=color_scale, showscale=False, hovertemplate='Species: %{y}
Hour: %{x}
Detections: %{customdata}', + colorscale=CUSTOM_COLOR_SCALE, showscale=False, hovertemplate='Species: %{y}
Hour: %{x}
Detections: %{customdata}', xgap=1, ygap=1, zmin=0, zmax=1 ), row=1, col=3) # Annotations annotations = [] - add_annotations(fig, text_confidence.reshape(-1, 1), determine_text_color(z_confidence, threshold=0.5, color_scheme=color_scheme), col=1, row=1, species_list=species_list, all_hours=ALL_HOURS, annotations=annotations) - add_annotations(fig, text_detections.reshape(-1, 1), text_color_detections, col=2, row=1, species_list=species_list, all_hours=ALL_HOURS, annotations=annotations) - add_annotations(fig, text_hourly, text_color_hourly, col=3, row=1, species_list=species_list, all_hours=ALL_HOURS, annotations=annotations) + add_annotations(fig, text_confidence.reshape(-1, 1), determine_text_color(z_confidence, threshold=0.5), + col=1, row=1, species_list=species_list, all_hours=ALL_HOURS, annotations=annotations) + add_annotations(fig, text_detections.reshape(-1, 1), text_color_detections, + col=2, row=1, species_list=species_list, all_hours=ALL_HOURS, annotations=annotations) + add_annotations(fig, text_hourly, text_color_hourly, + col=3, row=1, species_list=species_list, all_hours=ALL_HOURS, annotations=annotations) fig.update_layout(annotations=annotations) # Layout configuration fig.update_layout( - title=dict(text=f"{main_title}
{subtitle}", x=0.5, y=0.97, xanchor='center', yanchor='top', font=dict(size=24)), + title=dict(text=f"{main_title}
{subtitle}", + x=0.5, y=0.97, xanchor='center', yanchor='top', font=dict(size=24)), autosize=True, height=max(600, len(species_list) * 25 + 100), - yaxis=dict(autorange='reversed', tickfont=dict(size=10), showticklabels=True, ticklabelstandoff=15, fixedrange=True), - xaxis1=dict(title='Max confidence', showticklabels=False, title_font=dict(size=10), fixedrange=True), - xaxis2=dict(title='Total counts', showticklabels=False, title_font=dict(size=10), fixedrange=True), - xaxis3=dict(title='Hour', tickfont=dict(size=10), tickmode='linear', dtick=1, fixedrange=True), - margin=dict(l=20, r=20, t=80, b=80), clickmode='event+select', - plot_bgcolor='#CCCCCC', paper_bgcolor='#7F7F7F', font=dict(size=10), dragmode=False + yaxis=dict(autorange='reversed', tickfont=dict(size=12), showticklabels=True, ticklabelstandoff=15, fixedrange=True), + xaxis1=dict(title='Max Confidence', showticklabels=False, title_font=dict(size=12), fixedrange=True), + xaxis2=dict(title='Total Counts', showticklabels=False, title_font=dict(size=12), fixedrange=True), + xaxis3=dict(title='Hour', tickfont=dict(size=12), tickmode='linear', dtick=1, fixedrange=True), + margin=dict(l=20, r=20, t=80, b=80), clickmode='event+select', + plot_bgcolor=PAPER_BGCOLOR, + paper_bgcolor=PAPER_BGCOLOR, + font=dict(size=12, color='#000000'), dragmode=False ) fig.update_xaxes(showgrid=False, zeroline=False) fig.update_yaxes(showgrid=False, zeroline=False) @@ -197,6 +221,3 @@ def create_plotly_heatmap(df_birds, now): os.makedirs(output_dir, exist_ok=True) with open(os.path.join(output_dir, 'interactive_daily_plot.html'), 'w') as f: f.write(html_str) - - # Clear figure to reset layout and prevent issues in future runs - fig.clear()