antonymilne Claude commited on
Commit
d267326
·
1 Parent(s): 756cace

Separate AG Grid tables from Plotly charts

Browse files

Move all AG Grid table functions and configurations from charts.py to new tables.py file for better code organization and separation of concerns.

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

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

__pycache__/charts.cpython-312.pyc CHANGED
Binary files a/__pycache__/charts.cpython-312.pyc and b/__pycache__/charts.cpython-312.pyc differ
 
__pycache__/data_processing.cpython-312.pyc ADDED
Binary file (3.44 kB). View file
 
app.py CHANGED
@@ -17,10 +17,9 @@ from charts import (
17
  scatter_with_quadrants,
18
  pie_chart_by_order_status,
19
  bar_chart_top_n,
20
- custom_orders_aggrid,
21
  create_lollipop_chart_by_region,
22
  )
23
- from charts import COLUMN_DEFS_PRODUCT, COLUMN_DEFS_CUSTOMERS
24
 
25
 
26
  ###############################################################################
@@ -250,7 +249,8 @@ customers_page = vm.Page(
250
  vm.Parameter(
251
  id="customer_parameter",
252
  targets=["pareto_chart.highlight_customer"],
253
- selector=vm.RadioItems(options=["NONE", *df["Customer Name"]], visible=False),
 
254
  ),
255
  ],
256
  )
 
17
  scatter_with_quadrants,
18
  pie_chart_by_order_status,
19
  bar_chart_top_n,
 
20
  create_lollipop_chart_by_region,
21
  )
22
+ from tables import COLUMN_DEFS_PRODUCT, COLUMN_DEFS_CUSTOMERS, custom_orders_aggrid
23
 
24
 
25
  ###############################################################################
 
249
  vm.Parameter(
250
  id="customer_parameter",
251
  targets=["pareto_chart.highlight_customer"],
252
+ selector=vm.RadioItems(options=["NONE", *df["Customer Name"]]),
253
+ visible=False,
254
  ),
255
  ],
256
  )
charts.py CHANGED
@@ -3,7 +3,6 @@
3
  import pandas as pd
4
  import plotly.graph_objects as go
5
  import vizro.plotly.express as px
6
- from dash_ag_grid import AgGrid
7
  from vizro.models.types import capture
8
 
9
  CURRENT_YEAR = 2017
@@ -394,10 +393,10 @@ def pie_chart_by_order_status(data_frame, value_col="Sales"):
394
 
395
  @capture("graph")
396
  def scatter_with_quadrants(
 
397
  x: str,
398
  y: str,
399
  custom_data: list[str],
400
- data_frame: pd.DataFrame = None,
401
  highlight_sub_category=None,
402
  ):
403
  """Custom scatter plot with quadrants grouped by Sub-Category."""
