GuglielmoTor commited on
Commit
348bc84
·
verified ·
1 Parent(s): b7a0e8c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +26 -36
app.py CHANGED
@@ -26,7 +26,6 @@ from analytics_data_processing import prepare_filtered_analytics_data
26
  from analytics_plot_generator import (
27
  generate_posts_activity_plot, generate_engagement_type_plot,
28
  generate_mentions_activity_plot, generate_mention_sentiment_plot,
29
- # generate_total_follower_growth_plot, # Kept for reference, decide if needed
30
  generate_followers_count_over_time_plot,
31
  generate_followers_growth_rate_plot,
32
  generate_followers_by_demographics_plot,
@@ -49,20 +48,17 @@ def update_analytics_plots(token_state_value, date_filter_option, custom_start_d
49
  if not token_state_value or not token_state_value.get("token"):
50
  message = "❌ Access denied. No token. Cannot generate analytics."
51
  logging.warning(message)
52
- # Return placeholders for all plots
53
- num_expected_plots = 13 # Number of plots we expect to generate
54
  placeholder_figs = [create_placeholder_plot(title="Access Denied", message="No token.") for _ in range(num_expected_plots)]
55
  return [message] + placeholder_figs
56
 
57
- # --- Prepare Data ---
58
  try:
59
- # Updated unpacking to match prepare_filtered_analytics_data return signature
60
  (filtered_merged_posts_df,
61
  filtered_mentions_df,
62
  date_filtered_follower_stats_df,
63
  raw_follower_stats_df,
64
  start_dt_for_msg, end_dt_for_msg) = \
65
- prepare_filtered_analytics_data( # Direct call to imported function
66
  token_state_value, date_filter_option, custom_start_date, custom_end_date
67
  )
68
  except Exception as e:
@@ -72,47 +68,43 @@ def update_analytics_plots(token_state_value, date_filter_option, custom_start_d
72
  placeholder_figs = [create_placeholder_plot(title="Data Preparation Error", message=str(e)) for _ in range(num_expected_plots)]
73
  return [error_msg] + placeholder_figs
74
 
75
- # Date column names (still needed for plot generators if not passed as args or if defaults are not suitable)
76
  date_column_posts = token_state_value.get("config_date_col_posts", "published_at")
77
  date_column_mentions = token_state_value.get("config_date_col_mentions", "date")
78
- date_column_followers = token_state_value.get("config_date_col_followers", "date")
 
 
 
 
79
 
80
  logging.info(f"Data for plotting - Filtered Merged Posts: {len(filtered_merged_posts_df)} rows, Filtered Mentions: {len(filtered_mentions_df)} rows.")
81
  logging.info(f"Date-Filtered Follower Stats: {len(date_filtered_follower_stats_df)} rows, Raw Follower Stats: {len(raw_follower_stats_df)} rows.")
82
 
83
- # --- Generate Plots ---
84
  try:
85
- # Existing plots (using filtered_merged_posts_df for post-related plots)
86
  plot_posts_activity = generate_posts_activity_plot(filtered_merged_posts_df, date_column=date_column_posts)
87
- # Ensure likeCount, commentCount, shareCount are in filtered_merged_posts_df
88
  plot_engagement_type = generate_engagement_type_plot(filtered_merged_posts_df)
89
  plot_mentions_activity = generate_mentions_activity_plot(filtered_mentions_df, date_column=date_column_mentions)
90
  plot_mention_sentiment = generate_mention_sentiment_plot(filtered_mentions_df)
91
 
92
- # New Follower Dynamics Plots
93
  plot_followers_count = generate_followers_count_over_time_plot(
94
  date_filtered_follower_stats_df,
95
- date_column=date_column_followers, # Make sure 'date' is the correct column name
96
- count_column='follower_count_o', # Or relevant count column
97
- type_filter_column='follower_count_type',
98
- type_value='follower_gains_monthly' # As per your requirement
99
  )
100
  plot_followers_growth_rate = generate_followers_growth_rate_plot(
101
  date_filtered_follower_stats_df,
102
- date_column=date_column_followers,
103
- count_column='follower_count_o',
104
  type_filter_column='follower_count_type',
105
  type_value='follower_gains_monthly'
106
  )
107
 
108
- # New Follower Demographics Plots (using raw_follower_stats_df)
109
- plot_followers_by_location = generate_followers_by_demographics_plot(raw_follower_stats_df, category_col='category_name', count_column='follower_count_o', type_filter_column='follower_count_type', type_value='follower_geo', plot_title="Followers by Location")
110
- plot_followers_by_role = generate_followers_by_demographics_plot(raw_follower_stats_df, category_col='category_name', count_column='follower_count_o', type_filter_column='follower_count_type', type_value='follower_function', plot_title="Followers by Role")
111
- plot_followers_by_industry = generate_followers_by_demographics_plot(raw_follower_stats_df, category_col='category_name', count_column='follower_count_o', type_filter_column='follower_count_type', type_value='follower_industry', plot_title="Followers by Industry")
112
- plot_followers_by_seniority = generate_followers_by_demographics_plot(raw_follower_stats_df, category_col='category_name', count_column='follower_count_o', type_filter_column='follower_count_type', type_value='follower_seniority', plot_title="Followers by Seniority")
113
 
114
- # New Post Engagement/Performance Plots (using filtered_merged_posts_df)
115
- # Ensure 'engagement', 'clickCount', 'impressionCount' are in filtered_merged_posts_df
116
  plot_engagement_rate = generate_engagement_rate_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts, engagement_rate_col='engagement')
117
  plot_reach_over_time = generate_reach_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts, reach_col='clickCount')
118
  plot_impressions_over_time = generate_impressions_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts, impressions_col='impressionCount')
