117 | );
118 | }
119 | }
--------------------------------------------------------------------------------
/r_scripts/reduce_candidates_data_and_bind.R:
--------------------------------------------------------------------------------
1 | library(tidyverse)
2 | library(stringr)
3 |
4 | filter_desistentes = function(df) {
5 | return(
6 | df %>% filter(!str_detect(desc_sit_candidato, regex("RENÚNCIA|CANCELAMENTO", ignore_case = FALSE)))
7 | )
8 | }
9 |
10 | dell_cols = function(df) {
11 | return(df %>%
12 | select(-c(X1,
13 | nome_coligacao,
14 | nome_urna_candidato,
15 | composicao_legenda,
16 | nome_partido,
17 | descricao_cargo))
18 | )
19 | }
20 |
21 | filter_ghost_candidates = function(df) {
22 | df %>%
23 | filter(total_votos == 0)
24 | }
25 |
26 | filter_get_candidates_fem = function(df) {
27 | return(
28 | df %>% filter(str_detect(sexo, regex("FEMININO")))
29 | )
30 | }
31 |
32 | filter_get_candidates_masc = function(df) {
33 | return(
34 | df %>% filter(str_detect(sexo, regex("MASCULINO")))
35 | )
36 | }
37 |
38 | get_ghost_candidates = function(df) {
39 | df %>% mutate(
40 | total_candidate_fem = nrow(df %>% filter_get_candidates_fem),
41 | total_candidate_masc = nrow(df %>% filter_get_candidates_masc),
42 | total_ghosts_fem = nrow(df %>% filter_get_candidates_fem %>% filter_ghost_candidates),
43 | total_ghosts_masc = nrow(df %>% filter_get_candidates_masc %>% filter_ghost_candidates)
44 | )
45 | }
46 |
47 | finish_clean = function(df) {
48 | return(df %>%
49 | select(ano_eleicao,
50 | total_candidate_fem,
51 | total_candidate_masc,
52 | total_ghosts_fem,
53 | total_ghosts_masc))
54 | }
55 |
56 | preprocess = function(df) {
57 | return(df %>%
58 | filter_desistentes %>%
59 | dell_cols %>%
60 | get_ghost_candidates %>%
61 | finish_clean %>%
62 | head(1))
63 | }
64 |
65 | data_2000 = readr::read_csv2(here::here("data/candidatos/candidatos_2000.csv"), local=readr::locale("br"))
66 | data_2002 = readr::read_csv2(here::here("data/candidatos/candidatos_2002.csv"), local=readr::locale("br"))
67 | data_2004 = readr::read_csv2(here::here("data/candidatos/candidatos_2004.csv"), local=readr::locale("br"))
68 | data_2006 = readr::read_csv2(here::here("data/candidatos/candidatos_2006.csv"), local=readr::locale("br"))
69 | data_2008 = readr::read_csv2(here::here("data/candidatos/candidatos_2008.csv"), local=readr::locale("br"))
70 | data_2010 = readr::read_csv2(here::here("data/candidatos/candidatos_2010.csv"), local=readr::locale("br"))
71 | data_2012 = readr::read_csv2(here::here("data/candidatos/candidatos_2012.csv"), local=readr::locale("br"))
72 | data_2014 = readr::read_csv2(here::here("data/candidatos/candidatos_2014.csv"), local=readr::locale("br"))
73 | data_2016 = readr::read_csv2(here::here("data/candidatos/candidatos_2016.csv"), local=readr::locale("br"))
74 |
75 | data_2000 = preprocess(data_2000)
76 | data_2002 = preprocess(data_2002)
77 | data_2004 = preprocess(data_2004)
78 | data_2006 = preprocess(data_2006)
79 | data_2008 = preprocess(data_2008)
80 | data_2010 = preprocess(data_2010)
81 | data_2012 = preprocess(data_2012)
82 | data_2014 = preprocess(data_2014)
83 | data_2016 = preprocess(data_2016)
84 |
85 | summarize_total_ghost_candidates = rbind(data_2000, data_2002)
86 | summarize_total_ghost_candidates = rbind(summarize_total_ghost_candidates, data_2004)
87 | summarize_total_ghost_candidates = rbind(summarize_total_ghost_candidates, data_2006)
88 | summarize_total_ghost_candidates = rbind(summarize_total_ghost_candidates, data_2008)
89 | summarize_total_ghost_candidates = rbind(summarize_total_ghost_candidates, data_2010)
90 | summarize_total_ghost_candidates = rbind(summarize_total_ghost_candidates, data_2012)
91 | summarize_total_ghost_candidates = rbind(summarize_total_ghost_candidates, data_2014)
92 | summarize_total_ghost_candidates = rbind(summarize_total_ghost_candidates, data_2016)
93 |
94 | summarize_total_ghost_candidates = summarize_total_ghost_candidates %>%
95 | mutate(
96 | porc_ghost_fem = round(
97 | total_ghosts_fem * 100 / total_candidate_fem,
98 | 3),
99 | porc_ghost_masc = round(
100 | total_ghosts_masc * 100 / total_candidate_masc,
101 | 3)
102 | )
103 |
104 | write.csv2(summarize_total_ghost_candidates, "data/summarize_total_ghost_candidates.csv")
105 |
--------------------------------------------------------------------------------
/client/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | // In production, we register a service worker to serve assets from local cache.
2 |
3 | // This lets the app load faster on subsequent visits in production, and gives
4 | // it offline capabilities. However, it also means that developers (and users)
5 | // will only see deployed updates on the "N+1" visit to a page, since previously
6 | // cached resources are updated in the background.
7 |
8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
9 | // This link also includes instructions on opting out of this behavior.
10 |
11 | const isLocalhost = Boolean(
12 | window.location.hostname === 'localhost' ||
13 | // [::1] is the IPv6 localhost address.
14 | window.location.hostname === '[::1]' ||
15 | // 127.0.0.1/8 is considered localhost for IPv4.
16 | window.location.hostname.match(
17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
18 | )
19 | );
20 |
21 | export default function register() {
22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
23 | // The URL constructor is available in all browsers that support SW.
24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
25 | if (publicUrl.origin !== window.location.origin) {
26 | // Our service worker won't work if PUBLIC_URL is on a different origin
27 | // from what our page is served on. This might happen if a CDN is used to
28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
29 | return;
30 | }
31 |
32 | window.addEventListener('load', () => {
33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
34 |
35 | if (isLocalhost) {
36 | // This is running on localhost. Lets check if a service worker still exists or not.
37 | checkValidServiceWorker(swUrl);
38 |
39 | // Add some additional logging to localhost, pointing developers to the
40 | // service worker/PWA documentation.
41 | navigator.serviceWorker.ready.then(() => {
42 | console.log(
43 | 'This web app is being served cache-first by a service ' +
44 | 'worker. To learn more, visit https://goo.gl/SC7cgQ'
45 | );
46 | });
47 | } else {
48 | // Is not local host. Just register service worker
49 | registerValidSW(swUrl);
50 | }
51 | });
52 | }
53 | }
54 |
55 | function registerValidSW(swUrl) {
56 | navigator.serviceWorker
57 | .register(swUrl)
58 | .then(registration => {
59 | registration.onupdatefound = () => {
60 | const installingWorker = registration.installing;
61 | installingWorker.onstatechange = () => {
62 | if (installingWorker.state === 'installed') {
63 | if (navigator.serviceWorker.controller) {
64 | // At this point, the old content will have been purged and
65 | // the fresh content will have been added to the cache.
66 | // It's the perfect time to display a "New content is
67 | // available; please refresh." message in your web app.
68 | console.log('New content is available; please refresh.');
69 | } else {
70 | // At this point, everything has been precached.
71 | // It's the perfect time to display a
72 | // "Content is cached for offline use." message.
73 | console.log('Content is cached for offline use.');
74 | }
75 | }
76 | };
77 | };
78 | })
79 | .catch(error => {
80 | console.error('Error during service worker registration:', error);
81 | });
82 | }
83 |
84 | function checkValidServiceWorker(swUrl) {
85 | // Check if the service worker can be found. If it can't reload the page.
86 | fetch(swUrl)
87 | .then(response => {
88 | // Ensure service worker exists, and that we really are getting a JS file.
89 | if (
90 | response.status === 404 ||
91 | response.headers.get('content-type').indexOf('javascript') === -1
92 | ) {
93 | // No service worker found. Probably a different app. Reload the page.
94 | navigator.serviceWorker.ready.then(registration => {
95 | registration.unregister().then(() => {
96 | window.location.reload();
97 | });
98 | });
99 | } else {
100 | // Service worker found. Proceed as normal.
101 | registerValidSW(swUrl);
102 | }
103 | })
104 | .catch(() => {
105 | console.log(
106 | 'No internet connection found. App is running in offline mode.'
107 | );
108 | });
109 | }
110 |
111 | export function unregister() {
112 | if ('serviceWorker' in navigator) {
113 | navigator.serviceWorker.ready.then(registration => {
114 | registration.unregister();
115 | });
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/server/database.py:
--------------------------------------------------------------------------------
1 | from pymongo import MongoClient
2 | from flask_pymongo import PyMongo
3 |
4 |
5 | class Client(object):
6 | '''Wrapper para operacoes com banco de dados.'''
7 | def __init__(self, app):
8 | self.client = PyMongo(app)
9 |
10 |
11 | def _update_query(self, query, args):
12 | for arg in args:
13 | if args[arg] is not None:
14 | query[arg] = args[arg]
15 | return query
16 |
17 |
18 | def historico(self):
19 | return [data for data in self.client.db.historico.find({}, {'_id': False})]
20 |
21 |
22 | def mulheres_eleitoras_vs_eleitas(self, args, ano):
23 | match = {
24 | 'genero': 'FEMININO',
25 | 'ano': ano
26 | }
27 | match = self._update_query({}, args)
28 | query = [{
29 | '$match': match
30 | },
31 | {
32 | '$group': {
33 | '_id': {},
34 | 'eleitoras_mulheres': {
35 | '$sum': '$idade'
36 | }
37 | }
38 | }
39 | ]
40 |
41 | return [data for data in self.client.db.eleitores.aggregate(query)]
42 |
43 |
44 | def partidos_ranking_zero_votos(self, args):
45 | match = self._update_query({}, args)
46 | query = [{
47 | '$match': match
48 | },
49 | {
50 | '$group': {
51 | '_id': {
52 | 'sigla_partido': '$sigla_partido'
53 | },
54 | 'total_mulheres': {
55 | '$sum': '$total_candidatas'
56 | },
57 | 'total_mulheres_zero': {
58 | '$sum': '$cont_candidatas_zero_voto'
59 | }
60 | }
61 | },
62 | {
63 | '$project': {
64 | '_id': '$_id',
65 | 'porcent_zero': {
66 | '$divide': ['$total_mulheres_zero', '$total_mulheres']
67 | },
68 | 'total_mulheres': '$total_mulheres',
69 | 'total_mulheres_zero': '$total_mulheres_zero'
70 | }
71 | },
72 | {
73 | '$sort': {
74 | 'porcent_zero': -1
75 | }
76 | },
77 | {
78 | '$limit': 3
79 | }
80 | ]
81 |
82 | return [data for data in self.client.db.partidos.aggregate(query)]
83 |
84 |
85 | def partidos_media_zero_votos(self, args):
86 | match = self._update_query({}, args)
87 | query = [{
88 | '$match': match
89 | },
90 | {
91 | '$group': {
92 | '_id': {
93 | 'sigla_partido': '$sigla_partido'
94 | },
95 | 'total': {
96 | '$sum': '$cont_candidatas_zero_voto'
97 | }
98 | }
99 | },
100 | {
101 | '$group': {
102 | '_id': {},
103 | 'total': {
104 | '$avg': '$total'
105 | }
106 | }
107 | }
108 | ]
109 |
110 | return [data for data in self.client.db.partidos.aggregate(query)]
111 |
112 |
113 | def partidos_participacao_mulheres(self, args):
114 | match = self._update_query({}, args)
115 | query = [
116 | {
117 | '$match': match
118 | },
119 | {
120 | '$group': {
121 | '_id': {
122 | 'sigla_partido': '$sigla_partido'
123 | },
124 | 'total': {
125 | '$sum': '$total_candidatos'
126 | },
127 | 'total_mulheres': {
128 | '$sum': '$total_candidatas'
129 | }
130 | }
131 | },
132 | {
133 | '$project': {
134 | 'porcentagem_mulheres': {
135 | '$divide': ['$total_mulheres', '$total']
136 | },
137 | 'total': '$total',
138 | 'total_mulheres': '$total_mulheres'
139 | }
140 | },
141 | {
142 | '$sort': {
143 | 'porcentagem_mulheres': -1
144 | }
145 | }
146 | ]
147 |
148 | return [data for data in self.client.db.partidos.aggregate(query)]
--------------------------------------------------------------------------------
/client/src/components/visualizacoes/VotosVSInvestimentos.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2016 - 2017 Uber Technologies, Inc.
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in
11 | // all copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | // THE SOFTWARE.
20 |
21 | import React from 'react';
22 | import PropTypes from 'prop-types';
23 | import {
24 | XYPlot,
25 | XAxis,
26 | YAxis,
27 | MarkSeries,
28 | Hint,
29 | makeWidthFlexible
30 | } from 'react-vis';
31 |
32 |
33 | const tipStyle = {
34 | display: 'flex',
35 | color: '#fff',
36 | background: '#000',
37 | alignItems: 'right',
38 | padding: '2px'
39 | };
40 |
41 | const boxStyle = {height: '2px', width: '2px'};
42 |
43 |
44 | const dados = [
45 | {_id:{sigla_partido:"pt"},
46 | investimento: 1,
47 | votos: 10,
48 | n_mulheres: 30
49 | },
50 | {_id:{sigla_partido:"novo"},
51 | investimento: 10,
52 | votos: 25,
53 | n_mulheres: 12
54 | },
55 | {_id:{sigla_partido:"pmdb"},
56 | investimento: 40,
57 | votos: 2,
58 | n_mulheres: 65
59 | },
60 | {_id:{sigla_partido:"psol"},
61 | investimento: 104,
62 | votos: 80,
63 | n_mulheres: 5
64 | }
65 | ]
66 |
67 | export default class VotosVSInvestimentos extends React.Component {
68 | state = {
69 | value: false,
70 |
71 | }
72 | render() {
73 | const {
74 | value
75 | } = this.state;
76 |
77 | const dataPlot = dados.map(elem => {
78 | return {
79 | x: elem.investimento,
80 | y: elem.votos,
81 | partido: elem._id.sigla_partido,
82 | size: elem.n_mulheres,
83 | color: Math.random()
84 | }
85 | });
86 |
87 | const partidos = dataPlot.map(elem =>{
88 | return elem.partido
89 | }
90 | )
91 | const colors = dataPlot.map(elem =>{
92 | return elem.color
93 | })
94 | const bubblePlot = ({ width }) =>
101 |
102 |
103 | console.log(e)}
110 | onValueMouseOver={v => this.setState({value: v.x && v.y ? v: false}) }
111 | onSeriesMouseOut={() => this.setState({value: false})}
112 | >
113 |
114 |
115 | {this.state.value ?
116 |
117 |
118 | Partido {this.state.value.partido} com investimento de
119 | {this.state.value.x} milhões
120 | e {this.state.value.y} mil votos em {this.state.value.size}
121 | mulheres do partido.
122 |