Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add similar people to individual persons' pages #41

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 88 additions & 1 deletion pokr/controllers/person.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# -*- coding: utf-8 -*-
import math
import numpy

from collections import Counter, defaultdict, OrderedDict

from .base import Controller
from pokr.cache import cache
from pokr.database import db_session
from pokr.models import Bill, Candidacy, cosponsorship, Meeting, Party, Person, Pledge, Statement

from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.sql.expression import select

class PersonController(Controller):
model = 'person'
Expand Down Expand Up @@ -100,3 +104,86 @@ def sorted_statements(cls, person):
.filter(Statement.person_id==person.id)\
.order_by(Meeting.date.desc().nullslast(), Statement.sequence)

@classmethod
def get_similar_assembly_members(cls, person, assembly_id):
ideology_tuples = calculate_ideology_tuple(assembly_id)
# find the person's ideology level
self_ideology_tuple = None
for ideology_tuple in ideology_tuples:
if ideology_tuple[0] == person.id:
self_ideology_tuple = ideology_tuple
break

#remove self from the tuples
ideology_tuples.remove(self_ideology_tuple)
self_ideology = self_ideology_tuple[1]

# find the most similar 5 persons
diff_ideology_tuples = map(lambda tuple: (tuple[0], math.fabs(tuple[1] - self_ideology)), ideology_tuples)
diff_ideology_tuples.sort(cmp=lambda x,y: cmp(x[1], y[1]))
similar_people_ids = map(lambda tuple: tuple[0], diff_ideology_tuples[:5])

return Person.query\
.filter(Person.id.in_(similar_people_ids))\
.all()



def rescale(u):
u = (u - min(u)) / (max(u) - min(u))
return [float(v) for v in u]

# Also draws heavily from govtrack.us
@cache.memoize(timeout=60*60*24)
def generate_cosponsorship_matrix(assembly_id):
try:
bills = Bill.query.filter(Bill.assembly_id==assembly_id).all()
rep_to_row = {}
cosponsorships = []

def rownum(id):
if not id in rep_to_row:
rep_to_row[id] = len(rep_to_row)
return rep_to_row[id]

for bill in bills:
reps = bill.representative_people
if len(reps) == 0:
continue

for rep in reps:
for cosponsor in bill.cosponsors:
rownum(cosponsor.id)
cosponsorships.append((rep.id, cosponsor.id))

P = numpy.identity(len(rep_to_row), numpy.float)
for sponsor, cosponsor in cosponsorships:
P[rep_to_row[sponsor], rep_to_row[cosponsor]] += 1.0

except NoResultFound, e:
print e

return rep_to_row, P

# Got a lot of inspiration from govtrack.us
@cache.memoize(timeout=60*60*24)
def calculate_ideology_tuple(assembly_id):
try:
rep_to_row, P = generate_cosponsorship_matrix(assembly_id)
u, s, vh = numpy.linalg.svd(P)
spectrum = vh[1,:]
spectrum = rescale(spectrum)
ids = [None for k in rep_to_row]
for k, v in rep_to_row.items():
ids[v] = k

ideology_tuples = []
for index, person_id in enumerate(ids):
ideology_tuples.append((person_id, spectrum[index]))

ideology_tuples.sort(cmp=lambda x,y: cmp(x[1], y[1]))

except NoResultFound, e:
print e

return ideology_tuples
43 changes: 26 additions & 17 deletions pokr/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2015-04-01 17:11+0900\n"
"POT-Creation-Date: 2015-04-08 08:14-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.6\n"
"Generated-By: Babel 1.3\n"

#: pokr/models/meeting.py:49
#, python-format
Expand All @@ -32,7 +32,7 @@ msgstr ""
msgid "%(sitting_id)sth sitting"
msgstr ""

#: pokr/templates/bill-layout.html:10 pokr/templates/bill.html:142
#: pokr/templates/bill-layout.html:10 pokr/templates/bill.html:140
msgid "The summary of this bill has not been updated."
msgstr ""

Expand Down Expand Up @@ -74,50 +74,50 @@ msgstr ""
msgid "see official page"
msgstr ""

#: pokr/templates/bill.html:68
#: pokr/templates/bill.html:67
msgid "suggest to assembly"
msgstr ""

#: pokr/templates/bill.html:70
#: pokr/templates/bill.html:68
msgid "see original pdf"
msgstr ""

#: pokr/templates/bill.html:71
#: pokr/templates/bill.html:69
msgid "see original text"
msgstr ""

#: pokr/templates/bill.html:79
#: pokr/templates/bill.html:77
msgid "sponsors"
msgstr ""

#: pokr/templates/bill.html:82 pokr/templates/bill.html:105
#: pokr/templates/bill.html:80 pokr/templates/bill.html:103
#: pokr/templates/macros.html:105 pokr/templates/person-legislations.html:64
msgid "representative sponsor"
msgstr ""