@@ -129,7 +121,7 @@ def update_analytics_plots(token_state_value, date_filter_option, custom_start_d
129
  plot_followers_by_location, plot_followers_by_role, plot_followers_by_industry, plot_followers_by_seniority,
130
  plot_engagement_rate, plot_reach_over_time, plot_impressions_over_time
131
  ]
132
- num_plots_generated = sum(1 for p in all_generated_plots if p is not None and not isinstance(p, str)) # Check it's a figure
133
  logging.info(f"Successfully generated {num_plots_generated} plots.")
134
 
135
  return [message] + all_generated_plots
@@ -148,14 +140,14 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
148
  token_state = gr.State(value={
149
  "token": None, "client_id": None, "org_urn": None,
150
  "bubble_posts_df": pd.DataFrame(),
151
- "bubble_post_stats_df": pd.DataFrame(), # Added for merged post data
152
  "bubble_mentions_df": pd.DataFrame(),
153
  "bubble_follower_stats_df": pd.DataFrame(),
154
- "fetch_count_for_api": 0, # Retained from original if used elsewhere
155
  "url_user_token_temp_storage": None,
156
  "config_date_col_posts": "published_at",
157
  "config_date_col_mentions": "date",
158
- "config_date_col_followers": "date"
159
  })
160
 
161
  gr.Markdown("# 🚀 LinkedIn Organization Dashboard")
@@ -168,7 +160,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
168
  def initial_load_sequence(url_token, org_urn_val, current_state):
169
  logging.info(f"Initial load sequence triggered. Org URN: {org_urn_val}, URL Token: {'Present' if url_token else 'Absent'}")
170
  status_msg, new_state, btn_update = process_and_store_bubble_token(url_token, org_urn_val, current_state)
171
- dashboard_content = display_main_dashboard(new_state) # Assumes this function exists and works
172
  return status_msg, new_state, btn_update, dashboard_content
173
 
174
  with gr.Tabs() as tabs:
@@ -254,13 +246,12 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
254
  followers_by_seniority_plot = gr.Plot(label="Followers by Seniority")
255
 
256
  gr.Markdown("### Post Performance Insights (Filtered by Date)")
257
- with gr.Row(): # Single plot, can take full width or be in a row
258
  engagement_rate_plot = gr.Plot(label="Engagement Rate Over Time")
259
  with gr.Row():
260
  reach_over_time_plot = gr.Plot(label="Reach Over Time (Clicks)")
261
  impressions_over_time_plot = gr.Plot(label="Impressions Over Time")
262
 
263
- # Define all plot outputs for the analytics tab
264
  analytics_plot_outputs = [
265
  analytics_status_md, posts_activity_plot, engagement_type_plot,
266
  mentions_activity_plot, mention_sentiment_plot,
@@ -277,8 +268,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
277
  show_progress="full"
278
  )
279
 
