antonymilne Claude commited on
Commit
a4e7aa2
·
1 Parent(s): 0511d44

Refactor overview charts with shared helper functions

Browse files

- Extract common aggregation logic into _aggregate_data helper
- Extract year relabeling logic into _relabel_years helper
- Create _create_year_comparison_bar_chart for segment and category charts
- Refactor overview_by_customer_segment to use px.bar instead of go.Figure
- Refactor overview_by_product_category to use px.bar instead of go.Figure
- Update parameter names from value_col to column for consistency
- Eliminate 76 lines of duplicated code

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

Files changed (2) hide show
  1. app.py +2 -2
  2. charts.py +31 -106
app.py CHANGED
@@ -114,10 +114,10 @@ overview_page = vm.Page(
114
  selector=vm.RadioItems(options=["Sales", "Profit", "Order ID", "Customer ID"]),
115
  targets=[
116
  "region_bar_chart.value_col",
117
- "category_bar_chart.value_col",
118
  "order_status_pie_chart.column",
119
  "month_line_chart.column",
120
- "segment_bar_chart.value_col",
121
  ],
122
  visible=False,
123
  )
 
114
  selector=vm.RadioItems(options=["Sales", "Profit", "Order ID", "Customer ID"]),
115
  targets=[
116
  "region_bar_chart.value_col",
117
+ "category_bar_chart.column",
118
  "order_status_pie_chart.column",
119
  "month_line_chart.column",
120
+ "segment_bar_chart.column",
121
  ],
122
  visible=False,
123
  )
charts.py CHANGED
@@ -169,123 +169,48 @@ def overview_by_region(data_frame, value_col="Sales"):
169
  return fig
170
 
171
 
172
- @capture("graph")
173
- def overview_by_customer_segment(data_frame, value_col="Sales"):
174
- """Custom bar chart made with Plotly."""
175
- data_frame["Order Date"] = pd.to_datetime(data_frame["Order Date"])
176
- data_frame["Year"] = data_frame["Order Date"].dt.year
177
-
178
- if value_col == "Order ID":
179
- agg_df = (
180
- data_frame.groupby(["Segment", "Year"], as_index=False)["Order ID"]
181
- .nunique()
182
- .rename(columns={"Order ID": "Orders"})
183
- )
184
- agg_col = "Orders"
185
- elif value_col == "Customer ID":
186
- agg_df = (
187
- data_frame.groupby(["Segment", "Year"], as_index=False)["Customer ID"]
188
- .nunique()
189
- .rename(columns={"Customer ID": "Customers"})
190
- )
191
- agg_col = "Customers"
192
- else:
193
- agg_df = data_frame.groupby(["Segment", "Year"], as_index=False)[value_col].sum()
194
- agg_col = value_col
195
 
196
- pivot_df = agg_df.pivot_table(index="Segment", columns="Year", values=agg_col).reset_index()
197
 
198
- fig = go.Figure()
 
 
 
 
199
 
200
- if PREVIOUS_YEAR in pivot_df.columns:
201
- fig.add_trace(
202
- go.Bar(
203
- x=pivot_df["Segment"],
204
- y=pivot_df[PREVIOUS_YEAR],
205
- name="Previous year",
206
- marker_color=SECONDARY_COLOR,
207
- )
208
- )
209
 
210
- if CURRENT_YEAR in pivot_df.columns:
211
- fig.add_trace(
212
- go.Bar(
213
- x=pivot_df["Segment"],
214
- y=pivot_df[CURRENT_YEAR],
215
- name="Current year",
216
- marker_color=PRIMARY_COLOR,
217
- )
218
- )
219
 
220
- fig.update_layout(
 
 
 
 
221
  barmode="group",
222
- xaxis_title=None,
223
- yaxis_title=None,
224
- bargap=0.4,
225
- title=f"{agg_col} | By Customer Segment",
226
- showlegend=False,
227
  )
228
 
 
 
229
  return fig
230
 
231
 
232
  @capture("graph")
233
- def overview_by_product_category(data_frame, value_col="Sales"):
234
- """Bar chart comparing current year vs previous year by category."""
235
- data_frame["Year"] = data_frame["Order Date"].dt.year
236
 
