Skip to content
This repository has been archived by the owner on Dec 23, 2017. It is now read-only.

Commit

Permalink
Merge pull request #350 from jmcarp/feature/filings-tab
Browse files Browse the repository at this point in the history
Feature/filings tab
  • Loading branch information
LindsayYoung committed Jul 22, 2015
2 parents bc18560 + c964ba1 commit 8042786
Show file tree
Hide file tree
Showing 40 changed files with 940 additions and 335 deletions.
11 changes: 11 additions & 0 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import http
import datetime

import furl
from webargs import Arg
Expand Down Expand Up @@ -72,6 +73,14 @@ def series_group_has_data(groups, keys):
)


def cycle_start(value):
return datetime.datetime(value - 1, 1, 1)


def cycle_end(value):
return datetime.datetime(value, 12, 31)


app.jinja_env.globals.update({
'min': min,
'max': max,
Expand All @@ -86,6 +95,8 @@ def series_group_has_data(groups, keys):
'series_has_data': series_has_data,
'group_has_data': group_has_data,
'series_group_has_data': series_group_has_data,
'cycle_start': cycle_start,
'cycle_end': cycle_end,
})


Expand Down
5 changes: 5 additions & 0 deletions openfecwebapp/api_caller.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,8 @@ def load_cmte_financials(committee_id, **filters):
'reports': reports['results'],
'totals': totals['results'],
}


def load_cmte_aggregates(committee_id, aggregate, cycle):
response = _call_api('committee', committee_id, 'schedules', 'schedule_a', aggregate, cycle=cycle)
return response['results']
30 changes: 27 additions & 3 deletions openfecwebapp/views.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import datetime
import collections

from flask import render_template
from werkzeug.exceptions import abort

from openfecwebapp.api_caller import load_cmte_financials
from openfecwebapp import api_caller


def render_search_results(results, query, result_type):
Expand All @@ -15,22 +16,40 @@ def render_search_results(results, query, result_type):
)


def to_date(committee, cycle):
if committee['committee_type'] in ['H', 'S', 'P']:
return None
return min(datetime.datetime.now().year, cycle)


def render_committee(data, candidates=None, cycle=None):
committee = get_first_result_or_raise_500(data)

# committee fields will be top-level in the template
tmpl_vars = committee

tmpl_vars['cycle'] = cycle
tmpl_vars['year'] = to_date(committee, cycle)
tmpl_vars['result_type'] = 'committees'

# add related candidates a level below
tmpl_vars['candidates'] = candidates

financials = load_cmte_financials(committee['committee_id'], cycle=cycle)
financials = api_caller.load_cmte_financials(committee['committee_id'], cycle=cycle)
tmpl_vars['reports'] = financials['reports']
tmpl_vars['totals'] = financials['totals']

tmpl_vars['aggregates'] = {
'size': {
each['size']: each['total']
for each in api_caller.load_cmte_aggregates(
committee['committee_id'],
'by_size',
cycle=cycle,
)
}
}

return render_template('committees-single.html', **tmpl_vars)


Expand Down Expand Up @@ -66,7 +85,12 @@ def render_candidate(data, committees, cycle):
committee_groups = groupby(committees, lambda each: each['designation'])
committees_authorized = committee_groups.get('P', []) + committee_groups.get('A', [])
for committee in committees_authorized:
committee.update(load_cmte_financials(committee['committee_id'], cycle=cycle))
committee.update(
api_caller.load_cmte_financials(
committee['committee_id'],
cycle=cycle,
)
)

