In this short guide I will show you how to animate a *Radar Plot* with matplotlib^{ [1]} in Python.

At the end of this guide you will be able to create radar plot animations like this one:

The only modules needed are numpy and matplotlib. Import them like this:

import numpy as np import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation

For this guide, I am creating some artificial data to make the data structure a bit more visible:

length = 250 data = [ [np.sin(i*0.06) for i in range(0, length)], [np.cos(i*0.06) for i in range(0, length)], [np.sin(i*0.06) for i in range(0, length)], [np.cos(i*0.06) for i in range(0, length)], [np.sin(i*0.06) for i in range(0, length)] ]

`data`

is a list of the different features that you want to plot. Every feature list contains the individual datapoints that will be plotted at frame `i`

. This means all lists have to be the same length.

Now, the first feature list will need to be copied to the end of the data list. This will ensure that the radar plot will be a closed polygon. The first and last datapoint will overlap and therefore close the shape.

data = [*data, data[0]] # This works too data.append(data[0])

To achieve this, we can use the syntax `*expression`

to spread out the list and append the first entry.

From the Python documentation:

If the syntax`{star}expression`

appears in the function call,`expression`

must evaluate to an iterable^{ [2]}. Elements from these iterables are treated as if they were additional positional arguments. For the call`f(x1, x2, {star}y, x3, x4)`

, if _y_ evaluates to a sequence _y1_, …, _yM_, this is equivalent to a call with M+4 positional arguments _x1_, _x2_, _y1_, …, _yM_, _x3_, _x4_.

To create labels for every feature in the data list, create a new list and apply the same procedure with the spread operator.

labels = ["Label 1", "Label 2", "Label 3", "Label 4", "Label 5"] labels = [*labels, labels[0]] # This works too labels.append(labels[0])

The last step, before plotting begins, will be to calculate evenly distributed positions for the labels like this:

# Get len(labels) equal distance points on a circle label_loc = np.linspace(0, 2*np.pi, num=len(labels))

For every animation in matplotlib an initial plot (using the first datapoints) is needed. To create a radar plot it is important to set the projection method to `polar`

.

fig, ax = plt.subplots(figsize=(10, 10), subplot_kw={'projection': 'polar'})

In a radar plot the x-values will correspond to the positions on the circle (0-360 degrees) and the y-values are the distances from the middle point of the circle.

Therefore the x-values will be the label positions and the y-values will be the datapoints. For the initial plot the first datapoints will be selected using a list comprehension.

radar_ln = ax.plot(label_loc, [d[0] for d in data], label="Legend")

The labels themselves will be placed at the previously calculated positions around the circle by converting the radians to degrees and setting the labels in the `set_thetagrids`

method.

ax.set_thetagrids(np.degrees(label_loc), labels=labels) ax.legend(loc="lower left", bbox_to_anchor=(0.95, 0.95))

The limits in a radar plot can be changed too:

ax.set_rmax(2) ax.set_rmin(-2)

Animating a plot with matplotlib will always include an `update(i)`

function which will update the plot with new data for every frame `i`

. In this case the new data will again be selected with a list comprehension (the same way the plot was initialized).

def update(i, radar_ln, label_loc, data): radar_ln[0].set_data(label_loc, [d[i] for d in data]) return radar_ln

Finally, it is only a matter of assigning the correct variables to `FuncAnimation`

before running the `save()`

method.

ani = FuncAnimation(fig, update, frames=len(data[0]), fargs=(radar_ln, label_loc, data), interval=40) ani.save("animation.mp4", dpi=300)