mirror of https://github.com/apache/superset.git
Merge pull request #88 from mistercrunch/map
World Map viz with bubbles
This commit is contained in:
commit
047e142b43
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -108,6 +108,18 @@ class FormFactory(object):
|
|||
'Color Metric', choices=datasource.metrics_combo,
|
||||
default=default_metric,
|
||||
description="A metric to use for color"),
|
||||
'country_fieldtype': SelectField(
|
||||
'Country Field Type',
|
||||
default='cca2',
|
||||
choices=(
|
||||
('name', 'Full name'),
|
||||
('cioc', 'code International Olympic Committee (cioc)'),
|
||||
('cca2', 'code ISO 3166-1 alpha-2 (cca2)'),
|
||||
('cca3', 'code ISO 3166-1 alpha-3 (cca3)'),
|
||||
),
|
||||
description=(
|
||||
"The country code standard that Panoramix should expect "
|
||||
"to find in the [country] column")),
|
||||
'groupby': SelectMultipleSortableField(
|
||||
'Group by',
|
||||
choices=self.choicify(datasource.groupby_column_names),
|
||||
|
@ -191,6 +203,18 @@ class FormFactory(object):
|
|||
'90 days ago',
|
||||
'1 year ago'])
|
||||
),
|
||||
'max_bubble_size': FreeFormSelectField(
|
||||
'Max Bubble Size', default="25",
|
||||
choices=self.choicify([
|
||||
'5',
|
||||
'10',
|
||||
'15',
|
||||
'25',
|
||||
'50',
|
||||
'75',
|
||||
'100',
|
||||
])
|
||||
),
|
||||
'row_limit':
|
||||
FreeFormSelectField(
|
||||
'Row limit',
|
||||
|
@ -298,6 +322,10 @@ class FormFactory(object):
|
|||
"Range Filter", default=True,
|
||||
description=(
|
||||
"Whether to display the time range interactive selector")),
|
||||
'show_bubbles': BetterBooleanField(
|
||||
"Show Bubbles", default=False,
|
||||
description=(
|
||||
"Whether to display bubbles on top of countries")),
|
||||
'show_legend': BetterBooleanField(
|
||||
"Legend", default=True,
|
||||
description="Whether to display the legend (toggles)"),
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -20,6 +20,10 @@ form div {
|
|||
text-align: right;
|
||||
}
|
||||
|
||||
.select2-results .select2-highlighted {
|
||||
background-color: #005c66;
|
||||
}
|
||||
|
||||
.notbtn {
|
||||
cursor: default;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
Using the awesome lib at http://datamaps.github.io/
|
||||
*/
|
||||
|
||||
function viz_world_map(data_attribute) {
|
||||
var token = d3.select('#' + data_attribute.token);
|
||||
var render = function(done) {
|
||||
// Breadcrumb dimensions: width, height, spacing, width of tip/tail.
|
||||
var div = token;
|
||||
var xy = div.node().getBoundingClientRect();
|
||||
var width = xy.width;
|
||||
var height = xy.height - 25;
|
||||
|
||||
d3.json(data_attribute.json_endpoint, function(error, json){
|
||||
|
||||
if (error != null){
|
||||
var err = '<div class="alert alert-danger">' + error.responseText + '</div>';
|
||||
token.html(err);
|
||||
return '';
|
||||
done();
|
||||
}
|
||||
var ext = d3.extent(json.data, function(d){return d.m1});
|
||||
var extRadius = d3.extent(json.data, function(d){return d.m2});
|
||||
var radiusScale = d3.scale.linear()
|
||||
.domain([extRadius[0], extRadius[1]])
|
||||
.range([1, data_attribute.form_data.max_bubble_size]);
|
||||
json.data.forEach(function(d){
|
||||
d.radius = radiusScale(d.m2);
|
||||
})
|
||||
var colorScale = d3.scale.linear()
|
||||
.domain([ext[0], ext[1]])
|
||||
.range(["#FFF", "black"]);
|
||||
var d = {};
|
||||
for (var i=0; i<json.data.length; i++){
|
||||
var country = json.data[i];
|
||||
country['fillColor'] = colorScale(country.m1);
|
||||
d[country.country] = country;
|
||||
}
|
||||
f = d3.format('.3s');
|
||||
var map = new Datamap({
|
||||
element: document.getElementById(data_attribute.token),
|
||||
data: json.data,
|
||||
fills: {
|
||||
defaultFill: 'grey'
|
||||
},
|
||||
geographyConfig: {
|
||||
popupOnHover: true,
|
||||
highlightOnHover: true,
|
||||
borderWidth: 1,
|
||||
borderColor: 'grey',
|
||||
highlightBorderColor: 'black',
|
||||
highlightFillColor: '#005a63',
|
||||
highlightBorderWidth: 1,
|
||||
popupTemplate: function(geo, data) {
|
||||
return '<div class="hoverinfo"><strong>' + data.name + '</strong><br>'+ f(data.m1) + '</div>';
|
||||
},
|
||||
},
|
||||
bubblesConfig: {
|
||||
borderWidth: 1,
|
||||
borderOpacity: 1,
|
||||
borderColor: '#005a63',
|
||||
popupOnHover: true,
|
||||
radius: null,
|
||||
popupTemplate: function(geo, data) {
|
||||
return '<div class="hoverinfo"><strong>' + data.name + '</strong><br>'+ f(data.m2) + '</div>';
|
||||
},
|
||||
fillOpacity: 0.5,
|
||||
animate: true,
|
||||
highlightOnHover: true,
|
||||
highlightFillColor: '#005a63',
|
||||
highlightBorderColor: 'black',
|
||||
highlightBorderWidth: 2,
|
||||
highlightBorderOpacity: 1,
|
||||
highlightFillOpacity: 0.85,
|
||||
exitDelay: 100,
|
||||
key: JSON.stringify
|
||||
},
|
||||
});
|
||||
map.updateChoropleth(d);
|
||||
if(data_attribute.form_data.show_bubbles){
|
||||
map.bubbles(json.data);
|
||||
token.selectAll("circle.datamaps-bubble").style('fill', '#005a63');
|
||||
}
|
||||
done(json);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
render: render,
|
||||
resize: render,
|
||||
};
|
||||
}
|
||||
px.registerWidget('world_map', viz_world_map);
|
|
@ -0,0 +1,8 @@
|
|||
{% macro viz_html(viz) %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro viz_js(viz) %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro viz_css(viz) %}
|
||||
{% endmacro %}
|
|
@ -961,6 +961,87 @@ class DirectedForceViz(BaseViz):
|
|||
d = df.to_dict(orient='records')
|
||||
return dumps(d)
|
||||
|
||||
|
||||
class WorldMapViz(BaseViz):
|
||||
viz_type = "world_map"
|
||||
verbose_name = "World Map"
|
||||
is_timeseries = False
|
||||
template = 'panoramix/viz_world_map.html'
|
||||
js_files = [
|
||||
'lib/d3.min.js',
|
||||
'lib/topojson.min.js',
|
||||
'lib/datamaps.all.js',
|
||||
'widgets/viz_world_map.js']
|
||||
css_files = ['widgets/viz_world_map.css']
|
||||
fieldsets = (
|
||||
{
|
||||
'label': None,
|
||||
'fields': (
|
||||
'granularity',
|
||||
('since', 'until'),
|
||||
'entity',
|
||||
'country_fieldtype',
|
||||
'metric',
|
||||
)
|
||||
},
|
||||
{
|
||||
'label': 'Bubbles',
|
||||
'fields': (
|
||||
('show_bubbles', None),
|
||||
'secondary_metric',
|
||||
'max_bubble_size',
|
||||
)
|
||||
})
|
||||
form_overrides = {
|
||||
'entity': {
|
||||
'label': 'Country Field',
|
||||
'description': "3 letter code of the country",
|
||||
},
|
||||
'metric': {
|
||||
'label': 'Metric for color',
|
||||
'description': ("Metric that defines the color of the country"),
|
||||
},
|
||||
'secondary_metric': {
|
||||
'label': 'Bubble size',
|
||||
'description': ("Metric that defines the size of the bubble"),
|
||||
},
|
||||
}
|
||||
def query_obj(self):
|
||||
qry = super(WorldMapViz, self).query_obj()
|
||||
qry['metrics'] = [
|
||||
self.form_data['metric'], self.form_data['secondary_metric']]
|
||||
qry['groupby'] = [self.form_data['entity']]
|
||||
return qry
|
||||
|
||||
def get_json_data(self):
|
||||
from panoramix.data import countries
|
||||
df = self.get_df()
|
||||
cols = [self.form_data.get('entity')]
|
||||
metric = self.form_data.get('metric')
|
||||
secondary_metric = self.form_data.get('secondary_metric')
|
||||
if metric == secondary_metric:
|
||||
ndf = df[cols]
|
||||
ndf['m1'] = df[metric]
|
||||
ndf['m2'] = df[metric]
|
||||
else:
|
||||
cols += [metric, secondary_metric]
|
||||
ndf = df[cols]
|
||||
df = ndf
|
||||
df.columns = ['country', 'm1', 'm2']
|
||||
d = df.to_dict(orient='records')
|
||||
for row in d:
|
||||
country = countries.get(
|
||||
self.form_data.get('country_fieldtype'), row['country'])
|
||||
if country:
|
||||
row['country'] = country['cca3']
|
||||
row['latitude'] = country['lat']
|
||||
row['longitude'] = country['lng']
|
||||
row['name'] = country['name']
|
||||
else:
|
||||
row['country'] = "XXX"
|
||||
return dumps(d)
|
||||
|
||||
|
||||
viz_types_list = [
|
||||
TableViz,
|
||||
PivotTableViz,
|
||||
|
@ -977,6 +1058,7 @@ viz_types_list = [
|
|||
SunburstViz,
|
||||
DirectedForceViz,
|
||||
SankeyViz,
|
||||
WorldMapViz,
|
||||
]
|
||||
# This dict is used to
|
||||
viz_types = OrderedDict([(v.viz_type, v) for v in viz_types_list])
|
||||
|
|
Loading…
Reference in New Issue