index.html
<html>
<head>
<meta charset="utf-8" />
<script src="./plotly-1.35.2.min.js"></script>
<script src="./plotly-locale-cs.js"></script>
</head>
<body>
<div id="tester" style="width:900px;height:800px;"></div>
Pozn: intervaly jsou jen hrubý odhad na ukázku
<script>
var hex2rgba = (str, a) => str.replace('#','').split('').reduce((r,c,i,{length: l},j,n)=>(j=parseInt(i*3/l),n=parseInt(c,16),r[j]=(l==3?n:r[j])*16+n,r),[0,0,0,a||1]);
var electionData = [
{name:"Zelení", value: 0.0146, color:"#06b15d"},
{name:"Svobodní", value: 0.0156, color:"#009982"},
{name:"STAN", value: 0.0518, color:"#5d8c00"},
{name:"TOP 09", value: 0.0531, color:"#723769"},
{name:"KDU-ČSL", value: 0.0580, color:"#e6ac21"},
{name:"ČSSD", value: 0.0727, color:"#F07D00"},
{name:"KSČM", value: 0.0776, color:"#8c0000"},
{name:"SPD", value: 0.1064, color:"#ea2329"},
{name:"Piráti", value: 0.1079, color:"#000000"},
{name:"ODS", value: 0.1132, color:"#004494"},
{name:"ANO", value: 0.2964, color:"#261060"}
];
var electionDate = '2017-10-21';
var dates = ['2017-12-17', '2018-01-24', '2018-02-15', '2018-03-15'];
var parties = [
{name:"Zelení", data:[0.015, 'nan', 0.1, 0.1], color:"#06b15d"},
{name:"Svobodní", data:[null, 0.015, 0.01, 0.01], color:"#009982"},
{name:"TOP 09", data:[0.045, 0.04, 0.035, 0.045], color:"#723769"},
{name:"STAN", data:[0.04, 0.03, 0.03, 0.045], color:"#5d8c00"},
{name:"KDU-ČSL", data:[0.065, 0.05, 0.035, 0.045], color:"#e6ac21"},
{name:"SPD", data:[0.065, 0.075, 0.065, 0.065], color:"#ea2329"},
{name:"KSČM", data:[0.075, 0.08, 0.1, 0.11], color:"#8c0000"},
{name:"ČSSD", data:[0.1, 0.125, 0.12, 0.11], color:"#F07D00"},
{name:"Piráti", data:[0.115, 0.125, 0.13, 0.125], color:"#000000"},
{name:"ODS", data:[0.115, 0.12, 0.105, 0.125], color:"#004494"},
{name:"ANO", data:[0.355, 0.305, 0.335, 0.305], color:"#261060"}
];
var currentEstimates = [
{name:"Zelení", data:[0.1], color:"#06b15d"},
{name:"Svobodní", data:[0.01], color:"#009982"},
{name:"TOP 09", data:[0.045], color:"#723769"},
{name:"STAN", data:[0.045], color:"#5d8c00"},
{name:"KDU-ČSL", data:[0.045], color:"#e6ac21"},
{name:"SPD", data:[0.065], color:"#ea2329"},
{name:"KSČM", data:[0.11], color:"#8c0000"},
{name:"ČSSD", data:[0.11], color:"#F07D00"},
{name:"Piráti", data:[0.125], color:"#000000"},
{name:"ODS", data:[0.125], color:"#004494"},
{name:"ANO", data:[0.305], color:"#261060"}
]
var elections = electionData.map( obj => {
var d = {
type: 'scatter',
mode: 'markers',
x: [electionDate],
y: [obj.value * 100],
name: "Volby: " + obj.name,
legendgroup: obj.name,
showlegend: false,
marker: {
size: 20,
color: "rgba(" + hex2rgba(obj.color, 1).join(',') + ")",
}
}
return d
})
var data = parties.map(obj => {
var d = {
mode: 'markers+lines',
type: 'scatter',
line: {
color: "rgba(" + hex2rgba(obj.color).join(',') + ")",
shape: "spline"
},
textposition: 'top right',
textfont : {
family:'Arial',
size: 30,
color: "rgba(" + hex2rgba(obj.color).join(',') + ")"
}
};
d['legendgroup'] = obj.name;
d['name'] = obj.name;
d['x'] = dates;
d['y'] = obj.data.map( v => v * 100);
d['text'] = ['a','b','c','d'];
return d;
});
var currents = currentEstimates.map(obj => {
var d = {
mode: 'text',
type: 'scatter',
textposition: 'middle right',
textfont : {
family:'Arial',
size: 16,
color: "rgba(" + hex2rgba(obj.color).join(',') + ")"
}
};
d['legendgroup'] = obj.name;
d['name'] = obj.name;
d['x'] = [dates[dates.length -1]];
d['y'] = [obj.data[0] * 100];
d['text'] = " " + Math.round(obj.data[0] * 100) + "%";
return d;
});
var upper = parties.map(obj => {
var d = {
mode: 'lines',
type: 'scatter',
line: {
color: "rgba(" + hex2rgba(obj.color).join(',') + ")",
shape: "spline",
width: 0.01
},
showlegend: false,
hoverinfo: 'skip',
fill: 'tonexty'
};
d['legendgroup'] = obj.name;
d['name'] = obj.name;
d['x'] = dates;
d['y'] = obj.data.map( v => v * 1.15 * 100);
d['fillcolor'] = "rgba(" + hex2rgba(obj.color, 0.15).join(',') + ")";
return d;
});
var lower = parties.map(obj => {
var d = {
mode: 'lines',
type: 'scatter',
line: {
color: "rgba(" + hex2rgba(obj.color).join(',') + ")",
shape: "spline",
width: 0.01
},
showlegend: false,
hoverinfo: 'skip'
};
d['legendgroup'] = obj.name;
d['name'] = obj.name;
d['x'] = dates;
d['y'] = obj.data.map( v => v * 0.85 * 100);
return d;
});
var limit = [{
x: [electionDate, data[0]['x'][data[0]['x'].length - 1]],
y: [5, 5],
name: '5% hranice',
mode: 'lines',
hoverinfo: 'skip',
fill: 'tozeroy',
line: {
color: "red",
dash: 'dot',
width: 3
}
}]
var bounds = [];
for (var i = 0; i < upper.length; i++) {
bounds.push(lower[i]);
bounds.push(upper[i]);
}
data = bounds.concat(data);
data = elections.concat(data);
data = limit.concat(data);
data = currents.concat(data);
var layout = {
xaxis: {
type: 'date',
title: 'Datum průzkumu'
},
yaxis: {
title: 'Volební model',
ticksuffix: '%',
showticksuffix: 'all'
},
title:'Volební modely CVVM',
showlegend: true,
legend: {
traceorder: 'reversed'
},
annotations: [
{
xref: 'paper',
yref: 'paper',
x: 0.0,
y: 1.05,
xanchor: 'left',
yanchor: 'top',
text: 'Cool chart',
showarrow: true
}
]
};
var config = {
displaylogo: false,
staticPlot: false,
locale: 'cs'
}
TESTER = document.getElementById('tester');
Plotly.plot('tester', data, layout, config);
</script>
</body>
</html>
calc2.py
import copy
import csv
import json
import numpy
import operator
code = "cvvm201803"
inputfile = code + ".csv"
outputfile = "stats_" + code + ".json"
n = 550
runs = 10000
def dhondt(parties, seats):
line = []
for k in parties:
for j in range(1, seats + 1):
line.append({
'party_code': k,
'value': parties[k] / j
})
line_sorted = sorted(line, key=lambda x: x['value'], reverse=True)
nof_seats = {}
for k in parties:
nof_seats[k] = 0
for j in range(0, seats):
nof_seats[line_sorted[j]['party_code']] += 1
return nof_seats
trial_seats = {}
current_poll = {}
with open(inputfile) as fin:
dr = csv.DictReader(fin)
for row in dr:
current_poll[row['party_code']] = row
gains_prev = {}
with open("psp2017_results_selected.csv") as fin:
dr = csv.DictReader(fin)
for row in dr:
gains_prev[row['party_code']] = row
votes_prev = {}
with open("psp2017_selected.csv") as fin:
dr = csv.DictReader(fin)
for row in dr:
try:
votes_prev[row['party_code']]
except Exception:
votes_prev[row['party_code']] = {}
votes_prev[row['party_code']][row['region_code']] = row
votes_totals_prev = {}
for k in votes_prev:
s = 0
for j in votes_prev[k]:
s += int(votes_prev[k][j]['votes'])
votes_totals_prev[k] = s
regions_seats = {}
with open("psp2017_seats.csv") as fin:
dr = csv.DictReader(fin)
for row in dr:
regions_seats[row['region_code']] = row
def calculate_seats(current):
calc_nof_votes = {}
for k in current:
party_code_prev = current[k]['party_code_2017']
if float(current[k]['gain']) >= float(current[k]['needs']):
calc_nof_votes[k] = float(current[k]['gain']) / float(gains_prev[party_code_prev]['gain']) * votes_totals_prev[party_code_prev]
else:
calc_nof_votes[k] = 0
calc_nof_votes_regions = {}
for k in calc_nof_votes:
party_code_prev = current[k]['party_code_2017']
for j in regions_seats:
try:
calc_nof_votes_regions[j]
except Exception:
calc_nof_votes_regions[j] = {}
calc_nof_votes_regions[j][k] = calc_nof_votes[k] / votes_totals_prev[party_code_prev] * int(votes_prev[party_code_prev][j]['votes'])
calc_seats = {}
for k in current:
calc_seats[k] = 0
for j in regions_seats:
calculated = dhondt(calc_nof_votes_regions[j], int(regions_seats[j]['seats']))
for k in current:
calc_seats[k] += calculated[k]
return calc_seats
for i in range(0, runs):
current = copy.deepcopy(current_poll)
for k in current_poll:
current[k]['gain'] = numpy.random.binomial(n, float(current[k]['gain'])) / n
calc_seats = calculate_seats(current)
for k in calc_seats:
try:
trial_seats[k]
except Exception:
trial_seats[k] = []
trial_seats[k].append(calc_seats[k])
seats = calculate_seats(current_poll)
stats = []
for k in trial_seats:
try:
difference = seats[k] - int(gains_prev[current_poll[k]['party_code_2017']]['seats'])
except Exception:
difference = seats[k]
row = {
'party_code': k,
'median': sorted(trial_seats[k])[round(runs * 0.5)],
'lo': sorted(trial_seats[k])[round(runs * 0.05)],
'hi': sorted(trial_seats[k])[round(runs * 0.95)],
'seats': seats[k],
'difference': difference,
'name': current_poll[k]['name'],
'color': current_poll[k]['color'],
'gain': current_poll[k]['gain']
}
print(row)
stats.append(row)
stats.sort(key=operator.itemgetter("gain"), reverse=True)
stats.sort(key=operator.itemgetter("hi"), reverse=True)
stats.sort(key=lambda x: x['seats'], reverse=True)
with open(outputfile, "w") as fout:
json.dump(stats[0:9], fout)
def majority_probability(seats, majority=101):
over = 0
for i in range(0, runs):
s = 0
for k in seats:
s += seats[k][i]
if s >= majority:
over += 1
return over / runs
coalitions = []
potentials = []
for k in trial_seats:
potentials.append({
'trial_seats': {k: trial_seats[k]},
'seats': seats[k],
'party_code': k
})
for k in trial_seats:
for m in trial_seats:
if k < m:
potentials.append({
'trial_seats': {k: trial_seats[k], m: trial_seats[m]},
'seats': seats[k] + seats[m],
'party_code': '+'.join([k, m])
})
with open("coalitions.csv") as fin:
dr = csv.DictReader(fin)
for row in dr:
keys = row['party_code'].split('+')
ts = {}
ss = 0
for key in keys:
ts[key] = trial_seats[key]
ss += seats[key]
potentials.append({
'trial_seats': ts,
'seats': ss,
'party_code': row['party_code']
})
for p in potentials:
mp = majority_probability(p['trial_seats'])
if mp > 0:
item = {
'party_code': p['party_code'],
'seats': p['seats'],
'majority_probability': mp
}
coalitions.append(item)
coalitions.sort(key=lambda x: x['majority_probability'], reverse=True)
coalitions.html
<!doctype html>
<html lang="cs">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<title>Koalice</title>
<style>
.party {
float: left;
width: 10px;
height: 20px;
border-radius: 2px;
display: block;
line-height: 20px;
text-align: center;
color: #333;
font-weight: bold;
margin-right: 7px;
}
.party-name {
width: 60px;
}
.plus {
float: left:
}
.bg-ano {
background-color: #261060
}
.bg-cssd {
background-color: #F07D00
}
.bg-kscm {
background-color: #8c0000
}
.bg-spd {
background-color: #ea2329
}
.bg-ods {
background-color: #004494
}
.bg-pirati {
background-color: #000000
}
.bg-kdu-csl {
background-color: #e6ac21
}
.bg-top-09 {
background-color: #723769
}
.bg-stan {
background-color: #5d8c00
}
.row {
padding-top: 2em;
}
.bold {
font-weight: bold;
color: #444;
}
</style>
</head>
<body>
<div class="container">
<h2>Kdo by měl dostatek mandátů na vládu? <small><small><span class="badge badge-pill badge-secondary">1.4.2018</span> <span class="badge badge-primary">Experimentální</span></small></small></h2>
Jakou by měly <em>některé zvažované koalice</em> šanci získat 101 nebo více mandátů, čímž by získaly možnost podpory většinové vlády.
</div>
<div class="container bold">
<div class="row">
<div class="col">
<span class="party bg-ano"></span>
<span class="party">+</span>
<span class="party bg-kscm"></span>
<span class="party">+</span>
<span class="party bg-cssd"></span>
<span class="party">~</span>
131 mandátů<br />
šance na majoritu > 99 %
</div>
<div class="col">
<span class="party bg-ano"></span>
<span class="party">+</span>
<span class="party bg-kscm"></span>
<span class="party">+</span>
<span class="party bg-spd"></span>
<span class="party">~</span>
120<br />
šance ~ 98 %
</div>
<div class="col">
<span class="party bg-ano"></span>
<span class="party">+</span>
<span class="party bg-ods"></span>
<span class="party">~</span>
113<br />
šance ~ 86 %
</div>
<div class="col">
<span class="party bg-ano"></span>
<span class="party">+</span>
<span class="party bg-pirati"></span>
<span class="party">~</span>
110<br />
šance ~ 85 %
</div>
</div>
<div class="row">
<div class="col">
<span class="party bg-ano"></span>
<span class="party">+</span>
<span class="party bg-kscm"></span>
<span class="party">~</span>
108<br />
šance ~ 72 %
</div>
<div class="col">
<span class="party bg-ano"></span>
<span class="party">+</span>
<span class="party bg-cssd"></span>
<span class="party">~</span>
106<br />
šance ~ 67 %
</div>
<div class="col">
<span class="party bg-ods"></span>
<span class="party">+</span>
<span class="party bg-pirati"></span>
<span class="party">+</span>
<span class="party bg-kdu-csl"></span>
<span class="party">+</span>
<span class="party bg-top-09"></span>
<span class="party">+</span>
<span class="party bg-stan"></span>
<span class="party">+</span>
<span class="party bg-cssd"></span>
<span class="party">~</span>
80<br />
šance < 2 %
</div>
<div class="col">
<span class="party bg-ano"></span>
<span class="party">~</span>
83<br />
šance < 1 %
</div>
</div>
<div class="row legenda">
<div class="col">
Legenda:<br />
<span class="party bg-ano"></span>
<span class="party party-name">ANO</span>
<span class="party bg-ods"></span>
<span class="party party-name">ODS</span>
<span class="party bg-pirati"></span>
<span class="party party-name">Piráti</span>
<span class="party bg-kscm"></span>
<span class="party party-name">KSČM</span>
<span class="party bg-cssd"></span>
<span class="party party-name">ČSSD</span>
<span class="party bg-spd"></span>
<span class="party party-name">SPD</span>
<span class="party bg-kdu-csl"></span>
<span class="party party-name">KDU-ČSL</span>
<span class="party bg-top-09"></span>
<span class="party party-name">TOP 09</span>
<span class="party bg-stan"></span>
<span class="party party-name">STAN</span>
</div>
</div>
</div>
<div class="container">
<div class="card mt-4">
<div class="card-body bg-light small">
<p>Výpočet zisku mandátů: Jako základ je brán <strong>volební model CVVM z 15.3.2018</strong>. Přepočet na mandáty je po krajích s tím, že je zjednodušeně uvažováno stejné rozdělení voličů každé strany mezi kraji jako v volbách 2017. Také celkové počty mandátů pro každý kraj jsou zjednodušeně dle roku 2017.</p>
<p>Odhad počtu mandátů: Provedl jsem 10 000 simulací, kdy hodnoty volebního modelu byly náhodně upraveny se započítáním (zjednodušeně pouze) statistické chyby modelu. Jako další zjednodušení byly hodnoty pro jednotlivé strany uvažovány nezávislé.</p>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
cvvm201803.csv
party_code,gain,needs,party_code_2017,name,color
ano,0.305,0.05,ano,ANO,#261060
cssd,0.11,0.05,cssd,ČSSD,#F07D00
kscm,0.11,0.05,kscm,KSČM,#8c0000
ods,0.125,0.05,ods,ODS,#004494
top-09,0.045,0.05,top-09,TOP 09,#723769
kdu-csl,0.045,0.05,kdu-csl,KDU-ČSL,#e6ac21
spd,0.065,0.05,spd,SPD,#ea2329
pirati,0.125,0.05,pirati,Piráti,#000000
zeleni,0.01,0.05,zeleni,Zelení,#06b15d
svobodni,0.01,0.05,svobodni,Svobodní,#009982
stan,0.045,0.05,stan,STAN,#5d8c00
data.csv
party,value,date,weight
Zelení,0.0146,2017-10-21,5
Svobodní,0.0156,2017-10-21,5
STAN,0.0518,2017-10-21,5
TOP 09,0.0531,2017-10-21,5
KDU-ČSL,0.058,2017-10-21,5
ČSSD,0.0727,2017-10-21,5
KSČM,0.0776,2017-10-21,5
SPD,0.1064,2017-10-21,5
Piráti,0.1079,2017-10-21,5
ODS,0.1132,2017-10-21,5
ANO,0.2964,2017-10-21,5
Svobodní,0,2017-12-17,2
Zelení,0,2017-12-17,2
ANO,0.355,2017-12-17,2
ČSSD,0.1,2017-12-17,2
KSČM,0.075,2017-12-17,2
ODS,0.115,2017-12-17,2
TOP 09,0.045,2017-12-17,2
KDU-ČSL,0.065,2017-12-17,2
Piráti,0.115,2017-12-17,2
SPD,0.065,2017-12-17,2
STAN,0.04,2017-12-17,2
ANO,0.305,2018-01-24,2
ČSSD,0.125,2018-01-24,2
KSČM,0.08,2018-01-24,2
ODS,0.12,2018-01-24,2
TOP 09,0.04,2018-01-24,2
KDU-ČSL,0.05,2018-01-24,2
Piráti,0.125,2018-01-24,2
SPD,0.075,2018-01-24,2
STAN,0.03,2018-01-24,2
Svobodní,0.015,2018-01-24,2
Zelení,0.015,2018-01-24,2
ANO,0.335,2018-02-15,2
ČSSD,0.12,2018-02-15,2
KSČM,0.1,2018-02-15,2
ODS,0.105,2018-02-15,2
TOP 09,0.035,2018-02-15,2
KDU-ČSL,0.035,2018-02-15,2
Piráti,0.13,2018-02-15,2
SPD,0.065,2018-02-15,2
STAN,0.03,2018-02-15,2
Svobodní,0.01,2018-02-15,2
Zelení,0.01,2018-02-15,2
ANO,0.305,2018-03-15,2
ČSSD,0.11,2018-03-15,2
KSČM,0.11,2018-03-15,2
ODS,0.125,2018-03-15,2
TOP 09,0.045,2018-03-15,2
KDU-ČSL,0.045,2018-03-15,2
Piráti,0.125,2018-03-15,2
SPD,0.065,2018-03-15,2
STAN,0.045,2018-03-15,2
Svobodní,0.01,2018-03-15,2
Zelení,0.01,2018-03-15,2
plotly-locale-cs.js
Plotly.register({moduleType:"locale",name:"cs",dictionary:{},format:{days:["ned\u011ble","pond\u011bl\xed","\xfater\xfd","st\u0159eda","\u010dtvrtek","p\xe1tek","sobota"],shortDays:["ne","po","\xfat","st","\u010dt","p\xe1","so"],months:["leden","\xfanor","b\u0159ezen","duben","kv\u011bten","\u010derven","\u010dervenec","srpen","z\xe1\u0159\xed","\u0159\xedjen","listopad","prosinec"],shortMonths:["led","\xfano","b\u0159e","dub","kv\u011b","\u010der","\u010dvc","srp","z\xe1\u0159","\u0159\xedj","lis","pro"],date:"%d.%m.%Y"}});
plotly-locale-sk.js
Plotly.register({moduleType:"locale",name:"sk",dictionary:{},format:{days:["Nedel'a","Pondelok","Utorok","Streda","\u0160tvrtok","Piatok","Sobota"],shortDays:["Ned","Pon","Uto","Str","\u0160tv","Pia","Sob"],months:["Janu\xe1r","Febru\xe1r","Marec","Apr\xedl","M\xe1j","J\xfan","J\xfal","August","September","Okt\xf3ber","November","December"],shortMonths:["Jan","Feb","Mar","Apr","M\xe1j","J\xfan","J\xfal","Aug","Sep","Okt","Nov","Dec"],date:"%d.%m.%Y"}});
prepare_intervals.py
import csv
import datetime
path = "/home/michal/project/pollster.eu/dev/plotly/"
data_obj = {}
with open(path + "data.csv") as fin:
dr = csv.DictReader(fin)
for row in dr:
try:
data_obj[row['party']]
except Exception:
data_obj[row['party']] = []
data_obj[row['party']].append(row)
print(data_obj)
def fromisoformat(s):
return datetime.datetime.strptime(s,'%Y-%m-%d')
results = {}
for k in data_obj:
results[k] = []
items = data_obj[k]
for i, it in enumerate(items):
value = 0
w = 0
for it2 in items[0:(i + 1)]:
delta = fromisoformat(it['date']) - fromisoformat(it2['date'])
w += float(it2['weight']) * (1 / 2) ** (delta.days / 30)
value += (1 / 2) ** (delta.days / 30) * float(it2['value']) * float(it2['weight'])
if i > 0:
results[k].append({
'date': it['date'],
'value': value / w
})
for k in results:
items = results[k]
ds = []
for it in items:
ds.append(it['value'])
print('name: "', k, '", data: ', ds, ', color: ')
psp2017_results_selected.csv
party_code,gain,seats
ods,0.1132,25
cssd,0.0727,15
stan,0.0518,6
kscm,0.0776,15
pirati,0.1079,22
top-09,0.0531,7
ano,0.2964,78
kdu-csl,0.058,10
spd,0.1064,22
svobodni,0.0156,0
zeleni,0.0146,0
psp2017_seats.csv
region_code,seats
pr,24
st,26
jc,13
pl,11
ka,5
us,13
li,8
kr,11
pa,10
vy,10
jm,23
ol,12
zl,12
mo,22
psp2017_selected.csv
party_code,region_code,votes
ods,pr,99182
ods,st,85415
ods,jc,38232
ods,pl,32833
ods,ka,10796
ods,us,32197
ods,li,21468
ods,kr,32242
ods,pa,28313
ods,vy,25989
ods,jm,69319
ods,ol,27266
ods,zl,28752
ods,mo,40944
cssd,pr,34079
cssd,st,43853
cssd,jc,23035
cssd,pl,21643
cssd,ka,8530
cssd,us,22464
cssd,li,11811
cssd,kr,18128
cssd,pa,19294
cssd,vy,24631
cssd,jm,49248
cssd,ol,22760
cssd,zl,20454
cssd,mo,48417
stan,pr,30920
stan,st,53368
stan,jc,14435
stan,pl,13180
stan,ka,6453
stan,us,12299
stan,li,26780
stan,kr,14184
stan,pa,12855
stan,vy,11251
stan,jm,21222
stan,ol,13580
stan,zl,17168
stan,mo,14462
kscm,pr,28158
kscm,st,47695
kscm,jc,29414
kscm,pl,23502
kscm,ka,9960
kscm,us,33628
kscm,li,13981
kscm,kr,19792
kscm,pa,20002
kscm,vy,24829
kscm,jm,46966
kscm,ol,26853
kscm,zl,20669
kscm,mo,47651
zeleni,pr,14686
zeleni,st,9415
zeleni,jc,4326
zeleni,pl,3321
zeleni,ka,1549
zeleni,us,5013
zeleni,li,2907
zeleni,kr,3650
zeleni,pa,3261
zeleni,vy,3204
zeleni,jm,9147
zeleni,ol,3588
zeleni,zl,3685
zeleni,mo,6583
svobodni,pr,12857
svobodni,st,10679
svobodni,jc,5303
svobodni,pl,4138
svobodni,ka,1544
svobodni,us,4595
svobodni,li,3152
svobodni,kr,4310
svobodni,pa,3998
svobodni,vy,3565
svobodni,jm,10421
svobodni,ol,3963
svobodni,zl,4812
svobodni,mo,5892
pirati,pr,107590
pirati,st,79815
pirati,jc,33143
pirati,pl,27201
pirati,ka,12264
pirati,us,28004
pirati,li,23859
pirati,kr,29932
pirati,pa,27146
pirati,vy,26086
pirati,jm,53207
pirati,ol,25955
pirati,zl,24859
pirati,mo,47332
top-09,pr,77325
top-09,st,41843
top-09,jc,16713
top-09,pl,13095
top-09,ka,4495
top-09,us,12336
top-09,li,8825
top-09,kr,14308
top-09,pa,10864
top-09,vy,10163
top-09,jm,26356
top-09,ol,9903
top-09,zl,8443
top-09,mo,14142
ano,pr,124445
ano,st,189371
ano,jc,91012
ano,pl,84114
ano,ka,43268
ano,us,127574
ano,li,62302
ano,kr,88551
ano,pa,79551
ano,vy,75247
ano,jm,159909
ano,ol,95950
ano,zl,84750
ano,mo,194069
kdu-csl,pr,29143
kdu-csl,st,19925
kdu-csl,jc,16983
kdu-csl,pl,9499
kdu-csl,ka,2885
kdu-csl,us,6127
kdu-csl,li,4297
kdu-csl,kr,16294
kdu-csl,pa,17599
kdu-csl,vy,24295
kdu-csl,jm,52346
kdu-csl,ol,25257
kdu-csl,zl,33631
kdu-csl,mo,35362
spd,pr,35547
spd,st,59497
spd,jc,31062
spd,pl,28686
spd,ka,15233
spd,us,42777
spd,li,22878
spd,kr,28038
spd,pa,26202
spd,vy,25237
spd,jm,67973
spd,ol,41397
spd,zl,38020
spd,mo,76027
stats_cvvm201803.json
[{"difference": 5, "seats": 83, "hi": 88, "party_code": "ano", "color": "#261060", "gain": "0.305", "lo": 71, "median": 80, "name": "ANO"}, {"difference": 5, "seats": 30, "hi": 35, "party_code": "ods", "color": "#004494", "gain": "0.125", "lo": 21, "median": 27, "name": "ODS"}, {"difference": 5, "seats": 27, "hi": 36, "party_code": "pirati", "color": "#000000", "gain": "0.125", "lo": 21, "median": 27, "name": "Pir\u00e1ti"}, {"difference": 10, "seats": 25, "hi": 31, "party_code": "kscm", "color": "#8c0000", "gain": "0.11", "lo": 17, "median": 25, "name": "KS\u010cM"}, {"difference": 8, "seats": 23, "hi": 32, "party_code": "cssd", "color": "#F07D00", "gain": "0.11", "lo": 18, "median": 23, "name": "\u010cSSD"}, {"difference": -10, "seats": 12, "hi": 16, "party_code": "spd", "color": "#ea2329", "gain": "0.065", "lo": 0, "median": 12, "name": "SPD"}, {"difference": -10, "seats": 0, "hi": 10, "party_code": "kdu-csl", "color": "#e6ac21", "gain": "0.045", "lo": 0, "median": 0, "name": "KDU-\u010cSL"}, {"difference": -7, "seats": 0, "hi": 8, "party_code": "top-09", "color": "#723769", "gain": "0.045", "lo": 0, "median": 0, "name": "TOP 09"}, {"difference": -6, "seats": 0, "hi": 7, "party_code": "stan", "color": "#5d8c00", "gain": "0.045", "lo": 0, "median": 0, "name": "STAN"}]
test3.html
<html>
<head>
<meta charset="utf-8" />
<script src="./plotly-1.35.2.min.js"></script>
<script src="./plotly-locale-cs.js"></script>
</head>
<body>
<div id="tester" style="width:920px;height:800px;"></div>
<strong>Tip 1: </strong>kliknutím na legendu lze filtrovat strany<br />
<strong>Tip 2: </strong>najetím lze zobrazit toolbox - lze např. zoomovat<br />
Pozn: Linie vypočteny pomocí klouzavých průměrů (každý měsíc -> 1/2 váha)<br />
Intervaly jsou 95% statistická chyba zvětšená 1.5x jako odhad dalších chyb měření
<script>
var hex2rgba = (str, a) => str.replace('#','').split('').reduce((r,c,i,{length: l},j,n)=>(j=parseInt(i*3/l),n=parseInt(c,16),r[j]=(l==3?n:r[j])*16+n,r),[0,0,0,a||1]);
var electionData = [
{name:"Zelení", value: 0.0146, color:"#06b15d"},
{name:"Svobodní", value: 0.0156, color:"#009982"},
{name:"STAN", value: 0.0518, color:"#5d8c00"},
{name:"TOP 09", value: 0.0531, color:"#723769"},
{name:"KDU-ČSL", value: 0.0580, color:"#e6ac21"},
{name:"ČSSD", value: 0.0727, color:"#F07D00"},
{name:"KSČM", value: 0.0776, color:"#8c0000"},
{name:"SPD", value: 0.1064, color:"#ea2329"},
{name:"Piráti", value: 0.1079, color:"#000000"},
{name:"ODS", value: 0.1132, color:"#004494"},
{name:"ANO", value: 0.2964, color:"#261060"}
];
var electionDate = '2017-10-21';
var dates = ['2017-12-17', '2018-01-24', '2018-02-15', '2018-03-15'];
var parties = [
{name:"Zelení", data:['', 0.015, 0.01, 0.01], color:"#06b15d"},
{name:"Svobodní", data:['', 0.015, 0.01, 0.01], color:"#009982"},
{name:"TOP 09", data:[0.045, 0.04, 0.035, 0.045], color:"#723769"},
{name:"STAN", data:[0.04, 0.03, 0.03, 0.045], color:"#5d8c00"},
{name:"KDU-ČSL", data:[0.065, 0.05, 0.035, 0.045], color:"#e6ac21"},
{name:"SPD", data:[0.065, 0.075, 0.065, 0.065], color:"#ea2329"},
{name:"KSČM", data:[0.075, 0.08, 0.1, 0.11], color:"#8c0000"},
{name:"ČSSD", data:[0.1, 0.125, 0.12, 0.11], color:"#F07D00"},
{name:"Piráti", data:[0.115, 0.125, 0.13, 0.125], color:"#000000"},
{name:"ODS", data:[0.115, 0.12, 0.105, 0.125], color:"#004494"},
{name:"ANO", data:[0.355, 0.305, 0.335, 0.305], color:"#261060"}
];
var moving_averages = [
{name:"Zelení", data: [0.005856743759321369, 0.011254100547855188, 0.01063294415412413, 0.01032527621613037], color: "#06b15d"},
{name:"Svobodní", data: [0.006257890592151599, 0.011418446341276468, 0.010715889424643939, 0.010367902605148731], color: "#009982"},
{name:"TOP 09", data: [0.04824928934592487, 0.04337965027207751, 0.039229206870523246, 0.04203433274326568], color: "#723769"},
{name:"STAN", data: [0.044733532627396724, 0.03603617905310141, 0.033046457679522696, 0.03885695722122656], color: "#5d8c00"},
{name:"KDU-ČSL", data: [0.06219197217018839, 0.05499492748214653, 0.0450914336442997, 0.04504698864765719], color: "#e6ac21"},
{name:"SPD", data: [0.08160747887917155, 0.07770701715691061, 0.07141322758336781, 0.06829582063110688], color: "#ea2329"},
{name:"KSČM", data: [0.0760429817653586, 0.07837884971753015, 0.08908781221718377, 0.09925302134685932], color: "#8c0000"},
{name:"ČSSD", data: [0.0890486914637347, 0.1102711131127733, 0.11508983383195517, 0.11261571558691737], color: "#F07D00"},
{name:"Piráti", data: [0.11215185748690537, 0.1197362461759786, 0.1248198866563021, 0.12490743798401344], color: "#000000"},
{name:"ODS", data: [0.1142779357009056, 0.11765572822647653, 0.11138734207622482, 0.11800432142066311], color: "#004494"},
{name:"ANO", data: [0.33149279559614847, 0.31585382995916467, 0.32533693397077396, 0.31545135007030844], color: "#261060"}
]
var elections = electionData.map( obj => {
var d = {
type: 'scatter',
mode: 'markers',
x: [electionDate],
y: [obj.value * 100],
name: "Volby: " + obj.name,
legendgroup: obj.name,
showlegend: false,
marker: {
size: 20,
color: "rgba(" + hex2rgba(obj.color, 1).join(',') + ")",
}
}
return d
})
var data = parties.map(obj => {
var d = {
mode: 'markers',
type: 'scatter',
line: {
color: "rgba(" + hex2rgba(obj.color).join(',') + ")",
shape: "spline"
},
showlegend: false
};
d['legendgroup'] = obj.name;
d['name'] = obj.name;
d['x'] = dates;
d['y'] = obj.data.map(v => v * 100);
return d;
});
var mas = moving_averages.map(obj => {
var d = {
mode: 'lines',
type: 'scatter',
line: {
color: "rgba(" + hex2rgba(obj.color).join(',') + ")",
shape: "spline"
},
hoverinfo: 'skip'
};
d['legendgroup'] = obj.name;
d['name'] = obj.name;
d['x'] = dates;
d['y'] = obj.data.map(v => v * 100);
return d;
});
var upper = parties.map(function (obj, i) {
var d = {
mode: 'lines',
type: 'scatter',
line: {
color: "rgba(" + hex2rgba(obj.color).join(',') + ")",
shape: "spline",
width: 0.01
},
showlegend: false,
hoverinfo: 'skip',
fill: 'tonexty'
};
d['legendgroup'] = obj.name;
d['name'] = obj.name;
d['x'] = dates;
d['y'] = moving_averages[i].data.map(v => ((v * 550 + Math.sqrt(v * 550 * (1 - v)) * 1.95 * 1.5) / 550 * 100));
d['fillcolor'] = "rgba(" + hex2rgba(obj.color, 0.10).join(',') + ")";
return d;
});
var lower = parties.map(function (obj, i) {
var d = {
mode: 'lines',
type: 'scatter',
line: {
color: "rgba(" + hex2rgba(obj.color).join(',') + ")",
shape: "spline",
width: 0.01
},
showlegend: false,
hoverinfo: 'skip'
};
d['legendgroup'] = obj.name;
d['name'] = obj.name;
d['x'] = dates;
d['y'] = moving_averages[i].data.map(v => (Math.max((v * 550 - Math.sqrt(v * 550 * (1 - v)) * 1.95 * 1.5) / 550 * 100, 0)));
return d;
});
var limit = [{
x: [electionDate, data[0]['x'][data[0]['x'].length - 1]],
y: [5, 5],
name: '5% hranice',
mode: 'lines',
hoverinfo: 'skip',
fill: 'tozeroy',
line: {
color: "red",
dash: 'dot',
width: 3
}
}]
var bounds = [];
for (var i = 0; i < upper.length; i++) {
bounds.push(lower[i]);
bounds.push(upper[i]);
}
data = mas.concat(data)
data = bounds.concat(data);
data = elections.concat(data);
data = limit.concat(data);
var layout = {
xaxis: {
type: 'date',
title: 'Datum průzkumu'
},
yaxis: {
title: 'Volební model',
ticksuffix: '%',
showticksuffix: 'all'
},
title:'Volební modely CVVM',
showlegend: true,
legend: {
traceorder: 'reversed'
}
};
var config = {
displaylogo: false,
staticPlot: false,
locale: 'cs'
}
TESTER = document.getElementById('tester');
Plotly.plot('tester', data, layout, config);
</script>
</body>
</html>