def transform_row_index(index_values, field_map, dimension_hyperlink_templates): # Add the index to the row row = {} for key, value in index_values.items(): if key is None: continue field_alias = key field = field_map[field_alias] data = {RAW_VALUE: raw_value(value, field)} display = _display_value(value, field) if display is not None: data["display"] = display # If the dimension has a hyperlink template, then apply the template by formatting it with the dimension # values for this row. The values contained in `index_values` will always contain all of the required values # at this point, otherwise the hyperlink template will not be included. if key in dimension_hyperlink_templates: data["hyperlink"] = dimension_hyperlink_templates[key].format( **index_values) safe_key = safe_value(key) row[safe_key] = data return row
def transform_row_values(series, fields, is_transposed): # Add the values to the row index_names = series.index.names or [] row = {} for key, value in series.iteritems(): key = wrap_list(key) # Get the field for the metric metric_alias = wrap_list( series.name)[0] if is_transposed else key[0] field = fields[metric_alias] data = {RAW_VALUE: raw_value(value, field)} display = _display_value(value, field, date_as=return_none) if display is not None: data["display"] = display accessor_fields = [ fields[field_alias] for field_alias in index_names if field_alias is not None ] accessor = [ safe_value(value) for value, field in zip(key, accessor_fields) ] or key setdeepattr(row, accessor, data) return row
def test_totals_markers_are_returned_as_text_totals_marker(self): for marker, field in [ (TEXT_TOTALS, text_field), (NUMBER_TOTALS, number_field), (DATE_TOTALS, date_field), ]: with self.subTest(field.data_type): self.assertEqual("$totals", formats.raw_value(marker, field))
def transform_row_values(self, series, fields: Dict[str, Field], is_transposed: bool, is_pivoted: bool, hide_aliases: List[str]): row = {} row_colors = None for key, value in series.items(): if key in hide_aliases: continue key = wrap_list(key) # Get the field for the metric metric_alias = wrap_list( series.name)[0] if is_transposed else key[0] field = fields[metric_alias] data = { RAW_VALUE: raw_value(value, field), } if not row_colors: # No color for this field yet rule = find_rule_to_apply( self.formatting_rules_map[metric_alias], value) if rule is not None: colors = rule.determine_colors(value) data["color"], data["text_color"] = colors if not is_transposed and not is_pivoted and rule.covers_row: # No transposing or pivoting going on so set as row color if it's specified for the rule row_colors = colors display = _display_value(value, field, date_as=return_none) if display is not None: data["display"] = display accessor = self._get_row_value_accessor(series, fields, key) setdeepattr(row, accessor, data) # Assign the row colors to fields that aren't colored yet if row_colors: for key in series.keys(): accessor = self._get_row_value_accessor( series, fields, wrap_list(key)) data = getdeepattr(row, accessor) if "color" not in data: data["color"], data["text_color"] = row_colors return row, row_colors
def _render_category_data(group_df, field_alias, metric): categories = (list(group_df.index.levels[0]) if isinstance( group_df.index, pd.MultiIndex) else list(group_df.index)) series = [] for labels, y in group_df[field_alias].iteritems(): label = labels[0] if isinstance(labels, tuple) else labels if pd.isnull(label): # ignore nans in index continue series.append({ "x": categories.index(label), "y": formats.raw_value(y, metric) }) return series
def _render_timeseries_data(group_df, metric_alias, metric): series = [] for dimension_values, y in group_df[metric_alias].iteritems(): first_dimension_value = utils.wrap_list(dimension_values)[0] # Ignore empty result sets where the only row is totals if first_dimension_value in TOTALS_MARKERS: continue if pd.isnull(first_dimension_value): # Ignore totals on the x-axis. continue series.append(( formats.date_as_millis(first_dimension_value), formats.raw_value(y, metric), )) return series
def transform_row_index( index_values, field_map: Dict[str, Field], dimension_hyperlink_templates: Dict[str, str], hide_dimension_aliases: List[str], row_colors: List[str], ): # Add the index to the row row = {} for key, value in index_values.items(): if key is None or key not in field_map: continue field_alias = key field = field_map[field_alias] data = {RAW_VALUE: raw_value(value, field)} display = _display_value(value, field) if display is not None: data["display"] = display if row_colors is not None: data["color"], data["text_color"] = row_colors is_totals = display == TOTALS_LABEL # If the dimension has a hyperlink template, then apply the template by formatting it with the dimension # values for this row. The values contained in `index_values` will always contain all of the required values # at this point, otherwise the hyperlink template will not be included. if not is_totals and key in dimension_hyperlink_templates: try: data["hyperlink"] = dimension_hyperlink_templates[ key].format(**index_values) except KeyError: pass safe_key = safe_value(key) row[safe_key] = data for dimension_alias in hide_dimension_aliases: if dimension_alias in row: del row[dimension_alias] return row
def _render_pie_series(self, metric: Field, reference: Reference, data_frame: pd.DataFrame, dimension_fields: List[Field]) -> dict: metric_alias = utils.alias_selector(metric.alias) if self.split_dimension: dimension_fields = [ dimension for dimension in dimension_fields if dimension != self.split_dimension ] data_frame = data_frame.reset_index(alias_selector( self.split_dimension.alias), drop=True) data = [] for dimension_values, y in data_frame[metric_alias].iteritems(): dimension_values = utils.wrap_list(dimension_values) name = self._format_dimension_values(dimension_fields, dimension_values) data.append({ "name": name or metric.label, "y": formats.raw_value(y, metric) }) return { "name": reference_label(metric, reference), "type": "pie", "data": data, "tooltip": { "pointFormat": '<span style="color:{point.color}">\u25CF</span> {series.name}: ' "<b>{point.y} ({point.percentage:.1f}%)</b><br/>", "valueDecimals": metric.precision, "valuePrefix": reference_prefix(metric, reference), "valueSuffix": reference_suffix(metric, reference), }, }
def _render_pie_series(self, metric, reference, data_frame, dimension_fields): metric_alias = utils.alias_selector(metric.alias) data = [] for dimension_values, y in data_frame[metric_alias].iteritems(): dimension_values = utils.wrap_list(dimension_values) name = self._format_dimension_values(dimension_fields, dimension_values) data.append( {"name": name or metric.label, "y": formats.raw_value(y, metric),} ) return { "name": reference_label(metric, reference), "type": "pie", "data": data, "tooltip": { "pointFormat": '<span style="color:{point.color}">\u25CF</span> {series.name}: ' "<b>{point.y} ({point.percentage:.1f}%)</b><br/>", "valueDecimals": metric.precision, "valuePrefix": reference_prefix(metric, reference), "valueSuffix": reference_suffix(metric, reference), }, }
def test_inf_returned_as_inf_label(self): with self.subTest("positive inf"): self.assertIsNone(formats.raw_value(np.inf, None)) with self.subTest("negative inf"): self.assertIsNone(formats.raw_value(-np.inf, None))
def test_datetime_value_is_returned_as_iso_date_string(self): self.assertEqual( "2019-01-01T12:30:02", formats.raw_value(datetime(2019, 1, 1, 12, 30, 2), date_field), )
def test_date_value_is_returned_as_iso_date_string(self): self.assertEqual("2019-01-01T00:00:00", formats.raw_value(date(2019, 1, 1), date_field))
def test_boolean_value_is_returned_as_self(self): for value in (True, False): with self.subTest("using value" + str(value)): self.assertEqual(value, formats.raw_value(value, boolean_field))
def test_num_value_is_returned_as_self(self): for value in (0, -1, 1, 100, 0.0, -1.1, 1.1, 0.123456789, -0.123456789): with self.subTest("using value" + str(value)): self.assertEqual(value, formats.raw_value(value, number_field))
def test_text_value_is_returned_as_self(self): for value in ("abc", " dc23d- 0f30fi", ""): with self.subTest("using value" + value): self.assertEqual(value, formats.raw_value(value, text_field))
def test_none_returned_as_none(self): self.assertIsNone(formats.raw_value(None, None))
def test_nan_returned_as_none(self): self.assertIsNone(formats.raw_value(np.nan, None))