Lucas Nogueira Lucas Nogueira - 1 month ago 11
Python Question

Python: How to update the area in a scatter without updating x and y

Does anyone know how to update the s argument of the function scatter without having to give x and y as arguments again? I am trying to make an animation where the scatter circles increase in size, but the only way I can have it working requires me to give x and y as arguments every time I update the area.

This is the code I am working on:

#population plot
#plots a graph of the input from a file

import matplotlib.pyplot as plt;
import classplace as p;
import matplotlib.animation as amt

def animate(i, population, latitude, longitude, colour):
scalefactor = 0.00005;
area = [];
for n in population:
area.append(n*scalefactor*i);

plt.scatter(longitude, latitude, s = area, c = colour);
del area;
try:
readFile = open("GBplaces.csv", "r");

except:
print("Something went wrong! Can't open the file GBplaces.csv!\n");

else:
header = False;
places = [];

#stores the data in a list, where each element of the list is of class place, converting when necessary.
#Stores the header in a string
for line in readFile:
if(line[0] != '%'):
words = line.rstrip();
words = words.split(',');
places.append(p.Place(words[0], words[1], int(words[2]), float(words[3]), float(words[4])));

#closes readFile
readFile.close();

#creates an array of colours where cities are green and towns are yellow
#creates an array of longitude
#creates an array of latitude
#creates an array of population

colour = [];
longitude = [];
latitude = [];
population = [];

for n in range(p.Place.numcities + p.Place.numtowns):
if(places[n].tipe == "City"): colour.append("g");
else: colour.append("y");

longitude.append(places[n].longitude);
latitude.append(places[n].latitude);
population.append(places[n].population);

fig = plt.figure();

ani = amt.FuncAnimation(fig, animate, frames=50, fargs = (population, latitude, longitude, colour), interval=0.1, repeat = False, blit = False)
plt.show()


Where classplace is a file with the class definition

#classplace.py
#place class definition

class Place:
numcities = 0;
numtowns = 0;

def __init__(self, name, tipe, population, latitude, longitude):
self.name = name;
self.tipe = tipe;
self.population = population;
self.latitude = latitude;
self.longitude = longitude;

if(self.tipe == "City"): Place.numcities += 1;
elif(self.tipe == "Town"): Place.numtowns += 1;
else:
print("Instance is not allowed. You need to specify if %s is a City or Town.\n" %(self.name));
del self;


If I could update only the area the efficiency would get way much better.
Thank you for your help!

Answer

scatter returns matplotlib.collections.PathCollection object. You can use its methods get_sizes() and set_sizes() to retrieve or set sizes of points. Here is a modification of your example.

import matplotlib.pyplot as plt;
import matplotlib.animation as amt

# to embed animation as html5 video in Jupyter notebook
from matplotlib import rc
rc('animation', html='html5')

def animate(i, population, latitude, longitude, colour):
    scalefactor = 0.001
    area = [n*scalefactor*i for n in population]
    # it is better to use list comprehensions here

    sc.set_sizes(area)
    # here is the answer to the question

    return (sc,)

#creates an array of colours where cities are green and towns are yellow
#creates an array of longitude
#creates an array of latitude
#creates an array of population

# pick some random values

colour = ['g', 'g', 'y', 'y', 'y'];
longitude = [1, 2, 3, 4, 5];
latitude = [1, 3, 2, 5, 4];
population = [1000, 2000, 5000, 4000, 3000];

fig = plt.figure()
sc = plt.scatter(longitude, latitude, s=population)

# I didn't managed this to work without `init` function

def init():
    return (sc,)

ani = amt.FuncAnimation(fig, animate, frames=200, init_func=init,
                        fargs=(population, latitude, longitude, colour), 
                        interval=10, repeat = False, blit = True)

animation

Comments