@@ -582,107 +581,6 @@ def pareto_customers_chart(data_frame, value_col="Sales", highlight_customer=Non
582
  return fig
583
 
584
 
585
- CELL_STYLE_PRODUCT = {
586
- "styleConditions": [
587
- {
588
- "condition": "params.value < -0.5",
589
- "style": {"backgroundColor": "#e33b3b"},
590
- },
591
- {
592
- "condition": "params.value >= -0.5 && params.value <= 0",
593
- "style": {"backgroundColor": "#f19791"},
594
- },
595
- {
596
- "condition": "params.value > 0 && params.value <= 0.30",
597
- "style": {"backgroundColor": "#728aff"},
598
- },
599
- {
600
- "condition": "params.value > 0.30",
601
- "style": {"backgroundColor": "#2251ff"},
602
- },
603
- ]
604
- }
605
-
606
-
607
- COLUMN_DEFS_PRODUCT = [
608
- # {"field": "Product Name", "cellDataType": "text", "headerName": "Product", "flex": 3},
609
- {"field": "Sub-Category", "cellDataType": "text", "headerName": "Sub-Category", "flex": 3},
610
- {
611
- "field": "Profit",
612
- "cellDataType": "number",
613
- "flex": 2,
614
- "valueFormatter": {"function": "d3.format('$,.2f')(params.value)"},
615
- },
616
- {
617
- "field": "Sales",
618
- "cellDataType": "number",
619
- "flex": 2,
620
- "valueFormatter": {"function": "d3.format('$,.2f')(params.value)"},
621
- },
622
- {
623
- "field": "Profit Margin",
624
- "flex": 2,
625
- "cellDataType": "number",
626
- "valueFormatter": {"function": "d3.format('.0%')(params.value)"},
627
- "cellStyle": CELL_STYLE_PRODUCT,
628
- },
629
- ]
630
-
631
-
632
- CELL_STYLE_CUSTOMERS = {
633
- "styleConditions": [
634
- {
635
- "condition": "params.value < -0.1",
636
- "style": {"backgroundColor": "#ff9222"},
637
- },
638
- {
639
- "condition": "params.value >= -0.1 && params.value <= 0",
640
- "style": {"backgroundColor": "#ffba7f"},
641
- },
642
- {
643
- "condition": "params.value > 0 && params.value <= 0.05",
644
- "style": {"backgroundColor": "#e4e4e4"},
645
- },
646
- {
647
- "condition": "params.value > 0.05 && params.value <= 0.15",
648
- "style": {"backgroundColor": "#b7d4ee"},
649
- },
650
- {
651
- "condition": "params.value > 0.15 && params.value <= 0.20",
652
- "style": {"backgroundColor": "#80c4f6"},
653
- },
654
- {
655
- "condition": "params.value > 0.20",
656
- "style": {"backgroundColor": "#00b4ff"},
657
- },
658
- ]
659
- }
660
-
661
-
662
- COLUMN_DEFS_CUSTOMERS = [
663
- {"field": "Rank", "cellDataType": "number", "headerName": "Rank", "flex": 2},
664
- {
665
- "field": "Customer Name",
666
- "cellDataType": "text",
667
- "flex": 3,
668
- # "valueFormatter": {"function": "d3.format('$,.2f')(params.value)"},
669
- },
670
- {
671
- "field": "Sales",
672
- "cellDataType": "number",
673
- "flex": 3,
674
- "valueFormatter": {"function": "d3.format('$,.2f')(params.value)"},
675
- },
676
- {
677
- "headerName": "Cumulative %",
678
- "field": "Cumulative %",
679
- "type": "numericColumn",
680
- "valueFormatter": {"function": "d3.format('.1f')(params.value) + '%'"},
681
- "width": 130,
682
- },
683
- ]
684
-
685
-
686
  @capture("graph")
687
  def bar_chart_top_n(data_frame, x="Sales", y="City", n=10):
688
  """Generic bar chart to show top N by any dimension."""
@@ -704,115 +602,3 @@ def bar_chart_top_n(data_frame, x="Sales", y="City", n=10):
704
  )
705
 
706
  return fig