280
- # Also update analytics plots after a data sync
281
- sync_click_event.then( # Chaining after the sync operations
282
  fn=update_analytics_plots,
283
  inputs=[token_state, date_filter_selector, custom_start_date_picker, custom_end_date_picker],
284
  outputs=analytics_plot_outputs,
@@ -291,7 +281,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
291
  mentions_sentiment_dist_plot = gr.Plot(label="Mention Sentiment Distribution")
292
  refresh_mentions_display_btn.click(
293
  fn=run_mentions_tab_display, inputs=[token_state],
294
- outputs=[mentions_html, mentions_sentiment_dist_plot], # Assuming run_mentions_tab_display returns these
295
  show_progress="full"
296
  )
297
 
@@ -306,7 +296,7 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
306
 
307
  refresh_follower_stats_btn.click(
308
  fn=run_follower_stats_tab_display, inputs=[token_state],
309
- outputs=[follower_stats_html, fs_plot_monthly_gains, fs_plot_seniority, fs_plot_industry], # Assuming this matches
310
  show_progress="full"
311
  )
312
 
 
26
  from analytics_plot_generator import (
27
  generate_posts_activity_plot, generate_engagement_type_plot,
28
  generate_mentions_activity_plot, generate_mention_sentiment_plot,
 
29
  generate_followers_count_over_time_plot,
30
  generate_followers_growth_rate_plot,
31
  generate_followers_by_demographics_plot,
 
48
  if not token_state_value or not token_state_value.get("token"):
49
  message = "❌ Access denied. No token. Cannot generate analytics."
50
  logging.warning(message)
51
+ num_expected_plots = 13
 
52
  placeholder_figs = [create_placeholder_plot(title="Access Denied", message="No token.") for _ in range(num_expected_plots)]
53
  return [message] + placeholder_figs
54
 
 
55
  try:
 
56
  (filtered_merged_posts_df,
57
  filtered_mentions_df,
58
  date_filtered_follower_stats_df,
59
  raw_follower_stats_df,
60
  start_dt_for_msg, end_dt_for_msg) = \
61
+ prepare_filtered_analytics_data(
62
  token_state_value, date_filter_option, custom_start_date, custom_end_date
63
  )
64
  except Exception as e:
 
68
  placeholder_figs = [create_placeholder_plot(title="Data Preparation Error", message=str(e)) for _ in range(num_expected_plots)]
69
  return [error_msg] + placeholder_figs
70
 
 
71
  date_column_posts = token_state_value.get("config_date_col_posts", "published_at")
72
  date_column_mentions = token_state_value.get("config_date_col_mentions", "date")
73
+ # This 'date_column_followers' from token_state is for the *source* DataFrame's date column,
74
+ # but the plot generator now uses 'date_info_column' for the 'category_name' that holds date strings.
75
+ # We'll use the default 'category_name' in the plot functions directly.
76
+ # config_date_col_followers_source = token_state_value.get("config_date_col_followers", "date")
77
+
78
 
79
  logging.info(f"Data for plotting - Filtered Merged Posts: {len(filtered_merged_posts_df)} rows, Filtered Mentions: {len(filtered_mentions_df)} rows.")
80
  logging.info(f"Date-Filtered Follower Stats: {len(date_filtered_follower_stats_df)} rows, Raw Follower Stats: {len(raw_follower_stats_df)} rows.")
81
 
 
82
  try:
 
83
  plot_posts_activity = generate_posts_activity_plot(filtered_merged_posts_df, date_column=date_column_posts)
 
84
  plot_engagement_type = generate_engagement_type_plot(filtered_merged_posts_df)
85
  plot_mentions_activity = generate_mentions_activity_plot(filtered_mentions_df, date_column=date_column_mentions)
86
  plot_mention_sentiment = generate_mention_sentiment_plot(filtered_mentions_df)
87
 
88
+ # Corrected calls for follower plots: use date_info_column (defaults to 'category_name' in plot generator)
89
  plot_followers_count = generate_followers_count_over_time_plot(
90
  date_filtered_follower_stats_df,
91
+ # date_info_column is defaulted in the function to 'category_name'
92
+ # organic_count_col, paid_count_col are defaulted
93
+ type_filter_column='follower_count_type', # Ensure this column exists
94
+ type_value='follower_gains_monthly'
95
  )
96
  plot_followers_growth_rate = generate_followers_growth_rate_plot(
97
  date_filtered_follower_stats_df,
98
+ # date_info_column is defaulted
 
99
  type_filter_column='follower_count_type',
100
  type_value='follower_gains_monthly'
101
  )
102
 
103
+ plot_followers_by_location = generate_followers_by_demographics_plot(raw_follower_stats_df, category_col='category_name', type_filter_column='follower_count_type', type_value='follower_geo', plot_title="Followers by Location")
104
+ plot_followers_by_role = generate_followers_by_demographics_plot(raw_follower_stats_df, category_col='category_name', type_filter_column='follower_count_type', type_value='follower_function', plot_title="Followers by Role")
105
+ plot_followers_by_industry = generate_followers_by_demographics_plot(raw_follower_stats_df, category_col='category_name', type_filter_column='follower_count_type', type_value='follower_industry', plot_title="Followers by Industry")
106
+ plot_followers_by_seniority = generate_followers_by_demographics_plot(raw_follower_stats_df, category_col='category_name', type_filter_column='follower_count_type', type_value='follower_seniority', plot_title="Followers by Seniority")
 
107
 
 
 
108
  plot_engagement_rate = generate_engagement_rate_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts, engagement_rate_col='engagement')
109
  plot_reach_over_time = generate_reach_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts, reach_col='clickCount')
