0

I have the following data, here is a section of it

[{'Date': '2017 Q1', 'Saudi Arabia': 3.5080621303094413, 'Oman': 2.0803722435647836, 'Yemen': 1.9636651338439473, 'Israel': 3.0247692259733565}, {'Date': '2017 Q2', 'Saudi Arabia': 3.03137342597358, 'Oman': 2.2666875108328357, 'Yemen': 2.0820441357351513, 'Israel': 3.145231552094236}, {'Date': '2017 Q3', 'Saudi Arabia': 2.4309916593024394, 'Oman': 2.4635716453158922, 'Yemen': 2.326399413964078, 'Israel': 2.792350006532546}, {'Date': '2017 Q4', 'Saudi Arabia': 3.699283062258509, 'Oman': 3.1202643793473914, 'Yemen': 2.924974137360855, 'Israel': 3.5534406207725384}, {'Date': '2018 Q1', 'Saudi Arabia': 4.685752914561016, 'Oman': 3.7256945856760573, 'Yemen': 3.64807891731718, 'Israel': 4.3811754907135745}]

Except I have the 'Date' set as my index in my df.

I have tried to make an animated line chart using the following:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

file_path= r"C:\Users\Willi\OneDrive\Desktop\Data_for_chart.xlsx"
Title_for_chart = "Middle East inflation"


df = pd.read_excel(file_path)
df = df.T
header = df.iloc[0]
df = df[1:]
df.columns = header
df = df.apply(pd.to_numeric, errors = 'coerce')


#Getting the values so can easily adjust the axis
max_value = df.max().max() + df.max().max()*0.2
min_value = df.min().min() - df.min().min()*0.2


#plotting to see how it would look
dates_vals = list(df.index)
plt.plot(dates_vals, df.iloc[:,:])
plt.show()


##Setting up for animation
%matplotlib

fig, ax = plt.subplots(figsize=(12, 6))
lines = [ax.plot([], [], linestyle='-')[0] for _ in range(df.shape[1])]


def init():
    for line in lines:
        line.set_data([], [])
    return lines

def animate(i):
    for j, line in enumerate(lines):
        line.set_data(dates_vals[:i], df.iloc[:i, j])
    return lines

ani = animation.FuncAnimation(fig=fig, func=animate, frames=len(df), init_func=init, blit=True, repeat=True)

I have set it up like this as then regardless of the number of quarters or number of countries, the chart will work as it comes from an excel file that varies. However, it works when I do plt.show(), but have been unable to get it to animate?

Any suggestions would be greatly appreciated.

1 Answer 1

1

Here is a working version of that code:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

data = [{'Date': '2017 Q1', 'Saudi Arabia': 3.5080621303094413, 'Oman': 2.0803722435647836, 'Yemen': 1.9636651338439473, 'Israel': 3.0247692259733565},
        {'Date': '2017 Q2', 'Saudi Arabia': 3.03137342597358, 'Oman': 2.2666875108328357, 'Yemen': 2.0820441357351513, 'Israel': 3.145231552094236},
        {'Date': '2017 Q3', 'Saudi Arabia': 2.4309916593024394, 'Oman': 2.4635716453158922, 'Yemen': 2.326399413964078, 'Israel': 2.792350006532546},
        {'Date': '2017 Q4', 'Saudi Arabia': 3.699283062258509, 'Oman': 3.1202643793473914, 'Yemen': 2.924974137360855, 'Israel': 3.5534406207725384},
        {'Date': '2018 Q1', 'Saudi Arabia': 4.685752914561016, 'Oman': 3.7256945856760573, 'Yemen': 3.64807891731718, 'Israel': 4.3811754907135745}]

df = pd.DataFrame(data)
df.set_index('Date', inplace=True)
df = df.apply(pd.to_numeric, errors = 'coerce')


max_value = df.max().max() + df.max().max()*0.2
min_value = df.min().min() - df.min().min()*0.2


dates_vals = list(df.index)
plt.plot(dates_vals, df.iloc[:,:])
date_indices = np.arange(len(dates_vals))

plt.show()


fig, ax = plt.subplots(figsize=(12, 6))
lines = [ax.plot([], [], linestyle='-')[0] for _ in range(df.shape[1])]


def init():
    for line in lines:
        line.set_data([], [])
    return lines

def animate(i):
    for j, line in enumerate(lines):
        # Use date_indices instead of dates_vals
        line.set_data(date_indices[:i], df.iloc[:i, j])
    return lines

# Set the x labels correctly
ax.set_xlim(0, len(date_indices) - 1)
ax.set_ylim(min_value, max_value)

ani = animation.FuncAnimation(fig=fig, func=animate, frames=len(df) + 1, init_func=init, blit=True, repeat=True)
ax.set_xticks(date_indices)
ax.set_xticklabels(dates_vals, rotation=45)

# Show the animation
plt.show()


My changes were:

  • adding plt.show() in the end to show the animation
  • to fix this error: matplotlib.units.ConversionError: Failed to convert value(s) to axis units: ['2017 Q1', '2017 Q2', '2017 Q3', '2017 Q4'] I converted dates_vals from strings to numerical indices and used those indices in the animation.
def animate(i):
    for j, line in enumerate(lines):
        line.set_data(date_indices[:i], df.iloc[:i, j])
    return lines
  • Of course this meant that I had set the x-axis ticks and labels correctly.
ax.set_xticks(date_indices)
ax.set_xticklabels(dates_vals, rotation=45)

If you're working in a Jupyter notebook or Google colab and the animation doesn't work, try saving it as a file like so

ani.save('animation.gif', writer='imagemagick')

(I tested my code locally by running the script using python script.py, but not on Jupyter notebook or Colab)

2
  • Thank you every so much! Worked brilliantly and I learnt why, thanks :) Commented Jul 28 at 12:08
  • Since Jupyter was mentioned, I'll add that it should be possible to make it work in current Jupyter flavors by installing ipympl and using %matplotlib ipympl , see here for examples and a working environment you can use without touching your own system for testing/development.
    – Wayne
    Commented Jul 28 at 13:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.