mktgtech commited on
Commit
fdce7f7
·
verified ·
1 Parent(s): 1a95af5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +48 -32
app.py CHANGED
@@ -1,5 +1,6 @@
1
  import pandas as pd
2
  import gradio as gr
 
3
  import io
4
 
5
  # Helper function for categorization
@@ -23,11 +24,12 @@ def process_data(file):
23
  first_sheet = excel.sheet_names[0]
24
  df = pd.read_excel(file.name, sheet_name=first_sheet)
25
 
26
- # Clean and Standardize Columns
27
  df.columns = df.columns.map(lambda x: str(x).strip())
28
  non_date_cols = ["Keyword", "Avg. monthly searches"]
29
  available_non_date = [c for c in non_date_cols if c in df.columns]
30
 
 
31
  potential_date_cols = [col for col in df.columns if col not in non_date_cols and "Unnamed" not in col]
32
  rename_dict = {}
33
  for col in potential_date_cols:
@@ -41,7 +43,7 @@ def process_data(file):
41
  df.rename(columns=rename_dict, inplace=True)
42
  date_cols = list(rename_dict.values())
43
 
44
- # Build Visualization Data
45
  final_df = df[available_non_date].copy()
46
  viz_data = []
47
 
@@ -56,56 +58,69 @@ def process_data(file):
56
  counts['Month'] = col
57
  viz_data.append(counts)
58
 
59
- full_viz_df = pd.concat(viz_data)
60
 
61
- # Sort SEO buckets correctly
62
- sort_order = ["01–03", "04–10", "11–20", "21–30", "31–40", "41–50", "51–100", "100+", "Not Talking (Intent Not Correct)"]
63
- full_viz_df['Range'] = pd.Categorical(full_viz_df['Range'], categories=sort_order, ordered=True)
64
- full_viz_df = full_viz_df.sort_values(['Range', 'Month'])
 
 
65
 
66
- return final_df, full_viz_df, final_df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
  def filter_table(full_data, selection_data: gr.SelectData):
69
- # When clicking a bar, selection_data.value[0] is the X-axis value (The Range, e.g., "01-03")
70
- if not selection_data or not selection_data.value:
71
- return full_data
72
-
73
- clicked_range = selection_data.value[0]
74
 
75
- # Filter Logic: Find rows where this range appears in ANY month column
76
- range_cols = [c for c in full_data.columns if "Rank Range" in c]
 
 
77
 
78
- if not range_cols:
79
- return full_data
80
-
81
- # We filter the master dataframe to show keywords that have this rank in any tracked month
 
 
 
 
82
  filtered_df = full_data[full_data[range_cols].apply(lambda row: clicked_range in row.values, axis=1)]
83
  return filtered_df
84
 
85
  def reset_table(full_data):
86
  return full_data
87
 
88
- with gr.Blocks() as demo:
89
  full_data_state = gr.State()
90
 
91
  gr.Markdown("# 🚀 SEO Market Intelligence Dashboard")
92
- gr.Markdown("### Click a bar segment below to filter the keyword list.")
93
 
94
  with gr.Row():
95
  file_input = gr.File(label="Upload SEO Excel", file_types=[".xlsx"])
96
  with gr.Column():
97
  process_btn = gr.Button("📊 Build Dashboard", variant="primary")
98
- reset_btn = gr.Button("🔄 Reset Table Filters")
99
 
100
- # FIX: Removed 'group' and 'vertical' arguments.
101
- # 'color' handles the segmentation automatically.
102
- plot_output = gr.BarPlot(
103
- x="Range",
104
- y="Keyword Count",
105
- color="Month",
106
- title="Keyword Performance Distribution",
107
- tooltip=["Month", "Range", "Keyword Count"]
108
- )
109
 
110
  gr.Markdown("### 🔍 Keywords List")
111
  table_output = gr.DataFrame(interactive=False)
@@ -116,6 +131,7 @@ with gr.Blocks() as demo:
116
  outputs=[table_output, plot_output, full_data_state]
117
  )
118
 
 
119
  plot_output.select(
120
  fn=filter_table,
121
  inputs=[full_data_state],
@@ -129,4 +145,4 @@ with gr.Blocks() as demo:
129
  )
130
 
131
  if __name__ == "__main__":
132
- demo.launch(theme=gr.themes.Soft())
 
1
  import pandas as pd
2
  import gradio as gr
