Search code examples
pythonmatplotlibplotantialiasing

Sub-pixel accuracy scatter plots with matplotlib?


Note: I figured out a solution to this question while writing it. My answer is below.

Is there an easy way to get sub-pixel antialiased placement of circles using matplotlib? I was able to create the following .gif but the fact that the motion of the circles steps by integer pixels is really bugging me.

enter image description here

I can of course render a large image (plt.savefig("image.png",dpi=1000)) and scale down, but the added complexity is a pain (this is an example for students, so importing extra tools will annoy the students and installing extra tools will annoy campus IT!)

import matplotlib.pyplot as plt
from math import sin,cos
x=[]
y=[]
#Create 41**2 particles in the unit square
for i in range(41):
    for j in range(41):
        x.append(i*0.05-1.0)
        y.append(j*0.05-1.0)
#5 second video at 30 fps = 150 frames
for n in range(150):
    plt.close('all')
    fig, axes = plt.subplots(figsize=(5,5))
    #some cool motion
    for i in range(len(x)):
        x[i]+=0.001*cos(x[i]+3*y[i])
        y[i]+=0.001*sin(6*x[i]-4*y[i])
    #create the scatter plot
    axes.scatter(x,y,s=3,antialiased=True)
    axes.set_xlim(-1.4,1.4)
    axes.set_ylim(-1.4,1.4)
    axes.set_aspect('equal')
    plt.savefig("out/fig%03d.png"%n,dpi=80)

Solution

  • You may be interested in https://github.com/anntzer/mplcairo, a new cairo-based backend for Matplotlib which I originally wrote exactly because I was unhappy with this issue. It does not display the aforementioned problem, while maintaining reasonable performance.