707
-
708
-
709
- @capture("ag_grid")
710
- def custom_orders_aggrid(data_frame):
711
- """Custom aggrid table."""
712
- data_frame["Profit Ratio"] = (data_frame["Profit"] / data_frame["Sales"]).round(3)
713
- column_defs_orders = [
714
- {"headerName": "Order ID", "field": "Order ID", "minWidth": 150},
715
- {"headerName": "Status", "field": "Order Status", "minWidth": 150, "cellRenderer": "statusCellRenderer"},
716
- {
717
- "headerName": "Segment",
718
- "field": "Segment",
719
- "minWidth": 140,
720
- },
721
- {"headerName": "Customer", "field": "Customer Name", "minWidth": 170},
722
- {"headerName": "State", "field": "State", "minWidth": 150},
723
- {"headerName": "City", "field": "City", "minWidth": 150},
724
- {"headerName": "Category", "field": "Category", "minWidth": 150},
725
- {"headerName": "Sub-Category", "field": "Sub-Category", "minWidth": 150},
726
- {"headerName": "Sales", "field": "Sales", "valueFormatter": {"function": "d3.format('$,.2f')(params.value)"}},
727
- {
728
- "headerName": "Profit",
729
- "field": "Profit",
730
- "valueFormatter": {"function": "d3.format('$,.2f')(params.value)"},
731
- },
732
- {
733
- "headerName": "Profit Ratio",
734
- "field": "Profit Ratio",
735
- "minWidth": 140,
736
- "valueFormatter": {"function": "d3.format('.1%')(params.value)"},
737
- "cellStyle": {
738
- "styleConditions": [
739
- {
740
- "condition": "Number(params.value) < -0.5",
741
- "style": {
742
- "backgroundColor": "#e33b3b",
743
- "color": "white",
744
- "borderRadius": "18px",
745
- "padding": "4px",
746
- "fontWeight": "600",
747
- "justifyContent": "center",
748
- "alignItems": "center",
749
- "display": "flex",
750
- "marginTop": "8px",
751
- "height": "30px",
752
- },
753
- },
754
- {
755
- "condition": "Number(params.value) >= -0.5 && Number(params.value) < 0",
756
- "style": {
757
- "backgroundColor": "#f19791",
758
- "color": "white",
759
- "borderRadius": "18px",
760
- "padding": "4px",
761
- "fontWeight": "600",
762
- "justifyContent": "center",
763
- "alignItems": "center",
764
- "display": "flex",
765
- "marginTop": "8px",
766
- "height": "30px",
767
- },
768
- },
769
- {
770
- "condition": "Number(params.value) >= 0 && Number(params.value) < 0.30",
771
- "style": {
772
- "backgroundColor": "#728aff",
773
- "color": "white",
774
- "borderRadius": "18px",
775
- "padding": "4px",
776
- "fontWeight": "600",
777
- "justifyContent": "center",
778
- "alignItems": "center",
779
- "display": "flex",
780
- "marginTop": "8px",
781
- "height": "30px",
782
- },
783
- },
784
- {
785
- "condition": "Number(params.value) >= 0.30",
786
- "style": {
787
- "backgroundColor": "#2251ff",
788
- "color": "white",
789
- "borderRadius": "18px",
790
- "padding": "4px",
791
- "fontWeight": "600",
792
- "justifyContent": "center",
793
- "alignItems": "center",
794
- "display": "flex",
795
- "marginTop": "8px",
796
- "height": "30px",
797
- },
798
- },
799
- ]
800
- },
801
- },
802
- ]
803
-
804
- aggrid = AgGrid(
805
- columnDefs=column_defs_orders,
806
- defaultColDef={"resizable": True, "sortable": True, "filter": True, "minWidth": 30, "flex": 1},
807
- style={"height": "800px", "width": "100%"},
808
- rowData=data_frame.to_dict("records"),
809
- dashGridOptions={
810
- "rowHeight": 55,
811
- "animateRows": True,
812
- "suppressMovableColumns": True,
813
- "pagination": True,
814
- "paginationPageSize": 20,
815
- },
816
- dangerously_allow_code=True,
817
- )
818
- return aggrid
 
3
  import pandas as pd
4
  import plotly.graph_objects as go
5
  import vizro.plotly.express as px
 
6
  from vizro.models.types import capture
7
 
8
  CURRENT_YEAR = 2017
 
393
 
394
  @capture("graph")
395
  def scatter_with_quadrants(
396
+ data_frame: pd.DataFrame,
397
  x: str,
398
  y: str,
399
  custom_data: list[str],
 
400
  highlight_sub_category=None,
401
  ):
402
  """Custom scatter plot with quadrants grouped by Sub-Category."""
 
581
  return fig
582
 
583
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
584
  @capture("graph")
585
  def bar_chart_top_n(data_frame, x="Sales", y="City", n=10):
586
  """Generic bar chart to show top N by any dimension."""
 
602
  )
603
 
