Merge branch 'master' of github.com:mistercrunch/panoramix

This commit is contained in:
Maxime Beauchemin 2015-12-17 13:49:47 -08:00
commit 2a30908328
13 changed files with 26815 additions and 13 deletions

11549
panoramix/data/countries.json Normal file

File diff suppressed because it is too large Load Diff

2490
panoramix/data/countries.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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

1
panoramix/static/lib/topojson.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -20,6 +20,10 @@ form div {
text-align: right;
}
.select2-results .select2-highlighted {
background-color: #005c66;
}
.notbtn {
cursor: default;
}
@ -55,9 +59,9 @@ legend.legend-style {
background-color: transparent;
font-weight: bold;
}
.nvtooltip{
.nvtooltip {
position: relative; !important
z-index: 10;
z-index: 888;
}
legend {
@ -185,7 +189,7 @@ legend {
overflow: visible; /* This allows elements within these slice typesin a dashboard to overflow */
}
.dashboard div.nvtooltip {
z-index: 1; /* this lets tool tips go on top of other slices */
z-index: 888; /* this lets tool tips go on top of other slices */
}
.dashboard td.icons {
width: 50px;

View File

@ -217,6 +217,13 @@ function initializeDashboardView(dashboard_id) {
css = $(this).val();
$("#user_style").html(css);
});
$('li.widget').each(function() { /* this sets the z-index for left side boxes higher. */
current_row = $(this).attr('data-col');
$( this ).css('z-index', 100 - current_row);
});
$("div.chart").each(function() { /* this makes the whole chart fit within the dashboard div */
$(this).css('height', '95%');
});
}
// Export public functions

View File

@ -9,14 +9,13 @@ function viz_nvd3(data_attribute) {
return v = new Date(dttm.getUTCFullYear(), dttm.getUTCMonth(), dttm.getUTCDate(), dttm.getUTCHours(), dttm.getUTCMinutes(), dttm.getUTCSeconds());
}
var tickMultiFormat = d3.time.format.multi([
[".%L", function(d) { return d.getMilliseconds(); }],
[":%S", function(d) { return d.getSeconds(); }],
["%I:%M", function(d) { return d.getMinutes(); }],
["%I %p", function(d) { return d.getHours(); }],
["%a %d", function(d) { return d.getDay() && d.getDate() != 1; }],
["%b %d", function(d) { return d.getDate() != 1; }],
["%B", function(d) { return d.getMonth(); }],
["%Y", function() { return true; }]
[".%L", function(d) { return d.getMilliseconds(); }], // If there are millisections, show only them
[":%S", function(d) { return d.getSeconds(); }], // If there are seconds, show only them
["%a %b %d, %I:%M %p", function(d) { return d.getMinutes()!=0; }], // If there are non-zero minutes, show Date, Hour:Minute [AM/PM]
["%a %b %d, %I %p", function(d) { return d.getHours() != 0; }], // If there are hours that are multiples of 3, show date and AM/PM
["%a %b %d, %Y", function(d) { return d.getDate() != 1; }], // If not the first of the month, do "month day, year."
["%B %Y", function(d) { return d.getMonth() != 0 && d.getDate() == 1; }], // If the first of the month, do "month day, year."
["%Y", function(d) { return true; }] // fall back on month, year
]);
function formatDate(dttm) {
var d = UTC(new Date(dttm));
@ -44,7 +43,8 @@ function viz_nvd3(data_attribute) {
chart.lines2.xScale(d3.time.scale.utc());
chart.x2Axis
.showMaxMin(viz.form_data.x_axis_showminmax)
.tickFormat(formatDate);
.tickFormat(formatDate)
.staggerLabels(true);
} else {
chart = nv.models.lineChart()
}
@ -54,9 +54,13 @@ function viz_nvd3(data_attribute) {
chart.interpolate(viz.form_data.line_interpolation);
chart.xAxis
.showMaxMin(viz.form_data.x_axis_showminmax)
.tickFormat(formatDate);
.tickFormat(formatDate)
.staggerLabels(true);
chart.showLegend(viz.form_data.show_legend);
chart.yAxis.tickFormat(d3.format('.3s'));
if (chart.y2Axis != undefined) {
chart.y2Axis.tickFormat(d3.format('.3s'));
}
if (viz.form_data.contribution || viz.form_data.num_period_compare) {
chart.yAxis.tickFormat(d3.format('.3p'));
if (chart.y2Axis != undefined) {
@ -125,6 +129,8 @@ function viz_nvd3(data_attribute) {
chart.yAxis.tickFormat(d3.format('.3s'));
}
// make space for labels on right
chart.height($(".chart").height() - 50).margin({"right": 50});
if ((viz_type === "line" || viz_type === "area") && viz.form_data.rich_tooltip) {
chart.useInteractiveGuideline(true);
}

View File

@ -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);

View File

@ -0,0 +1,8 @@
{% macro viz_html(viz) %}
{% endmacro %}
{% macro viz_js(viz) %}
{% endmacro %}
{% macro viz_css(viz) %}
{% endmacro %}

View File

@ -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])