1010 DEFAULT_CHART_WIDTH ,
1111 DEFAULT_X_AXIS ,
1212 DEFAULT_Y_AXIS ,
13+ ChartAxisFields ,
1314 ChartTypes ,
15+ DataSourceFileType ,
1416 DEFAULT_Y_AXIS_MINIMUM_VAlUE ,
17+ extract_metric_group_from_metric ,
18+ )
19+ from metrics .domain .models .charts .dual_category_charts import (
20+ DualCategoryChartRequestParams ,
1521)
16- from metrics .domain .models .charts import DualCategoryChartRequestParams
1722
1823
1924class DualCategoryChartSegmentSerializer (serializers .Serializer ):
@@ -33,59 +38,125 @@ class DualCategoryChartSegmentSerializer(serializers.Serializer):
3338 )
3439
3540
36- class StaticFieldsSerializer (PlotSerializer ):
37- theme = serializers .CharField (
38- required = True ,
39- allow_blank = True ,
40- allow_null = True ,
41- )
42- sub_theme = serializers .CharField (
43- required = True ,
44- allow_blank = True ,
45- allow_null = True ,
46- )
47-
48-
4941class DualCategoryChartSerializer (BaseChartsSerializer ):
5042 chart_type = serializers .ChoiceField (
5143 help_text = help_texts .CHART_TYPE_FIELD ,
52- choices = ChartTypes .selectable_choices (),
44+ choices = ChartTypes .dual_category_chart_options (),
5345 required = True ,
5446 )
5547 primary_field_values = serializers .ListField (
5648 child = serializers .CharField (),
5749 help_text = "List of primary field values for this segment" ,
58- required = True ,
59- allow_empty = False ,
50+ required = False ,
51+ allow_empty = True ,
6052 )
6153
6254 secondary_category = serializers .CharField (
6355 help_text = "Secondary category field for the chart" ,
6456 required = True ,
6557 )
6658
67- static_fields = StaticFieldsSerializer ()
59+ static_fields = PlotSerializer ()
6860
6961 segments = serializers .ListField (
7062 child = DualCategoryChartSegmentSerializer (),
7163 help_text = "Segments for the dual category chart" ,
7264 required = True ,
7365 )
7466
67+ @classmethod
68+ def validate (cls , attrs : dict ) -> dict :
69+ """Validate primary_field_values based on the selected x-axis."""
70+ x_axis = attrs .get ("x_axis" ) or DEFAULT_X_AXIS
71+ primary_field_values = attrs .get ("primary_field_values" ) or []
72+ metric = attrs ["static_fields" ]["metric" ]
73+ metric_group = extract_metric_group_from_metric (metric = metric )
74+ is_timeseries_data = DataSourceFileType [metric_group ].is_timeseries
75+
76+ if is_timeseries_data :
77+ if primary_field_values :
78+ raise serializers .ValidationError (
79+ {
80+ "primary_field_values" : (
81+ "This field should not be provided for timeseries data."
82+ )
83+ }
84+ )
85+ if x_axis != ChartAxisFields .date .name :
86+ raise serializers .ValidationError (
87+ {
88+ "x_axis" : (
89+ "This field should be set to 'date' for timeseries data."
90+ )
91+ }
92+ )
93+
94+ elif not is_timeseries_data and not primary_field_values :
95+ raise serializers .ValidationError (
96+ {"primary_field_values" : ("This field is required for headline data." )}
97+ )
98+
99+ return attrs
100+
75101 def to_models (self , request : Request ) -> DualCategoryChartRequestParams :
76102 x_axis = self .data .get ("x_axis" ) or DEFAULT_X_AXIS
77103 y_axis = self .data .get ("y_axis" ) or DEFAULT_Y_AXIS
78104
79- for plot in self .data ["segments" ]:
80- plot ["x_axis" ] = x_axis
81- plot ["y_axis" ] = y_axis
105+ primary_field_values = self .data .get ("primary_field_values" ) or []
106+ secondary_category = self .data ["secondary_category" ]
107+ static_fields : dict [str , str | int ] = self .validated_data .pop ("static_fields" )
108+
109+ if static_fields ["date_to" ]:
110+ static_fields ["date_to" ] = static_fields ["date_to" ].isoformat ()
111+
112+ if static_fields ["date_from" ]:
113+ static_fields ["date_from" ] = static_fields ["date_from" ].isoformat ()
114+
115+ groups_plots = []
116+ segments : list [dict ] = self .data ["segments" ]
117+
118+ metric_group = extract_metric_group_from_metric (metric = static_fields ["metric" ])
119+ is_timeseries_data = DataSourceFileType [metric_group ].is_timeseries
120+
121+ # If timeseries data
122+ if is_timeseries_data :
123+ plots = [
124+ {
125+ "x_axis" : x_axis ,
126+ "y_axis" : y_axis ,
127+ "line_colour" : segment ["colour" ],
128+ ** static_fields ,
129+ secondary_category : segment ["secondary_field_value" ],
130+ "chart_type" : self .data ["chart_type" ],
131+ "label" : segment ["label" ],
132+ }
133+ for segment in segments
134+ ]
135+ groups_plots .extend (plots )
136+
137+ else :
138+ for primary_field_value in primary_field_values :
139+ plots = [
140+ {
141+ "x_axis" : x_axis ,
142+ "y_axis" : y_axis ,
143+ "line_colour" : segment ["colour" ],
144+ ** static_fields ,
145+ x_axis : primary_field_value ,
146+ secondary_category : segment ["secondary_field_value" ],
147+ "chart_type" : self .data ["chart_type" ],
148+ "label" : segment ["label" ],
149+ }
150+ for segment in segments
151+ ]
152+ groups_plots .extend (plots )
82153
83154 return DualCategoryChartRequestParams (
84155 chart_type = self .data ["chart_type" ],
85- primary_field_values = self . data [ " primary_field_values" ] ,
156+ primary_field_values = primary_field_values ,
86157 secondary_category = self .data ["secondary_category" ],
87158 static_fields = self .data ["static_fields" ],
88- segments = self . data [ "segments" ] ,
159+ plots = groups_plots ,
89160 file_format = self .data ["file_format" ],
90161 chart_height = self .data ["chart_height" ] or DEFAULT_CHART_HEIGHT ,
91162 chart_width = self .data ["chart_width" ] or DEFAULT_CHART_WIDTH ,
@@ -97,4 +168,5 @@ def to_models(self, request: Request) -> DualCategoryChartRequestParams:
97168 or DEFAULT_Y_AXIS_MINIMUM_VAlUE ,
98169 y_axis_maximum_value = self .data ["y_axis_maximum_value" ],
99170 request = request ,
171+ legend_title = self .data .get ("legend_title" , "" ),
100172 )
0 commit comments