3
+ import plotly.express as px
4
  import io
5
 
6
  # Helper function for categorization
 
24
  first_sheet = excel.sheet_names[0]
25
  df = pd.read_excel(file.name, sheet_name=first_sheet)
26
 
27
+ # 1. Standardize Columns
28
  df.columns = df.columns.map(lambda x: str(x).strip())
29
  non_date_cols = ["Keyword", "Avg. monthly searches"]
30
  available_non_date = [c for c in non_date_cols if c in df.columns]
31
 
32
+ # 2. Identify and Rename Date Columns
33
  potential_date_cols = [col for col in df.columns if col not in non_date_cols and "Unnamed" not in col]
34
  rename_dict = {}
35
  for col in potential_date_cols:
 
43
  df.rename(columns=rename_dict, inplace=True)
44
  date_cols = list(rename_dict.values())
45
 
46
+ # 3. Build Visualization Data
47
  final_df = df[available_non_date].copy()
48
  viz_data = []
49
 
 
58
  counts['Month'] = col
59
  viz_data.append(counts)
60
 
61
+ full_viz_df = pd.concat(viz_data) if viz_data else pd.DataFrame()
62
 
63
+ # 4. Enforce Exact Sorting Order
64
+ # We define the list explicitly so Plotly knows "04-10" comes after "01-03"
65
+ correct_order = [
66
+ "01–03", "04–10", "11–20", "21–30", "31–40",
67
+ "41–50", "51–100", "100+", "Not Talking (Intent Not Correct)"
68
+ ]
69
 
70
+ # Create the Chart
71
+ if not full_viz_df.empty:
72
+ fig = px.bar(
73
+ full_viz_df,
74
+ x='Range',
75
+ y='Keyword Count',
76
+ color='Month',
77
+ barmode='group', # <--- This creates the 3 separate bars side-by-side
78
+ text_auto=True,
79
+ title="Keyword Performance Distribution (Grouped)",
80
+ category_orders={"Range": correct_order} # <--- This fixes the sorting
81
+ )
82
+ fig.update_layout(clickmode='event+select')
83
+ else:
84
+ fig = None
85
+
86
+ return final_df, fig, final_df
87
 
88
  def filter_table(full_data, selection_data: gr.SelectData):
89
+ if not selection_data: return full_data
 
 
 
 
90
 
91
+ # Get the clicked category (e.g., "04-10")
92
+ clicked_range = selection_data.value['x']
93
+ # Get the clicked series (e.g., "27_Oct_2025") from the legend group
94
+ clicked_month = selection_data.value.get('legendgroup', None)
95
 
96
+ # If we know the month, filter by that specific month's column
97
+ if clicked_month:
98
+ target_col = f"{clicked_month}_Rank Range"
99
+ if target_col in full_data.columns:
100
+ return full_data[full_data[target_col] == clicked_range]
101
+
102
+ # Fallback: Filter where range appears in ANY month
103
+ range_cols = [c for c in full_data.columns if "Rank Range" in c]
104
  filtered_df = full_data[full_data[range_cols].apply(lambda row: clicked_range in row.values, axis=1)]
105
  return filtered_df
106
 
107
  def reset_table(full_data):
108
  return full_data
109
 
110
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
111
  full_data_state = gr.State()
112
 
113
  gr.Markdown("# 🚀 SEO Market Intelligence Dashboard")
114
+ gr.Markdown("Upload your file. The chart will show **3 side-by-side bars** for each rank range.")
115
 
116
  with gr.Row():
117
  file_input = gr.File(label="Upload SEO Excel", file_types=[".xlsx"])
118
  with gr.Column():
119
  process_btn = gr.Button("📊 Build Dashboard", variant="primary")
120
+ reset_btn = gr.Button("🔄 Reset Filters")
121
 
122
+ # We use gr.Plot because it supports the 'barmode' grouping we need
123
+ plot_output = gr.Plot(label="Interactive Chart")
 
 
 
 
 
 
 
124
 
125
  gr.Markdown("### 🔍 Keywords List")
126
  table_output = gr.DataFrame(interactive=False)
 
131
  outputs=[table_output, plot_output, full_data_state]
132
  )
133
 
134
+ # Interactive filtering
135
  plot_output.select(
136
  fn=filter_table,
137
  inputs=[full_data_state],
 
145
  )
146
 
147
  if __name__ == "__main__":
148
+ demo.launch()