604
  return fig
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tables.py ADDED
@@ -0,0 +1,222 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """AG Grid table configurations for the Superstore BI dashboard."""
2
+
3
+ from dash_ag_grid import AgGrid
4
+ from vizro.models.types import capture
5
+
6
+
7
+ CELL_STYLE_PRODUCT = {
8
+ "styleConditions": [
9
+ {
10
+ "condition": "params.value < -0.5",
11
+ "style": {"backgroundColor": "#e33b3b"},
12
+ },
13
+ {
14
+ "condition": "params.value >= -0.5 && params.value <= 0",
15
+ "style": {"backgroundColor": "#f19791"},
16
+ },
17
+ {
18
+ "condition": "params.value > 0 && params.value <= 0.30",
19
+ "style": {"backgroundColor": "#728aff"},
20
+ },
21
+ {
22
+ "condition": "params.value > 0.30",
23
+ "style": {"backgroundColor": "#2251ff"},
24
+ },
25
+ ]
26
+ }
27
+
28
+
29
+ COLUMN_DEFS_PRODUCT = [
30
+ {"field": "Sub-Category", "cellDataType": "text", "headerName": "Sub-Category", "flex": 3},
31
+ {
32
+ "field": "Profit",
33
+ "cellDataType": "number",
34
+ "flex": 2,
35
+ "valueFormatter": {"function": "d3.format('$,.2f')(params.value)"},
36
+ },
37
+ {
38
+ "field": "Sales",
39
+ "cellDataType": "number",
40
+ "flex": 2,
41
+ "valueFormatter": {"function": "d3.format('$,.2f')(params.value)"},
42
+ },
43
+ {
44
+ "field": "Profit Margin",
45
+ "flex": 2,
46
+ "cellDataType": "number",
47
+ "valueFormatter": {"function": "d3.format('.0%')(params.value)"},
48
+ "cellStyle": CELL_STYLE_PRODUCT,
49
+ },
50
+ ]
51
+
52
+
53
+ CELL_STYLE_CUSTOMERS = {
54
+ "styleConditions": [
55
+ {
56
+ "condition": "params.value < -0.1",
57
+ "style": {"backgroundColor": "#ff9222"},
58
+ },
59
+ {
60
+ "condition": "params.value >= -0.1 && params.value <= 0",
61
+ "style": {"backgroundColor": "#ffba7f"},
62
+ },
63
+ {
64
+ "condition": "params.value > 0 && params.value <= 0.05",
65
+ "style": {"backgroundColor": "#e4e4e4"},
66
+ },
67
+ {
68
+ "condition": "params.value > 0.05 && params.value <= 0.15",
69
+ "style": {"backgroundColor": "#b7d4ee"},
70
+ },
71
+ {
72
+ "condition": "params.value > 0.15 && params.value <= 0.20",
73
+ "style": {"backgroundColor": "#80c4f6"},
74
+ },
75
+ {
76
+ "condition": "params.value > 0.20",
77
+ "style": {"backgroundColor": "#00b4ff"},
78
+ },
79
+ ]
80
+ }
81
+
82
+
83
+ COLUMN_DEFS_CUSTOMERS = [
84
+ {"field": "Rank", "cellDataType": "number", "headerName": "Rank", "flex": 2},
85
+ {
86
+ "field": "Customer Name",
87
+ "cellDataType": "text",
88
+ "flex": 3,
89
+ },
90
+ {
91
+ "field": "Sales",
92
+ "cellDataType": "number",
93
+ "flex": 3,
94
+ "valueFormatter": {"function": "d3.format('$,.2f')(params.value)"},
95
+ },
96
+ {
97
+ "headerName": "Cumulative %",
98
+ "field": "Cumulative %",
99
+ "type": "numericColumn",
100
+ "valueFormatter": {"function": "d3.format('.1f')(params.value) + '%'"},
101
+ "width": 130,
102
+ },
103
+ ]
104
+
105
+
106
+ @capture("ag_grid")
107
+ def custom_orders_aggrid(data_frame):
108
+ """Create custom AG Grid table for orders with conditional formatting.
109
+
110
+ Args:
111
+ data_frame: Source dataframe containing order data.
112
+
113
+ Returns:
114
+ AgGrid: Configured AG Grid component with custom column definitions and styling.
115
+ """
116
+ data_frame["Profit Ratio"] = (data_frame["Profit"] / data_frame["Sales"]).round(3)
117
+ column_defs_orders = [
118
+ {"headerName": "Order ID", "field": "Order ID", "minWidth": 150},
119
+ {"headerName": "Status", "field": "Order Status", "minWidth": 150, "cellRenderer": "statusCellRenderer"},
120
+ {
121
+ "headerName": "Segment",
122
+ "field": "Segment",
123
+ "minWidth": 140,
124
+ },
125
+ {"headerName": "Customer", "field": "Customer Name", "minWidth": 170},
126
+ {"headerName": "State", "field": "State", "minWidth": 150},
127
+ {"headerName": "City", "field": "City", "minWidth": 150},
128
+ {"headerName": "Category", "field": "Category", "minWidth": 150},
129
+ {"headerName": "Sub-Category", "field": "Sub-Category", "minWidth": 150},
130
+ {"headerName": "Sales", "field": "Sales", "valueFormatter": {"function": "d3.format('$,.2f')(params.value)"}},
131
+ {
132
+ "headerName": "Profit",
133
+ "field": "Profit",
134
+ "valueFormatter": {"function": "d3.format('$,.2f')(params.value)"},
135
+ },
136
+ {
137
+ "headerName": "Profit Ratio",
138
+ "field": "Profit Ratio",
139
+ "minWidth": 140,
140
+ "valueFormatter": {"function": "d3.format('.1%')(params.value)"},
141
+ "cellStyle": {
142
+ "styleConditions": [
143
+ {
144
+ "condition": "Number(params.value) < -0.5",
145
+ "style": {
146
+ "backgroundColor": "#e33b3b",
147
+ "color": "white",
148
+ "borderRadius": "18px",
149
+ "padding": "4px",
150
+ "fontWeight": "600",
151
+ "justifyContent": "center",
152
+ "alignItems": "center",
153
+ "display": "flex",
154
+ "marginTop": "8px",
155
+ "height": "30px",
156
+ },
157
+ },
158
+ {
159
+ "condition": "Number(params.value) >= -0.5 && Number(params.value) < 0",
160
+ "style": {
161
+ "backgroundColor": "#f19791",
162
+ "color": "white",
163
+ "borderRadius": "18px",
164
+ "padding": "4px",
165
+ "fontWeight": "600",
166
+ "justifyContent": "center",
167
+ "alignItems": "center",
168
+ "display": "flex",
169
+ "marginTop": "8px",
170
+ "height": "30px",
171
+ },
172
+ },
173
+ {
174
+ "condition": "Number(params.value) >= 0 && Number(params.value) < 0.30",
175
+ "style": {
176
+ "backgroundColor": "#728aff",
177
+ "color": "white",
178
+ "borderRadius": "18px",
179
+ "padding": "4px",
180
+ "fontWeight": "600",
181
+ "justifyContent": "center",
182
+ "alignItems": "center",
183
+ "display": "flex",
184
+ "marginTop": "8px",
185
+ "height": "30px",
186
+ },
187
+ },
188
+ {
189
+ "condition": "Number(params.value) >= 0.30",
190
+ "style": {
191
+ "backgroundColor": "#2251ff",
192
+ "color": "white",
193
+ "borderRadius": "18px",
194
+ "padding": "4px",
195
+ "fontWeight": "600",
196
+ "justifyContent": "center",
197
+ "alignItems": "center",
198
+ "display": "flex",
199
+ "marginTop": "8px",
200
+ "height": "30px",
201
+ },
202
+ },
203
+ ]
204
+ },
205
+ },
206
+ ]
207
+
208
+ aggrid = AgGrid(
209
+ columnDefs=column_defs_orders,
210
+ defaultColDef={"resizable": True, "sortable": True, "filter": True, "minWidth": 30, "flex": 1},
211
+ style={"height": "800px", "width": "100%"},
212
+ rowData=data_frame.to_dict("records"),
213
+ dashGridOptions={
214
+ "rowHeight": 55,
215
+ "animateRows": True,
216
+ "suppressMovableColumns": True,
217
+ "pagination": True,
218
+ "paginationPageSize": 20,
219
+ },
220
+ dangerously_allow_code=True,
221
+ )
222
+ return aggrid