tmpl_vars['committee_groups'] = committee_groups
tmpl_vars['committees_authorized'] = committees_authorized
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"dependencies": {
"URIjs": "1.15.1",
"browserify": "10.2.4",
"chroma-js": "1.0.1",
"d3": "3.5.5",
"datatables": "1.10.7",
"drmonty-datatables-responsive": "1.0.6",
Expand All @@ -56,6 +57,7 @@
"perfect-scrollbar": "0.6.2",
"preprocessify": "0.0.3",
"querystring": "0.2.0",
"topojson": "1.6.19",
"typeahead.js": "0.10.5",
"underscore": "1.8.3",
"vinyl-buffer": "1.0.0",
Expand Down
4 changes: 4 additions & 0 deletions static/js/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@ var charts = require('./modules/charts.js');
var glossary = require('./modules/glossary.js');
var Search = require('./modules/search');
var tables = require('./modules/tables');
var maps = require('./modules/maps');
var toggle = require('./modules/toggle');

typeahead.init();
glossary.init();
charts.init();
maps.init();

var SLT_ACCORDION = '.js-accordion';

Expand Down Expand Up @@ -173,4 +176,5 @@ $(document).ready(function() {

filters.init();
tables.init();
toggle.init();
});
149 changes: 149 additions & 0 deletions static/js/modules/maps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
'use strict';

/* global require, module, window, document, API_LOCATION, API_VERSION, API_KEY */

var d3 = require('d3');
var $ = require('jquery');
var URI = require('URIjs');
var _ = require('underscore');
var chroma = require('chroma-js');
var topojson = require('topojson');

var events = require('./events');
var helpers = require('./helpers');
var states = require('../us.json');

var compactRules = [
['B', 9],
['M', 6],
['k', 3]
];

function chooseRule(value) {
return _.find(compactRules, function(rule) {
return value >= Math.pow(10, rule[1]);
});
}

function compactNumber(value, rule) {
var divisor = Math.pow(10, rule[1]);
return d3.round(value / divisor, 1).toString() + rule[0];
}

function stateMap($elm, width, height) {
var url = URI(API_LOCATION)
.path([
API_VERSION,
'committee',
$elm.data('committee-id'),
'schedules',
'schedule_a',
'by_state'
].join('/'))
.query({
cycle: $elm.data('cycle'),
per_page: 99
})
.toString();

var svg = d3.select($elm[0])
.append('svg')
.attr('width', width)
.attr('height', height);
var projection = d3.geo.albersUsa()
.scale(450)
.translate([220, 250]);
var path = d3.geo.path().projection(projection);

d3.json(url, function(error, data) {
var results = _.reduce(
data.results,
function(acc, val) {
acc[val.state_full] = val.total;
return acc;
},
{}
);
var quantiles = 4;
var max = _.max(_.pluck(data.results, 'total'));
var scale = chroma.scale(['#fff', '#2678BA']).domain([0, max]);
var quantize = chroma.scale(['#fff', '#2678BA']).domain([0, max], quantiles);
var map = svg.append('g')
.selectAll('path')
.data(topojson.feature(states, states.objects.units).features)
.enter().append('path')
.attr('fill', function(d) {
return scale(results[d.properties.name]);
})
.attr('data-state', function(d) {
return d.properties.name;
})
.attr('class', 'shape')
.attr('d', path);

// Add legend swatches
var legendWidth = 40;
var legendBar = 35;
var legend = svg.selectAll('g.legend')
.data(quantize.domain())
.enter()
.append('g')
.attr('class', 'legend');
legend.append('rect')
.attr('x', function(d, i) {
return i * legendWidth + (legendWidth - legendBar) / 2;
})
.attr('y', 20)
.attr('width', legendBar)
.attr('height', 20)
.style('fill', function(d) {
return scale(d);
});

// Add legend text
var compactRule = chooseRule(quantize.domain()[Math.floor(quantiles / 2)]);
legend.append('text')
.attr('x', function(d, i) {
return (i + 0.5) * legendWidth;
})
.attr('y', 50)
.attr('width', legendWidth)
.attr('height', 20)
.attr('font-size', '10px')
.attr('text-anchor', 'middle')
.text(function(d) {
return compactNumber(d, compactRule);
});
});
}

function highlightState($parent, state) {
var rule = '[data-state="' + state + '"]';
$parent.find('path:not(' + rule + ')').each(function(idx, elm) {
elm.classList.remove('active');
});
var $path = $parent.find('path' + rule);
if ($path.length) {
$path[0].classList.add('active');
}
}

function init() {
$('.state-map').each(function(idx, elm) {
var $elm = $(elm);
stateMap($elm, 400, 400);
events.on('state.table', function(params) {
highlightState($elm, params.state);
});
$elm.on('click', 'path[data-state]', function(e) {
var state = $(this).attr('data-state');
highlightState($elm, state);
events.emit('state.map', {state: state});
});
});
}

module.exports = {
init: init,
stateMap: stateMap
};
Loading

0 comments on commit 8042786

Please sign in to comment.