From: Tom Rees Date: Fri, 25 Jan 2013 12:06:59 +0000 Subject: #167 Refactoring controller's logic to create better Percentage graphs X-Git-Url: http://maxious.lambdacomplex.org/git/?p=ckanext-ga-report.git&a=commitdiff&h=66388ec20aa1030e4cd7333f4ee6f4c75876b1c3 --- #167 Refactoring controller's logic to create better Percentage graphs --- --- a/ckanext/ga_report/controller.py +++ b/ckanext/ga_report/controller.py @@ -411,49 +411,52 @@ if data==[]: return data # Create a consistent x-axis - num_points = [ len(package['data']) for package in data ] + num_points = [ len(series['data']) for series in data ] ideal_index = num_points.index( max(num_points) ) x_axis = [ point['x'] for point in data[ideal_index]['data'] ] - for package in data: - xs = [ point['x'] for point in package['data'] ] + for series in data: + xs = [ point['x'] for point in series['data'] ] assert set(xs).issubset( set(x_axis) ), (xs, x_axis) # Zero pad any missing values for x in set(x_axis).difference(set(xs)): - package['data'].append( {'x':x, 'y':0} ) - assert len(package['data'])==len(x_axis), (len(package['data']),len(x_axis),package['data'],x_axis,set(x_axis).difference(set(xs))) + series['data'].append( {'x':x, 'y':0} ) + assert len(series['data'])==len(x_axis), (len(series['data']),len(x_axis),series['data'],x_axis,set(x_axis).difference(set(xs))) if percentageMode: + def get_totals(series_list): + totals = {} + for series in series_list: + for point in series['data']: + totals[point['x']] = totals.get(point['x'],0) + point['y'] + lengths = [ len(series['data']) for series in series_list ] + assert len(set(lengths))==1 + assert lengths[0] == len(totals) + return totals # Transform data into percentage stacks - totals = {} - for x in x_axis: - for package in data: - for point in package['data']: - totals[ point['x'] ] = totals.get(point['x'],0) + point['y'] + totals = get_totals(data) # Roll insignificant series into a catch-all THRESHOLD = 0.01 - significant_series = [] - for package in data: - for point in package['data']: + raw_data = data + data = [] + for series in raw_data: + for point in series['data']: fraction = float(point['y']) / totals[point['x']] - if fraction>THRESHOLD and not (package in significant_series): - significant_series.append(package) - temp = {} - for package in data: - if package in significant_series: continue - for point in package['data']: - temp[point['x']] = temp.get(point['x'],0) + point['y'] - catch_all = { 'name':'Other','data': [ {'x':x,'y':y} for x,y in temp.items() ] } - # Roll insignificant series into one - data = significant_series - data.append(catch_all) + if not (series in data) and fraction>THRESHOLD: + data.append(series) + # Overwrite data with a set of intereting series + others = [ x for x in raw_data if not (x in data) ] + data.append({ + 'name':'Other', + 'data': [ {'x':x,'y':y} for x,y in get_totals(others).items() ] + }) # Turn each point into a percentage - for package in data: - for point in package['data']: + for series in data: + for point in series['data']: point['y'] = (point['y']*100) / totals[point['x']] # Sort the points - for package in data: - package['data'] = sorted( package['data'], key=lambda x:x['x'] ) + for series in data: + series['data'] = sorted( series['data'], key=lambda x:x['x'] ) # Strip the latest month's incomplete analytics - package['data'] = package['data'][:-1] + series['data'] = series['data'][:-1] return data --- a/ckanext/ga_report/public/scripts/ckanext_ga_reports.js +++ b/ckanext/ga_report/public/scripts/ckanext_ga_reports.js @@ -1,9 +1,18 @@ - var CKAN = CKAN || {}; CKAN.GA_Reports = {}; CKAN.GA_Reports.render_rickshaw = function( css_name, data, mode, colorscheme ) { var graphLegends = $('#graph-legend-container'); + + if (!Modernizr.svg) { + $("#chart_"+css_name) + .html( '
Your browser does not support vector graphics. No graphs can be rendered.
') + .closest('.rickshaw_chart_container').css('height',50); + var myLegend = $('
') + .html('(Graph cannot be rendered)') + .appendTo(graphLegends); + return; + } var myLegend = $('
').appendTo(graphLegends); var palette = new Rickshaw.Color.Palette( { scheme: colorscheme } ); @@ -24,20 +33,15 @@ graph: graph, orientation: 'left', tickFormat: Rickshaw.Fixtures.Number.formatKMBT, - element: document.getElementById('y_axis_'+css_name), + element: document.getElementById('y_axis_'+css_name) } ); var legend = new Rickshaw.Graph.Legend( { element: document.querySelector('#legend_'+css_name), graph: graph } ); - var hoverDetail = new Rickshaw.Graph.HoverDetail( { + var shelving = new Rickshaw.Graph.Behavior.Series.Toggle( { graph: graph, - formatter: function(series, x, y) { - var date = '' + new Date(x * 1000).toUTCString() + ''; - var swatch = ''; - var content = swatch + series.name + ": " + parseInt(y) + '
' + date; - return content; - } + legend: legend } ); graph.render(); }; --- /dev/null +++ b/ckanext/ga_report/public/scripts/rickshaw_ie7_shim.js @@ -1,1 +1,109 @@ +/* + * Collection of shims to allow d3 and Rickshaw to load, error-free + * (but ultimately unusable) on Internet Explorer 7. The browser's + * API lacks several crucial functions which these libraries depend + * upon to load; we try to hide these errors from the user. + * + * With thanks to Array functions from: + * http://stackoverflow.com/questions/2790001/fixing-javascript-array-functions-in-internet-explorer-indexof-foreach-etc + * + * Use (Modernizr.svg==true) to detect whether it's okay to draw a graph. + */ +'use strict'; +window.Element = window.Element || {'prototype': {}}; +window.CSSStyleDeclaration = window.CSSStyleDeclaration || {'prototype':{}}; + +// Add ECMA262-5 method binding if not supported natively +// +if (!('bind' in Function.prototype)) { + Function.prototype.bind= function(owner) { + var that= this; + if (arguments.length<=1) { + return function() { + return that.apply(owner, arguments); + }; + } else { + var args= Array.prototype.slice.call(arguments, 1); + return function() { + return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments))); + }; + } + }; +} + +// Add ECMA262-5 string trim if not supported natively +// +if (!('trim' in String.prototype)) { + String.prototype.trim= function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + }; +} + +// Add ECMA262-5 Array methods if not supported natively +// +if (!('indexOf' in Array.prototype)) { + Array.prototype.indexOf= function(find, i /*opt*/) { + if (i===undefined) i= 0; + if (i<0) i+= this.length; + if (i<0) i= 0; + for (var n= this.length; ithis.length-1) i= this.length-1; + for (i++; i-->0;) /* i++ because from-argument is sadly inclusive */ + if (i in this && this[i]===find) + return i; + return -1; + }; +} +if (!('forEach' in Array.prototype)) { + Array.prototype.forEach= function(action, that /*opt*/) { + for (var i= 0, n= this.length; i
Download as CSV

+ +
  • +

    Graph Legend

    +
    +
  • --- a/ckanext/ga_report/templates/ga_report/publisher/read.html +++ b/ckanext/ga_report/templates/ga_report/publisher/read.html @@ -23,6 +23,11 @@

    Download as CSV

    + +
  • +

    Graph Legend

    +
    +
  • --- a/ckanext/ga_report/templates/ga_report/site/index.html +++ b/ckanext/ga_report/templates/ga_report/site/index.html @@ -12,6 +12,7 @@ + @@ -142,7 +143,12 @@ $(function() { CKAN.GA_Reports.bind_sparklines(); CKAN.GA_Reports.bind_sidebar(); - $(window).trigger('hashchange'); + if (!window.location.hash) { + window.location.hash='totals'; + } + else { + $(window).trigger('hashchange'); + } });