How to add more metrics on the country_map in Apache-superset?
Asked Answered
I

1

17

I am using country_map in for visualization purposes. When zooming in on a polygon, information from the columns appears inside of the polygon, like so:

map

There is only one available metric option to display: metric

Code for the metric update is found on this path:

superset/assets/src/visualizations/CountryMap/CountryMap.js

Code:

const updateMetrics = function (region) {
  if (region.length > 0) {     
    resultText.text(format(region[0].metric));
  }
};

The metrics are defined in controls.jsx:

/superset/static/assets/src/explore/controls.jsx

const metrics = {
  type: 'MetricsControl',
  multi: true,
  label: t('Metrics'),
  validators: [v.nonEmpty],
  default: (c) => {
    const metric = mainMetric(c.savedMetrics);
    return metric ? [metric] : null;
  },
  mapStateToProps: (state) => {
    const datasource = state.datasource;
    return {
      columns: datasource ? datasource.columns : [],
      savedMetrics: datasource ? datasource.metrics : [],
      datasourceType: datasource && datasource.type,
    };
  },
  description: t('One or many metrics to display'),
};
const metric = {
  ...metrics,
  multi: false,
  label: t('Metric'),
  default: props => mainMetric(props.savedMetrics),
};

Country map is using metric, which doesn't allow multiple metrics to be selected, Code found here:

superset/assets/src/explore/controlPanels/CountryMap.js

  controlPanelSections: [
    {
      label: t('Query'),
      expanded: true,
      controlSetRows: [
        ['entity'],
        ['metric'],
        ['adhoc_filters'],
      ],
    },
    {
      label: t('Options'),
      expanded: true,
      controlSetRows: [
        ['select_country', 'number_format'],
        ['linear_color_scheme'],
      ],
    },
  ],

The python class of country_map is located at viz.py:

class CountryMapViz(BaseViz):

    """A country centric"""

    viz_type = 'country_map'
    verbose_name = _('Country Map')
    is_timeseries = False
    credits = 'From bl.ocks.org By john-guerra'

    def query_obj(self):
        qry = super(CountryMapViz, self).query_obj()
        qry['metrics'] = [
            self.form_data['metric']]
        qry['groupby'] = [self.form_data['entity']]
        return qry

Changing the code in CountryMap.js and viz.py from metric to metrics results in the following error:

Traceback (most recent call last):
  File "/Documents/superset/superset/superset/viz.py", line 410, in get_df_payload
    df = self.get_df(query_obj)
  File "/Documents/superset/superset/superset/viz.py", line 213, in get_df
    self.results = self.datasource.query(query_obj)
  File "/Documents/superset/superset/superset/connectors/sqla/models.py", line 797, in query
    sql = self.get_query_str(query_obj)
  File "/Documents/superset/superset/superset/connectors/sqla/models.py", line 471, in get_query_str
    qry = self.get_sqla_query(**query_obj)
  File "/Documents/superset/superset/superset/connectors/sqla/models.py", line 585, in get_sqla_query
    elif m in metrics_dict:
TypeError: unhashable type: 'list'

How can I add more metrics to display inside the polygon?

Inceptive answered 11/2, 2019 at 9:59 Comment(2)
What did you modify exactly? Could you post your modification to CountryMap.js and viz.py?Westberg
@Westberg In CountryMap.js I changed ['metric'] to ['metrics']. I did the same in viz.py, at the CountryMapViz class, where I just modified self.form_data['metric']] to self.form_data['metrics']], in the query_obj(self) method.Inceptive
W
1

The direct cause of the error TypeError: unhashable type: 'list' is your modification to file "viz.py":

self.form_data['metric']] to self.form_data['metrics']], in the query_obj(self) method.

As you can see in the source code here, form data metrics is a list object that contains metric, where metric is probably a string or other hashable object. In python language, a list object is not hashable. Because you replace a hashable object (metric) with an unhashable one (metrics), an unhashable type error is then raised.

The correct way to modify CoutryMapViz.query_obj() to accept metrics query can be found in the other Viz classes. The code section here is a very nice example:


class CalHeatmapViz(BaseViz):

"""Calendar heatmap."""
...

    def query_obj(self):
        d = super(CalHeatmapViz, self).query_obj()
        fd = self.form_data
        d['metrics'] = fd.get('metrics')
        return d

Finally, the CoutryMapViz.query_obj() method should look like this:

class CountryMapViz(BaseViz):

...

    def query_obj(self):
        qry = super(CountryMapViz, self).query_obj()
        qry['metrics'] = fd.get('metrics')
        qry['groupby'] = [self.form_data['entity']]
        return qry
Westberg answered 7/3, 2019 at 14:6 Comment(4)
This change however does not make a difference in the metrics shown inside the polygon. Even if you select more than 1 metric in the form, only the first selected metric will be shown when you hover on or click the polygonsInceptive
This is to do with the get_data method. You can use the codes in the CalHeatmapViz.get_data() function as an example.Westberg
To make the chart display correct, you need to modify the propTypes in CountryMap.js and CoutryMapViz.get_data() in viz.py. This is another question that worth to be discussed in another post.Westberg
my question however is not about getting rid of the Type error, but rather about the end result being functional. But regardless, thanks for your contribution and the suggestions in the commentInceptive

© 2022 - 2024 — McMap. All rights reserved.