237
- if value_col == "Order ID":
238
- agg_df = (
239
- data_frame.groupby(["Category", "Year"], as_index=False)["Order ID"]
240
- .nunique()
241
- .rename(columns={"Order ID": "Orders"})
242
- )
243
- agg_col = "Orders"
244
- elif value_col == "Customer ID":
245
- agg_df = (
246
- data_frame.groupby(["Category", "Year"], as_index=False)["Customer ID"]
247
- .nunique()
248
- .rename(columns={"Customer ID": "Customers"})
249
- )
250
- agg_col = "Customers"
251
- else:
252
- agg_df = data_frame.groupby(["Category", "Year"], as_index=False)[value_col].sum()
253
- agg_col = value_col
254
-
255
- pivot_df = agg_df.pivot_table(index="Category", columns="Year", values=agg_col).reset_index()
256
-
257
- fig = go.Figure()
258
-
259
- if PREVIOUS_YEAR in pivot_df.columns:
260
- fig.add_trace(
261
- go.Bar(
262
- x=pivot_df["Category"],
263
- y=pivot_df[PREVIOUS_YEAR],
264
- name="Previous year",
265
- marker_color=SECONDARY_COLOR,
266
- )
267
- )
268
-
269
- if CURRENT_YEAR in pivot_df.columns:
270
- fig.add_trace(
271
- go.Bar(
272
- x=pivot_df["Category"],
273
- y=pivot_df[CURRENT_YEAR],
274
- name="Current year",
275
- marker_color=PRIMARY_COLOR,
276
- )
277
- )
278
-
279
- fig.update_layout(
280
- barmode="group",
281
- xaxis_title=None,
282
- yaxis_title=None,
283
- bargap=0.4,
284
- title=f"{agg_col} | By Product Category",
285
- showlegend=False,
286
- )
287
 
288
- return fig
 
 
 
289
 
290
 
291
  import calendar
@@ -293,10 +218,10 @@ import calendar
293
 
294
  @capture("graph")
295
  def overview_by_month(data_frame, column="Sales"):
296
- grouped_df = data_frame.groupby(["Year", "Month"], as_index=False).agg({column: COLUMN_TO_AGGFUNC[column]})
297
  # Relabel for plotting in human-readable way.
298
  grouped_df["Month"] = grouped_df["Month"].map({i: calendar.month_abbr[i] for i in range(1, 13)})
299
- grouped_df["Year"] = grouped_df["Year"].map({THIS_YEAR: "This year", LAST_YEAR: "Last year"})
300
 
301
  fig = px.line(
302
  grouped_df,
@@ -319,7 +244,7 @@ def overview_by_month(data_frame, column="Sales"):
319
 
320
  @capture("graph")
321
  def overview_by_order_status(data_frame, column="Sales"):
322
- grouped_df = data_frame.groupby("Order Status", as_index=False).agg({column: COLUMN_TO_AGGFUNC[column]})
323
 
324
  fig = px.pie(
325
  grouped_df,
 
169
  return fig
170
 
171
 
172
+ def _aggregate_data(data_frame, group_columns, column):
173
+ """Aggregate data using the appropriate function for the column."""
174
+ return data_frame.groupby(group_columns, as_index=False).agg({column: COLUMN_TO_AGGFUNC[column]})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
 
 
176
 
177
+ # TODO: move to data_processing?
178
+ def _relabel_years(data_frame):
179
+ """Relabel years for human-readable plotting."""
180
+ data_frame["Year"] = data_frame["Year"].map({THIS_YEAR: "This year", LAST_YEAR: "Last year"})
181
+ return data_frame
182
 
 
 
 
 
 
 
 
 
 
183
 
184
+ def _create_year_comparison_bar_chart(data_frame, group_column, column, title_suffix):
185
+ """Helper function to create a grouped bar chart comparing years."""
186
+ grouped_df = _aggregate_data(data_frame, [group_column, "Year"], column)
187
+ grouped_df = _relabel_years(grouped_df)
 
 
 
 
 
188
 
189
+ fig = px.bar(
190
+ grouped_df,
191
+ x=group_column,
192
+ y=column,
193
+ color="Year",
194
  barmode="group",
195
+ title=f"{COLUMN_TO_METRIC[column]} | {title_suffix}",
196
+ color_discrete_map={"This year": PRIMARY_COLOR, "Last year": SECONDARY_COLOR},
 
 
 
197
  )
198
 
199
+ fig.update_layout(xaxis_title=None, yaxis_title=None, bargap=0.4, showlegend=False)
200
+
201
  return fig
202
 
203
 
204
  @capture("graph")
205
+ def overview_by_customer_segment(data_frame, column="Sales"):
206
+ """Bar chart comparing current year vs previous year by customer segment."""
207
+ return _create_year_comparison_bar_chart(data_frame, "Segment", column, "By Customer Segment")
208
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
 
210
+ @capture("graph")
211
+ def overview_by_product_category(data_frame, column="Sales"):
212
+ """Bar chart comparing current year vs previous year by category."""
213
+ return _create_year_comparison_bar_chart(data_frame, "Category", column, "By Product Category")
214
 
215
 
216
  import calendar
 
218
 
219
  @capture("graph")
220
  def overview_by_month(data_frame, column="Sales"):
221
+ grouped_df = _aggregate_data(data_frame, ["Year", "Month"], column)
222
  # Relabel for plotting in human-readable way.
223
  grouped_df["Month"] = grouped_df["Month"].map({i: calendar.month_abbr[i] for i in range(1, 13)})
224
+ grouped_df = _relabel_years(grouped_df)
225
 
226
  fig = px.line(
227
  grouped_df,
 
244
 
245
  @capture("graph")
246
  def overview_by_order_status(data_frame, column="Sales"):
247
+ grouped_df = _aggregate_data(data_frame, "Order Status", column)
248
 
249
  fig = px.pie(
250
  grouped_df,