Spaces:
Running
Running
Update analytics_plot_generator.py
Browse files- analytics_plot_generator.py +131 -0
analytics_plot_generator.py
CHANGED
@@ -7,6 +7,7 @@ import numpy as np
|
|
7 |
import matplotlib.ticker as mticker
|
8 |
import matplotlib.patches as patches # Added for rounded corners
|
9 |
import ast # For safely evaluating string representations of lists
|
|
|
10 |
|
11 |
# Configure logging for this module
|
12 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(module)s - %(message)s')
|
@@ -839,3 +840,133 @@ def generate_content_topic_breakdown_plot(df, topics_col='li_eb_labels', top_n=1
|
|
839 |
logging.error(f"Error generating {title}: {e}", exc_info=True)
|
840 |
if fig: plt.close(fig)
|
841 |
return create_placeholder_plot(title=f"{title} Error", message=str(e))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
import matplotlib.ticker as mticker
|
8 |
import matplotlib.patches as patches # Added for rounded corners
|
9 |
import ast # For safely evaluating string representations of lists
|
10 |
+
from analytics_data_processing import generate_chatbot_data_summaries
|
11 |
|
12 |
# Configure logging for this module
|
13 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(module)s - %(message)s')
|
|
|
840 |
logging.error(f"Error generating {title}: {e}", exc_info=True)
|
841 |
if fig: plt.close(fig)
|
842 |
return create_placeholder_plot(title=f"{title} Error", message=str(e))
|
843 |
+
|
844 |
+
|
845 |
+
# --- Analytics Tab: Plot Figure Generation Function ---
|
846 |
+
def update_analytics_plots_figures(token_state_value, date_filter_option, custom_start_date, custom_end_date, current_plot_configs):
|
847 |
+
logging.info(f"Updating analytics plot figures. Filter: {date_filter_option}, Custom Start: {custom_start_date}, Custom End: {custom_end_date}")
|
848 |
+
num_expected_plots = 19 # Ensure this matches the number of plots generated
|
849 |
+
|
850 |
+
plot_data_summaries_for_chatbot = {} # Initialize dict for chatbot summaries
|
851 |
+
|
852 |
+
if not token_state_value or not token_state_value.get("token"):
|
853 |
+
message = "❌ Accesso negato. Nessun token. Impossibile generare le analisi."
|
854 |
+
logging.warning(message)
|
855 |
+
placeholder_figs = [create_placeholder_plot(title="Accesso Negato", message="Nessun token.") for _ in range(num_expected_plots)]
|
856 |
+
# For each plot_config, add a default "no data" summary
|
857 |
+
for p_cfg in current_plot_configs:
|
858 |
+
plot_data_summaries_for_chatbot[p_cfg["id"]] = "Accesso negato, nessun dato per il chatbot."
|
859 |
+
return [message] + placeholder_figs + [plot_data_summaries_for_chatbot]
|
860 |
+
try:
|
861 |
+
(filtered_merged_posts_df,
|
862 |
+
filtered_mentions_df,
|
863 |
+
date_filtered_follower_stats_df, # For time-based follower plots
|
864 |
+
raw_follower_stats_df, # For demographic follower plots
|
865 |
+
start_dt_for_msg, end_dt_for_msg) = \
|
866 |
+
prepare_filtered_analytics_data(
|
867 |
+
token_state_value, date_filter_option, custom_start_date, custom_end_date
|
868 |
+
)
|
869 |
+
|
870 |
+
# Generate data summaries for chatbot AFTER data preparation
|
871 |
+
plot_data_summaries_for_chatbot = generate_chatbot_data_summaries(
|
872 |
+
current_plot_configs, # Pass the plot_configs list
|
873 |
+
filtered_merged_posts_df,
|
874 |
+
filtered_mentions_df,
|
875 |
+
date_filtered_follower_stats_df,
|
876 |
+
raw_follower_stats_df,
|
877 |
+
token_state_value
|
878 |
+
)
|
879 |
+
|
880 |
+
except Exception as e:
|
881 |
+
error_msg = f"❌ Errore durante la preparazione dei dati per le analisi: {e}"
|
882 |
+
logging.error(error_msg, exc_info=True)
|
883 |
+
placeholder_figs = [create_placeholder_plot(title="Errore Preparazione Dati", message=str(e)) for _ in range(num_expected_plots)]
|
884 |
+
for p_cfg in current_plot_configs:
|
885 |
+
plot_data_summaries_for_chatbot[p_cfg["id"]] = f"Errore preparazione dati: {e}"
|
886 |
+
return [error_msg] + placeholder_figs + [plot_data_summaries_for_chatbot]
|
887 |
+
|
888 |
+
date_column_posts = token_state_value.get("config_date_col_posts", "published_at")
|
889 |
+
date_column_mentions = token_state_value.get("config_date_col_mentions", "date")
|
890 |
+
media_type_col_name = token_state_value.get("config_media_type_col", "media_type")
|
891 |
+
eb_labels_col_name = token_state_value.get("config_eb_labels_col", "li_eb_label")
|
892 |
+
|
893 |
+
plot_figs = [] # Initialize list to hold plot figures
|
894 |
+
|
895 |
+
plot_titles_for_errors = [p_cfg["label"] for p_cfg in current_plot_configs]
|
896 |
+
|
897 |
+
try:
|
898 |
+
# Dinamiche dei Follower (2 plots)
|
899 |
+
plot_figs.append(generate_followers_count_over_time_plot(date_filtered_follower_stats_df, type_value='follower_gains_monthly'))
|
900 |
+
plot_figs.append(generate_followers_growth_rate_plot(date_filtered_follower_stats_df, type_value='follower_gains_monthly')) # Assuming this uses 'follower_gains_monthly' to calculate rate
|
901 |
+
|
902 |
+
# Demografia Follower (4 plots)
|
903 |
+
plot_figs.append(generate_followers_by_demographics_plot(raw_follower_stats_df, type_value='follower_geo', plot_title="Follower per Località"))
|
904 |
+
plot_figs.append(generate_followers_by_demographics_plot(raw_follower_stats_df, type_value='follower_function', plot_title="Follower per Ruolo"))
|
905 |
+
plot_figs.append(generate_followers_by_demographics_plot(raw_follower_stats_df, type_value='follower_industry', plot_title="Follower per Settore"))
|
906 |
+
plot_figs.append(generate_followers_by_demographics_plot(raw_follower_stats_df, type_value='follower_seniority', plot_title="Follower per Anzianità"))
|
907 |
+
|
908 |
+
# Approfondimenti Performance Post (4 plots)
|
909 |
+
plot_figs.append(generate_engagement_rate_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts))
|
910 |
+
plot_figs.append(generate_reach_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts))
|
911 |
+
plot_figs.append(generate_impressions_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts)) # Ensure 'impressions_sum' or equivalent is used by this func
|
912 |
+
plot_figs.append(generate_likes_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts))
|
913 |
+
|
914 |
+
# Engagement Dettagliato Post nel Tempo (4 plots)
|
915 |
+
plot_figs.append(generate_clicks_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts))
|
916 |
+
plot_figs.append(generate_shares_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts))
|
917 |
+
plot_figs.append(generate_comments_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts))
|
918 |
+
plot_figs.append(generate_comments_sentiment_breakdown_plot(filtered_merged_posts_df, sentiment_column='comment_sentiment')) # Make sure 'comment_sentiment' exists
|
919 |
+
|
920 |
+
# Analisi Strategia Contenuti (3 plots)
|
921 |
+
plot_figs.append(generate_post_frequency_plot(filtered_merged_posts_df, date_column=date_column_posts))
|
922 |
+
plot_figs.append(generate_content_format_breakdown_plot(filtered_merged_posts_df, format_col=media_type_col_name))
|
923 |
+
plot_figs.append(generate_content_topic_breakdown_plot(filtered_merged_posts_df, topics_col=eb_labels_col_name))
|
924 |
+
|
925 |
+
# Analisi Menzioni (Dettaglio) (2 plots)
|
926 |
+
plot_figs.append(generate_mentions_activity_plot(filtered_mentions_df, date_column=date_column_mentions))
|
927 |
+
plot_figs.append(generate_mention_sentiment_plot(filtered_mentions_df)) # Make sure this function handles empty/malformed df
|
928 |
+
|
929 |
+
if len(plot_figs) != num_expected_plots:
|
930 |
+
logging.warning(f"Mismatch in generated plots. Expected {num_expected_plots}, got {len(plot_figs)}. This will cause UI update issues.")
|
931 |
+
while len(plot_figs) < num_expected_plots:
|
932 |
+
plot_figs.append(create_placeholder_plot(title="Grafico Non Generato", message="Logica di generazione incompleta."))
|
933 |
+
|
934 |
+
message = f"📊 Analisi aggiornate per il periodo: {date_filter_option}"
|
935 |
+
if date_filter_option == "Intervallo Personalizzato":
|
936 |
+
s_display = start_dt_for_msg.strftime('%Y-%m-%d') if start_dt_for_msg else "Qualsiasi"
|
937 |
+
e_display = end_dt_for_msg.strftime('%Y-%m-%d') if end_dt_for_msg else "Qualsiasi"
|
938 |
+
message += f" (Da: {s_display} A: {e_display})"
|
939 |
+
|
940 |
+
final_plot_figs = []
|
941 |
+
for i, p_fig_candidate in enumerate(plot_figs):
|
942 |
+
if p_fig_candidate is not None and not isinstance(p_fig_candidate, str): # Basic check for a plot object
|
943 |
+
final_plot_figs.append(p_fig_candidate)
|
944 |
+
else:
|
945 |
+
err_title = plot_titles_for_errors[i] if i < len(plot_titles_for_errors) else f"Grafico {i+1}"
|
946 |
+
logging.warning(f"Plot {err_title} (index {i}) non è una figura valida: {p_fig_candidate}. Uso placeholder.")
|
947 |
+
final_plot_figs.append(create_placeholder_plot(title=f"Errore: {err_title}", message="Impossibile generare figura."))
|
948 |
+
|
949 |
+
return [message] + final_plot_figs[:num_expected_plots] + [plot_data_summaries_for_chatbot]
|
950 |
+
|
951 |
+
except (KeyError, ValueError) as e_plot_data:
|
952 |
+
logging.error(f"Errore dati durante la generazione di un grafico specifico: {e_plot_data}", exc_info=True)
|
953 |
+
error_msg_display = f"Errore dati in un grafico: {str(e_plot_data)[:100]}"
|
954 |
+
|
955 |
+
num_already_generated = len(plot_figs)
|
956 |
+
for i in range(num_already_generated, num_expected_plots):
|
957 |
+
err_title_fill = plot_titles_for_errors[i] if i < len(plot_titles_for_errors) else f"Grafico {i+1}"
|
958 |
+
plot_figs.append(create_placeholder_plot(title=f"Errore Dati: {err_title_fill}", message=f"Precedente errore: {str(e_plot_data)[:50]}"))
|
959 |
+
|
960 |
+
for p_cfg in current_plot_configs: # Ensure summaries dict is populated on error
|
961 |
+
if p_cfg["id"] not in plot_data_summaries_for_chatbot:
|
962 |
+
plot_data_summaries_for_chatbot[p_cfg["id"]] = f"Errore dati grafico: {e_plot_data}"
|
963 |
+
return [error_msg_display] + plot_figs[:num_expected_plots] + [plot_data_summaries_for_chatbot]
|
964 |
+
|
965 |
+
except Exception as e_general:
|
966 |
+
error_msg = f"❌ Errore generale durante la generazione dei grafici: {e_general}"
|
967 |
+
logging.error(error_msg, exc_info=True)
|
968 |
+
placeholder_figs_general = [create_placeholder_plot(title=plot_titles_for_errors[i] if i < len(plot_titles_for_errors) else f"Grafico {i+1}", message=str(e_general)) for i in range(num_expected_plots)]
|
969 |
+
for p_cfg in current_plot_configs: # Ensure summaries dict is populated on error
|
970 |
+
if p_cfg["id"] not in plot_data_summaries_for_chatbot:
|
971 |
+
plot_data_summaries_for_chatbot[p_cfg["id"]] = f"Errore generale grafici: {e_general}"
|
972 |
+
return [error_msg] + placeholder_figs_general + [plot_data_summaries_for_chatbot]
|