110
  plot_impressions_over_time = generate_impressions_over_time_plot(filtered_merged_posts_df, date_column=date_column_posts, impressions_col='impressionCount')
 
121
  plot_followers_by_location, plot_followers_by_role, plot_followers_by_industry, plot_followers_by_seniority,
122
  plot_engagement_rate, plot_reach_over_time, plot_impressions_over_time
123
  ]
124
+ num_plots_generated = sum(1 for p in all_generated_plots if p is not None and not isinstance(p, str))
125
  logging.info(f"Successfully generated {num_plots_generated} plots.")
126
 
127
  return [message] + all_generated_plots
 
140
  token_state = gr.State(value={
141
  "token": None, "client_id": None, "org_urn": None,
142
  "bubble_posts_df": pd.DataFrame(),
143
+ "bubble_post_stats_df": pd.DataFrame(),
144
  "bubble_mentions_df": pd.DataFrame(),
145
  "bubble_follower_stats_df": pd.DataFrame(),
146
+ "fetch_count_for_api": 0,
147
  "url_user_token_temp_storage": None,
148
  "config_date_col_posts": "published_at",
149
  "config_date_col_mentions": "date",
150
+ "config_date_col_followers": "date" # This is for the original follower data's date column, if different from category_name for time series
151
  })
152
 
153
  gr.Markdown("# 🚀 LinkedIn Organization Dashboard")
 
160
  def initial_load_sequence(url_token, org_urn_val, current_state):
161
  logging.info(f"Initial load sequence triggered. Org URN: {org_urn_val}, URL Token: {'Present' if url_token else 'Absent'}")
162
  status_msg, new_state, btn_update = process_and_store_bubble_token(url_token, org_urn_val, current_state)
163
+ dashboard_content = display_main_dashboard(new_state)
164
  return status_msg, new_state, btn_update, dashboard_content
165
 
166
  with gr.Tabs() as tabs:
 
246
  followers_by_seniority_plot = gr.Plot(label="Followers by Seniority")
247
 
248
  gr.Markdown("### Post Performance Insights (Filtered by Date)")
249
+ with gr.Row():
250
  engagement_rate_plot = gr.Plot(label="Engagement Rate Over Time")
251
  with gr.Row():
252
  reach_over_time_plot = gr.Plot(label="Reach Over Time (Clicks)")
253
  impressions_over_time_plot = gr.Plot(label="Impressions Over Time")
254
 
 
255
  analytics_plot_outputs = [
256
  analytics_status_md, posts_activity_plot, engagement_type_plot,
257
  mentions_activity_plot, mention_sentiment_plot,
 
268
  show_progress="full"
269
  )
270
 
271
+ sync_click_event.then(
 
272
  fn=update_analytics_plots,
273
  inputs=[token_state, date_filter_selector, custom_start_date_picker, custom_end_date_picker],
274
  outputs=analytics_plot_outputs,
 
281
  mentions_sentiment_dist_plot = gr.Plot(label="Mention Sentiment Distribution")
282
  refresh_mentions_display_btn.click(
283
  fn=run_mentions_tab_display, inputs=[token_state],
284
+ outputs=[mentions_html, mentions_sentiment_dist_plot],
285
  show_progress="full"
286
  )
287
 
 
296
 
297
  refresh_follower_stats_btn.click(
298
  fn=run_follower_stats_tab_display, inputs=[token_state],
299
+ outputs=[follower_stats_html, fs_plot_monthly_gains, fs_plot_seniority, fs_plot_industry],
300
  show_progress="full"
301
  )
302