Europe Happiness

Anticipation of happiness, Oil painting on canvas, by Leonid Afremov:

In [2]:
from IPython.display import Image
Image(url='https://afremov.com/image.php?type=P&id=18696')
Out[2]:

In this notebook we visualize Europe country happiness scores. Data are retrieved from World Happiness Report 2016.

In [3]:
import numpy as np
import pandas as pd
import matplotlib.cm as cm
In [4]:
df=pd.read_excel('Europe-Happiness.xlsx')
df
Out[4]:
Country World-Rank Score
0 Denmark 1 7.526
1 Switzerland 2 7.509
2 Iceland 3 7.501
3 Norway 4 7.498
4 Finland 5 7.413
5 Netherlands 7 7.339
6 Sweden 10 7.291
7 Israel 11 7.267
8 Austria 12 7.119
9 Germany 16 6.994
10 Belgium 18 6.929
11 Ireland 19 6.907
12 Luxembourg 20 6.871
13 United Kingdom 23 6.725
14 Czech Republic 27 6.596
15 Malta 30 6.488
16 France 32 6.478
17 Spain 37 6.361
18 Slovakia 45 6.078
19 Uzbekistan 49 5.987
20 Italy 50 5.977
21 Kazakhstan 54 5.919
22 Moldova 55 5.897
23 Russia 56 5.856
24 Poland 57 5.835
25 Lithuania 60 5.813
26 Belarus 61 5.802
27 North Cyprus 62 5.771
28 Slovenia 63 5.768
29 Latvia 68 5.560
30 Cyprus 69 5.546
31 Romania 71 5.528
32 Estonia 72 5.517
33 Croatia 74 5.488
34 Kosovo 77 5.401
35 Turkey 78 5.389
36 Azerbaijan 81 5.291
37 Serbia 86 5.177
38 Bosnia and Herzegovina 87 5.163
39 Montenegro 88 5.161
40 Hungary 91 5.145
41 Portugal 94 5.123
42 Macedonia 95 5.121
43 Greece 99 5.033
44 Albania 109 4.655
45 Armenia 121 4.360
46 Ukraine 123 4.324
47 Georgia 126 4.252
48 Bulgaria 129 4.217
In [5]:
N=len(df)
In [6]:
score=df['Score'].values
country=list(df.Country)
country[13]='U Kingdom'
country[14]='Czech Rep'
country[38]='Bosn Herzeg'
world_rk=list(df['World-Rank'])
In [7]:
import plotly.plotly as py
from plotly.graph_objs import *

Function that maps a normalized happiness score to a color in the chosen colormap:

In [8]:
def map_z2color(val, colormap, vmin, vmax):
    #map the normalized value val to a corresponding color in the mpl colormap
    
    if vmin>=vmax:
        raise ValueError('incorrect relation between vmin and vmax')
    t=(val-vmin)/float((vmax-vmin))#normalize val
    C=map(np.uint8, np.array(colormap(t)[:3])*255)
    #convert to a Plotly color code:
    return 'rgb'+str((C[0], C[1], C[2]))
       
    
In [9]:
def set_layout(title, plot_size):# set plot layout
    axis=dict(showline=False, 
              zeroline=False,
              showgrid=False,
              showticklabels=False,
              title='' 
             )

    return Layout(title=title,
                  font=Font(size=12), 
                  xaxis=XAxis(axis, range=[-3.5, 4]),
                  yaxis=YAxis(axis, range=[-4.5, 3.5]),
                  showlegend=False,
                  width=plot_size,
                  height=plot_size,
                  hovermode='closest',
                  annotations=[]        
                 )  
In [10]:
def set_annotation(x, y, anno_text,  angle, fontsize=11): # annotations
    return Annotation(x= x,  
                      y= y,       
                      text= anno_text,      
                      textangle=angle, # angle in degrees 
                      font= Font(size=fontsize),  
                      showarrow=False     
                     ) 

We visualize Europe country happiness through a circular barchart. The height of each bar is proportional to the corresponding happiness score:

In [11]:
bar_height=[score[k]/4.75 for k in range(N)]

The bars are inserted along the unit circle, starting with the angular position $\pi/2$, in the anti-clockwise direction:

In [12]:
theta=[np.pi/2+(2*k+1)*np.pi/72  for k in range(N)]# angular position of base bar centers
In [13]:
xi=[np.cos(theta[k]) for k in range(N)]# starting bar position
yi=[np.sin(theta[k]) for k in range(N)]


xf=[(bar_height[k]+1)*np.cos(theta[k]) for k in range(N)]#end bar position
yf=[(bar_height[k]+1)*np.sin(theta[k]) for k in range(N)]

xm=[(xi[k]+xf[k])*0.5   for k in range(N)]#mid bar position for inserting hovering text
ym=[(yi[k]+yf[k])*0.5   for k in range(N)]

xpos_t=[(bar_height[k]+1.32)*np.cos(theta[k]) for k in range(N)]#text position
ypos_t=[(bar_height[k]+1.32)*np.sin(theta[k]) for k in range(N)]

The decreased level of happiness is illustrated through the Viridis colormap:

In [14]:
import matplotlib.cm as cm
cmap=cm.viridis
In [15]:
vmin=score[-1]
vmax=score[0]
bar_colors=[map_z2color(score[k], cmap, score[-1], score[0]) for k in range(N)]

Define the hover text:

In [16]:
text=[country[k]+'<br>Score: '+'{:0.3f}'.format(score[k])+'<br>World rank: ' 
      +'{:d}'.format(world_rk[k])  for  k in range(len(score))]

Set position of the hover text inside bars:

In [17]:
trace=Scatter(x=xm,
              y=ym,
              name='',
              mode='markers' ,
              marker=dict(size=0.05, color=bar_colors[15]),
              text=text,
              hoverinfo='text')
tracet=Scatter(x=xf,
               y=yf,
               name='',
               mode='markers' ,
               marker=dict(size=0.05, color=bar_colors[15]), 
               text=text,
               hoverinfo='text')
In [18]:
traceB=[Scatter(x=[xi[k], xf[k], None], # Circular bars are drawn as lines of width 9
                y=[yi[k], yf[k], None], 
                mode='lines', 
                line=dict(color=bar_colors[k], width=9.6),
                hoverinfo='none')  
        for k in range(N)]
In [19]:
title="Europe Happiness Score and Global Ranking"+\
"<br>Data: World Happiness Report, 2016"+\
"<a href='http://worldhappiness.report/wp-content/uploads/sites/2/2016/03/HR-V1_web.pdf'> [1]</a>"
layout=set_layout('', 1000)
In [20]:
annotext_angle=[(-(180*np.arctan(yi[k]/xi[k])/np.pi)) for k in range(N)]# angles in degrees, computed following 
                                                                        #Plotly reversed trigonometric rule

Insert annotations:

In [21]:
for k in range(N):
    layout['annotations']+=[set_annotation(xpos_t[k], ypos_t[k], country[k],  annotext_angle[k],  fontsize=10)]
layout['annotations']+=[set_annotation(0.5, 0.1, title, 0 ) ]    
In [22]:
fig=Figure(data=Data(traceB+[trace, tracet]), layout=layout)
py.sign_in('empet', 'api_key')
py.iplot(fig, filename='Europe-Happiness')
Out[22]:
In [23]:
from IPython.core.display import HTML
def  css_styling():
    styles = open("./custom.css", "r").read()
    return HTML(styles)
css_styling()
Out[23]: