Source code for mapache.vis

# mapache, @cesans 2016 (c)

import matplotlib.pylab as plt
import matplotlib
import numpy as np
from sklearn import gaussian_process
import time
import datetime

[docs]class SingleBars: def __init__(self, poll, parties, elections=None, join_coalitions=True): plt.rcParams['figure.figsize'] = (12, 6) self._fig, ax = plt.subplots() plt.rcParams['xtick.labelsize'] = 16 plt.rcParams['axes.labelweight'] = 'bold' plt.rcParams['font.weight'] = 'normal' plt.rcParams['xtick.major.pad']='16' plt.rcParams['axes.titlesize'] = 20 plt.rcParams['axes.titleweight'] = 'bold' parties_votes = [] for i, p in enumerate(parties.parties.values()): parties_votes.append((p, poll.get_party(p,join_coalitions))) parties_votes.sort(key=lambda x: x[1], reverse=True) parties_votes = [] for i, p in enumerate(parties.parties.values()): parties_votes.append((p, poll.get_party(p,join_coalitions))) parties_votes.sort(key=lambda x: x[1], reverse=True) width = 0.6 left_lim = 0.1 plt.title(poll.pollster + poll.date.strftime(' - %-d %b'), loc='left', x=0, y=1.1, fontdict={'ha':'left'}) names = [] for i, (p, votes) in enumerate(parties_votes): a = ax.bar(left_lim+i, votes, width=width, color=p.color, edgecolor='none') ax.text(left_lim+i+width/2, votes-4, '{0}%'.format(votes), fontdict={'weight':'bold', 'color':'w', 'fontsize':'20', 'ha':'center', 'va':'center'}) names.append(p.short_name) if elections: vot =elections.get_party(p,join_coalitions) if a: plt.plot([left_lim+i-0.1*width, left_lim+i+width+0.1*width], [vot, vot], color=[0.2,0.2,0.2], linewidth=3) idx = np.arange(len(parties.parties))+width/2 + left_lim ax.set_xticks(idx) ax.set_xlim([0, idx[-1]+width/2 + left_lim]) ax.set_xticklabels(names); ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) ax.spines['left'].set_visible(False) ax.xaxis.set_ticks_position('none') ax.yaxis.set_ticks_position('none') if poll.error: plt.figtext(0.125,.94,'({}% error)'.format(poll.error), fontdict={'fontsize': 12})
[docs] def export(self, filename): """ TODO :param filename: :return: """ self._fig.savefig(filename)
def _percentage_formatter(y, _): """ TODO :param y: :return: """ s = str(y) if matplotlib.rcParams['text.usetex'] is True: return s + r'$\%$' else: return s + '%'
[docs]class TimeSeries: """ TODO """ def __init__(self, parties): """ TODO :param parties: :return: """ #TODO sure? plt.rcParams['figure.figsize'] = (18,12) self.parties = parties self.columns = [] self.__up_to_date = False self.__fig = None
[docs] def add_column(self, polls, main=False): """ TODO :param polls: :param main: :return: """ self.__fig = None self.columns.append({'polls': polls, 'main': main})
[docs] def show(self): """ TODO :return: """ if self.__fig is None: self.__create_fig() plt.show()
[docs] def export(self, filename): """ TODO :param filename: :return: """ # TODO if self.__fig is None: self.__create_fig() pass
def __create_fig(self): """ TODO :return: """ self.__fig = plt.figure() if not self.columns: print('No columns have been added') return range_lengths = [] for c in self.columns: # TODO add get_dates() to ListPolls!! dates = [p.date for p in c['polls'].polls] range_lengths.append((max(dates) - min(dates)).days) # range_lengths = [c['polls']['dates'][-1] - c['polls']['dates'][0] for c in self.columns] range_lengths_nonzero = [r for r in range_lengths if r != 0] total_length = (sum(range_lengths) / (1 - (len(self.columns) - len(range_lengths_nonzero)) * 0.1)) range_lengths = [r / total_length if r != 0 else 0.1 for r in range_lengths] gs = matplotlib.gridspec.GridSpec(1, len(self.columns), width_ratios=range_lengths) for i, c in enumerate(self.columns): ax = plt.subplot(gs[i]) first = False last = False if i == 0: first = True if i == len(self.columns) - 1: last = True self.__draw_column(c['polls'], ax, first, last) max_percentage = 0 for i, c in enumerate(self.columns): for poll in c['polls'].polls: for name, percentages in poll.parties.items(): max_percentage = max(max_percentage, np.max(percentages)) yticks = [tick for tick in [10, 20, 30, 40, 50, 60, 70, 80, 90] if tick < max_percentage] for g in gs: ax = plt.subplot(g) ax.set_yticks(yticks, minor=False) ax.set_ylim(0, min(max_percentage + 5, 100)) def __draw_column(self, polls, ax, first=False, last=False): """ TODO :param polls: :param first: :param last: :return: """ self.__fig = None #From type!! dates = [p.date for p in polls.polls] single = len(dates) == 1 title_loc = 'left' if single: title_loc = 'center' ax.set_title(polls._name, loc=title_loc) self.__scatter(polls, self.parties, ax, single, last) if not single: self.__gp(polls, self.parties, ax) ax.set_yticks([10, 20, 30, 40, 50, 60, 70, 80, 90], minor=False) ax.yaxis.grid(True, which='major') ax.yaxis.grid(True, which='minor') ax.spines['top'].set_visible(False) ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) ax.spines['bottom'].set_visible(True) ax.spines['left'].set_visible(False) ax.yaxis.set_ticks_position('none') ax.xaxis.set_ticks_position('bottom') formatter = matplotlib.ticker.FuncFormatter(_percentage_formatter) ax.get_yaxis().set_major_formatter(formatter) # ax.set_xlim(polls['dates'][0] - 0.5, polls['dates'][-1] + 0.5) if not first: ax.set_yticklabels([]) if single: #TODO fix! ax.set_xticks([polls.polls[0].date], minor=False) pass def __scatter(self, polls, parties, ax, single=False, last=False): """ TODO :param single: :return: """ last_date = datetime.datetime.min for party in parties.parties.values(): polls_party = polls.get_party(party) dates = [x[0] for x in polls_party] votes = [x[1] for x in polls_party] if single: ax.scatter(dates, votes, 70, c=party.color, edgecolors='none', label=u'Observations') else: ax.scatter(dates, votes, c=np.append(party.color, [0.6]), edgecolors='none', s=40, label=u'Observations') last_date = max(last_date, max(dates)) if last: # TODO move to last point of regression, not poll #TODO add name label at the end! for party in parties.parties.values(): polls_party = polls.get_party(party) last_date_arg = np.argmin([x[0] for x in polls_party]) votes = polls_party[last_date_arg][1] polls_party = polls.get_party(party) plt.text(last_date, votes, ' ' + party.short_name, color=party.color, weight='bold', verticalalignment='center', fontsize=20) def __gp(self,polls, parties, ax): """ TODO :param x: :param ax: :param partyname: :return: """ for party in parties.parties.values(): polls_party = polls.get_party(party) dates = [x[0] for x in polls_party] votes = [x[1] for x in polls_party] x = dates y = votes # + 0.5 - 0.5? x_dense = np.atleast_2d(np.linspace(time.mktime(x[0].timetuple()), time.mktime(x[-1].timetuple()), 1000)).T #x_dense = np.atleast_2d(np.linspace(x[0], x[-1], 1000)).T np.random.seed(1) gp = gaussian_process.GaussianProcess(corr='squared_exponential', theta0=1e-1, thetaL=1e-3, thetaU=1, random_start=100, nugget=10 - 8) x = [time.mktime(xi.timetuple()) for xi in x] gp.fit(np.reshape(x, (-1, 1)) + np.random.randn(len(x),1)*0.01, np.reshape(y,(-1, 1))) y_pred, mse = gp.predict(x_dense, eval_MSE=True) sigma = np.sqrt(mse) x_dense = [datetime.datetime.fromtimestamp(xi) for xi in x_dense] ax.plot(x_dense, y_pred, 'b-', label=u'Prediction', c=party.color, linewidth=3)
# TODO Check and (maybe) fix? # ax.fill(np.concatenate([x_dense, x_dense[::-1]]), # np.concatenate([y_pred - 1.9600 * sigma, # (y_pred + 1.9600 * sigma)[::-1]]), # color=np.append(party.color, [0.1]), fc='b', ec='None', # label='95% confidence interval')