#: pokr/templates/bill.html:93 pokr/templates/bill.html:119
#: pokr/templates/bill.html:91 pokr/templates/bill.html:117
msgid "cosponsors"
msgstr ""

#: pokr/templates/bill.html:134
#: pokr/templates/bill.html:132
msgid "contents"
msgstr ""

#: pokr/templates/bill.html:137 pokr/templates/party.html:43
#: pokr/templates/bill.html:135 pokr/templates/party.html:43
msgid "summary"
msgstr ""

#: pokr/templates/bills.html:5 pokr/templates/bills.html:9
msgid "bills"
msgstr ""

#: pokr/templates/bills.html:29 pokr/templates/parties.html:30
#: pokr/templates/bills.html:30 pokr/templates/parties.html:30
#: pokr/templates/people.html:29 pokr/templates/region.html:54
#: pokr/templates/region.html:99
msgid "th"
msgstr ""

#: pokr/templates/bills.html:57 pokr/templates/macro-statement.html:6
#: pokr/templates/bills.html:62 pokr/templates/macro-statement.html:6
#: pokr/templates/macros.html:95 pokr/templates/mypage.html:88
#: pokr/templates/mypage.html:113 pokr/templates/person-legislations.html:29
#: pokr/templates/person-legislations.html:73
Expand All @@ -126,7 +126,7 @@ msgstr ""
msgid "more"
msgstr ""

#: pokr/templates/bills.html:58 pokr/templates/district-feeds.html:19
#: pokr/templates/bills.html:63 pokr/templates/district-feeds.html:19
msgid "No summary"
msgstr ""

Expand Down Expand Up @@ -554,6 +554,7 @@ msgstr ""

#: pokr/templates/person-legislations.html:13
#: pokr/templates/person-legislations.html:53
#: pokr/templates/person-similar-people.html:18
msgid "th assembly"
msgstr ""

Expand All @@ -566,6 +567,14 @@ msgstr ""
msgid "role"
msgstr ""

#: pokr/templates/person-similar-people.html:4
msgid "similar people"
msgstr ""

#: pokr/templates/person-similar-people.html:8
msgid "based on cosponsorships"
msgstr ""

#: pokr/templates/person-statements.html:6
msgid "Statements"
msgstr ""
Expand Down Expand Up @@ -620,11 +629,11 @@ msgstr ""
msgid "Wikipedia"
msgstr ""

#: pokr/templates/person.html:161
#: pokr/templates/person.html:162
msgid "trends"
msgstr ""

#: pokr/templates/person.html:163
#: pokr/templates/person.html:164
#, python-format
msgid "Results from Google Trends searched by query %(name)s"
msgstr ""
Expand Down Expand Up @@ -736,7 +745,7 @@ msgid "sources"
msgstr ""

#: pokr/templates/includes/header.html:15
#: pokr/templates/includes/header.html:17 pokr/views/bill.py:19
#: pokr/templates/includes/header.html:17 pokr/views/bill.py:26
msgid "bill"
msgstr ""

Expand Down
18 changes: 18 additions & 0 deletions pokr/static/less/person.less
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,24 @@
}
}

#section-similar-people {
div.content {
div.group {
div {
display: inline-block;

&.similarity {
width: 13%;
}

&.people {

}
}
}
}
}

#section-elections {
tr:first-child th,
tr:first-child td {
Expand Down
32 changes: 32 additions & 0 deletions pokr/templates/person-similar-people.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{% import 'macros.html' as macro with context %}

<div id="section-similar-people" class="section">
<h3 id="similar-people">{{ gettext('similar people') }}</h3>
<table id="person-legislations" class="table table-condensed">
<thead>
<tr>
<th>{{ gettext('based on cosponsorships') }}</th>
<th></th>
</tr>
</thead>
<tbody>
{% for candidacy in person.candidacies %}
{% if candidacy.is_elected %}
{% set similar_assembly_members = PersonController.get_similar_assembly_members(person, candidacy.assembly_id) %}
<tr>
<td>
<a href="{{ url_for('person_main', assembly_id=candidacy.assembly_id) }}">{{ candidacy.assembly_id }}{{ gettext('th assembly') }}</a>
</td>
<td>
{% for similar_assembly_member in similar_assembly_members %}
<span class="people">
<a href="{{ url_for('person', id=similar_assembly_member.id) }}">{{ similar_assembly_member.name }}</a>
</span>
{% endfor %}
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
1 change: 1 addition & 0 deletions pokr/templates/person.html
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ <h3 id="profile">
</div>
{% endif %}
</div>
{% if has_bills %}{% include 'person-similar-people.html' with context %}{% endif %}
{% if has_bills %}{% include 'person-legislations.html' with context %}{% endif %}
{% include 'person-statements.html' with context %}
{% include 'person-elections.html' with context %}
Expand Down
Binary file modified pokr/translations/ko/LC_MESSAGES/messages.mo
Binary file not shown.
Loading