In this notebook we visualize Europe countries happiness scores. Data are retrieved from World Happiness Report 2016.
import numpy as np
import pandas as pd
import matplotlib.cm as cm
df = pd.read_excel('Data/Europe-Happiness.xlsx')
df.head()
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 |
N = len(df)
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'])
import plotly.plotly as py
import plotly.graph_objs as go
Function that maps a normalized happiness score to a color in a given matplotlib colormap:
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) / (vmax-vmin) #normalize val
C = (np.array(colormap(t)[:3])*255).astype(np.uint8)
#convert to a Plotly color code:
return f'rgb{tuple(C)}'
def set_layout(title, plot_size):# set plot layout
return go.Layout(title=title,
font=dict(size=12),
xaxis=dict(visible=False, range=[-3.5, 4]),
yaxis=dict(visible=False, range=[-4.5, 3.5]),
showlegend=False,
width=plot_size,
height=plot_size,
hovermode='closest')
def set_annotation(x, y, anno_text, angle, fontsize=11): # annotations
return dict(x= x,
y= y,
text= anno_text,
textangle=angle, # angle in degrees
font=dict(size=fontsize),
showarrow=False
)
We visualize countries happiness through a circular barchart. The height of each bar is proportional to the corresponding happiness score:
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:
theta = [np.pi/2+(2*k+1)*np.pi/72 for k in range(N)] # angular position of base bar centers
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:
import matplotlib.cm as cm
cmap = cm.viridis
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:
text = [f'{country[k]}<br>Score: {round(score[k],3)}<br>World rank: {world_rk[k]}' for k in range(len(score))]
Set position of the hover text inside bars:
trace = go.Scatter(x=xm,
y=ym,
name='',
mode='markers' ,
marker=dict(size=0.05, color=bar_colors[15]),
text=text,
hoverinfo='text')
tracet = go.Scatter(x=xf,
y=yf,
name='',
mode='markers' ,
marker=dict(size=0.05, color=bar_colors[15]),
text=text,
hoverinfo='text')
traceB = [go.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)]
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('', 900)
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
Define and insert annotations in plot layout:
annot = []
for k in range(N):
annot += [set_annotation(xpos_t[k], ypos_t[k], country[k], annotext_angle[k], fontsize=10)]
annot += [set_annotation(0.5, 0.1, title, 0 ) ]
fig = go.FigureWidget(data=traceB+[trace, tracet], layout=layout)
fig.layout.update(annotations=annot,
plot_bgcolor='rgb(245,245,245)');
fig
FigureWidget({ 'data': [{'hoverinfo': 'none', 'line': {'color': 'rgb(253, 231, 36)', 'width'…