How to plot a Arrow and Range plot in Python?

Viewed 286

Arrow plots are a relatively new chart type. They show how data points (e.g. life expectancy, election results) of different categories (e.g. countries, parties) have changed between two dates (e.g. decades, years, days). Arrow plots show exactly two dates. If you want to show multiple time points for your data points, consider a line chart. If your emphasis is on the gap between the dots rather than the time that has passed between them, then a range plot is the better choice. If you don't have time points and just want to show one or multiple dots on a line, consider a dot plot.

enter image description here

Source : economist- Americans are getting more nervous about what they say in public

enter image description here

Source: bundestag.de Get the data

I'm just curious to know if there is any python package that can be used to plot a similar kind of Arrow plots. My knowledge of visualization was minimum. I'm not asking for the exact replicate of the above Plot, a similar plot would be highly appreciated.

I'm open to new ideas and approaches and wanted to put some feelers out before diving into getting started

Can it be possible to plot the above plot with Python if YES, Which package would be used to plot the above plot? Can anybody shed some light on plotting the above plot with Python? I would be happy to receive any leads on it from you.

1 Answers

For this type of graph, I think the most time-consuming type is MPL, but I wrote the code in a way to mimic the second example of the expected output. Basically, it is created with arrows and annotations.

import pandas as pd
import numpy as np
import io

data = '''
Party 2009 2013
CDU/CSU 33.8 41.5
SPD 23.0 25.7
LINKE 11.9 8.6
GRÜNE 10.7 8.4
FDP 14.6 4.8
'''

df = pd.read_csv(io.StringIO(data), delim_whitespace=True)

import matplotlib.pyplot as plt
from matplotlib import colors as mcolors
colors = mcolors.TABLEAU_COLORS

fig, ax = plt.subplots(figsize=(10,4))
plt.rcParams.update({'axes.spines.top': False, 'axes.spines.right': False})

for (idx,row), c in zip(df.iterrows(),colors):
    cols = colors.keys()
    ax.arrow(row['2009'], idx, row['2013']-row['2009'], 0, head_width=0.2, head_length=0.7, width=0.03, fc=c, ec=c)
    if row['2009'] < row['2013']:
        ax.annotate('{}'.format(row['2009']), xy=(row['2009'], idx), xytext=(row['2009']-2.5,idx-0.05), xycoords='data', color=c)
        ax.annotate('{}'.format(row['2013']), xy=(row['2013'], idx), xytext=(row['2013']+0.9,idx-0.05), xycoords='data', color=c)
    else:
        ax.annotate('{}'.format(row['2009']), xy=(row['2009'], idx), xytext=(row['2009']+0.5,idx-0.05), xycoords='data', color=c)
        ax.annotate('{}'.format(row['2013']), xy=(row['2013'], idx), xytext=(row['2013']-2.5,idx-0.05), xycoords='data', color=c)

    ax.set_yticks(np.arange(len(df)))        
    ax.set_yticklabels(df['Party'])
    ax.grid()
    ax.set_xlim(-5,45)
    ax.tick_params('x', length=0, which='major')
    ax.tick_params('y', length=0, which='major')

ax.annotate('2009', xy=(0.25,0.85), xytext=(0.25,0.93), xycoords='figure fraction', arrowprops=dict(arrowstyle='-'))
ax.annotate('2013', xy=(0.45,0.85), xytext=(0.45,0.93), xycoords='figure fraction', arrowprops=dict(arrowstyle='-'))
plt.show()

enter image description here

Related