I have some data that I plotted with Python but now I want to erase the plots but not the figure itself.
I have some thing like this :
import numpy as np
import pylab as plt
a = np.array([1,2,3,4,5,6,7,8,9,10])
b = np.array([1,2,3,4,5,6,7,8,9,10])
c = plt.plot(a,b,'r.')
So to clear this I tried this :
a = np.array([])
b = np.array([])
c = plt.plot(a,b,'r.')
but it does not work. What is the best way to accomplish this?
You can use the remove method of the returned plot object. This is true of any plot object that inherits from Artist.
c = plt.plot(a,b,'r.')
for handle in c:
handle.remove()
To have axes with the same values of your a, b arrays, you can do:
import matplotlib.pyplot as plt
plt.clf() # To clear the figure.
plt.axis([1,10,1,10])
From here:
When to use cla(), clf() or close() for clearing a plot in matplotlib?
plt.cla() clears an axis, i.e. the currently active axis in the
current figure. It leaves the other axes untouched.
plt.clf() clears the entire current figure with all its axes, but
leaves the window opened, such that it may be reused for other plots.
plt.close() closes a window, which will be the current window, if not
specified otherwise.
Also if you prefer doing it line by line, you can remove them like this even if you've lost original references:
for l in ax.get_lines():
xval = l.get_xdata()[0]
if (xval == my_criteria):
l.remove()
or for all, simply:
for l in ax.get_lines():
l.remove()
likewise you can do the same indexing by y values.
Related
When I plot some data with matplotlib without setting any parameters, the data gets plotted with both x and y axis limits set correctly, meaning that all data is shown and no space is wasted (case 1):
import matplotlib
matplotlib.use('QT5Agg')
import matplotlib.pyplot as plt
x = range(10)
plt.plot(x,'-o',markersize='10')
plt.tight_layout()
plt.show()
Result:
If I set some limits for e. g. the x axis, even using autoscale() does not autoscale the y axis anymore (case 2):
import matplotlib
matplotlib.use('QT5Agg')
import matplotlib.pyplot as plt
x = range(10)
plt.plot(x,'-o',markersize='10')
plt.autoscale(enable=True,axis='y')
plt.xlim(7.5,11)
plt.tight_layout()
plt.show()
Result:
Question: which function is used internally by matplotlib to determine the limits for both axes and update the plot in case 1?
Background: I want to use this function as a base for reimplementing / extending this functionality for case 2.
As #ImportanceOfBeingEarnest pointed out in the answer below, there is no such automatized way at the moment. So, in case you are interested in knowing how to rescale your y-axis, one way to do so is by recomputing the corresponding y-values and then reassigning the y-limits using the method specified in this unaccepted answer. I haven't marked this as a duplicate because there are certain different issues in your example:
First (major one), you have plotted only x-values. So, to apply the method in the other answer, I had to first get the y-values in an array. This is done using get_ydata()
Second, the x-values were changed from range() generator to a NumPy array, as the former does not support indexing.
Third, I had to use a variable for the x-limits to be consistent with the function.
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
plt.plot(x,'-o',markersize='10')
x_lims = [7.5, 11]
plt.xlim(x_lims)
ax = plt.gca()
y = ax.lines[0].get_ydata()
def find_nearest(array,value):
idx = (np.abs(array-value)).argmin()
return idx
y_low = y[find_nearest(x, x_lims[0])]
y_high = y[find_nearest(x, x_lims[1])]
ax.set_ylim(y_low, y_high)
plt.tight_layout()
plt.show()
When updating an "imshow" plot in matplotlib, it's best to use im.set_data, rather than using ax.imshow repeatedly in the loop. But what if the extent of the data is changing? Is it possible to update the extent of the data on each iteration of the loop?
Here is an example:
import numpy as np
import matplotlib.pyplot as plt
import time
ax = plt.subplot(111)
plt.ion()
plt.show()
count = 0
for size in np.linspace(1,3,10):
x = np.linspace(-size,size,100)
y = np.linspace(-size,size,100)
X,Y = np.meshgrid(x,y)
R = (X**2+Y**2)**0.5
Z = np.sin(R)/R
ext =(-size,size,-size,size)
if count == 0:
im = plt.imshow(Z,extent=ext)
else:
im.set_data(Z)
# Update the extent of the data
plt.draw()
plt.pause(0.5)
ax.set_xlim(-size,size)
ax.set_ylim(-size,size)
count += 1
plt.ioff()
plt.show()
The colored region should take up the entire axes if I could update the extent properly.
In your example, im.set_extent(ext).
More generally, though, almost any kwarg you can pass in to a matplotlib artist during initialization will have get_foo and set_foo methods. (That's actually how initialization works and how artist.set(...) and plt.setp works, as well.)
If you're looking for how to change a given property, the first place to look is a set_<name> method.
There are exceptions to this. For example, scatter returns a Collection, so you need to call set_offsets instead of set_xy to change the x, y data. Generally speaking, though, it's consistent.
I am looping through a bunch of CSV files containing various measurements.
Each file might be from one of 4 different data sources.
In each file, I merge the data into monthly datasets, that I then plot in a 3x4 grid. After this plot has been saved, the loop moves on and does the same to the next file.
This part I got figured out, however I would like to add a visual clue to the plots, as to what data it is. As far as I understand it (and tried it)
plt.subplot(4,3,1)
plt.hist(Jan_Data,facecolor='Red')
plt.ylabel('value count')
plt.title('January')
does work, however this way, I would have to add the facecolor='Red' by hand to every 12 subplots. Looping through the plots wont work for this situation, since I want the ylabel only for the leftmost plots, and xlabels for the bottom row.
Setting facecolor at the beginning in
fig = plt.figure(figsize=(20,15),facecolor='Red')
does not work, since it only changes the background color of the 20 by 15 figure now, which subsequently gets ignored when I save it to a PNG, since it only gets set for screen output.
So is there just a simple setthecolorofallbars='Red' command for plt.hist(… or plt.savefig(… I am missing, or should I just copy n' paste it to all twelve months?
You can use mpl.rc("axes", color_cycle="red") to set the default color cycle for all your axes.
In this little toy example, I use the with mpl.rc_context block to limit the effects of mpl.rc to just the block. This way you don't spoil the default parameters for your whole session.
import matplotlib as mpl
import matplotlib.pylab as plt
import numpy as np
np.random.seed(42)
# create some toy data
n, m = 2, 2
data = []
for i in range(n*m):
data.append(np.random.rand(30))
# and do the plotting
with mpl.rc_context():
mpl.rc("axes", color_cycle="red")
fig, axes = plt.subplots(n, m, figsize=(8,8))
for ax, d in zip(axes.flat, data):
ax.hist(d)
The problem with the x- and y-labels (when you use loops) can be solved by using plt.subplots as you can access every axis seperately.
import matplotlib.pyplot as plt
import numpy.random
# creating figure with 4 plots
fig,ax = plt.subplots(2,2)
# some data
data = numpy.random.randn(4,1000)
# some titles
title = ['Jan','Feb','Mar','April']
xlabel = ['xlabel1','xlabel2']
ylabel = ['ylabel1','ylabel2']
for i in range(ax.size):
a = ax[i/2,i%2]
a.hist(data[i],facecolor='r',bins=50)
a.set_title(title[i])
# write the ylabels on all axis on the left hand side
for j in range(ax.shape[0]):
ax[j,0].set_ylabel(ylabel[j])
# write the xlabels an all axis on the bottom
for j in range(ax.shape[1]):
ax[-1,j].set_xlabel(xlabels[j])
fig.tight_layout()
All features (like titles) which are not constant can be put into arrays and placed at the appropriate axis.
I have two similar pieces of matplotlib codes that produce different results.
1:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0,10,100)
y = np.linspace(0,10,100)
y[10:40] = np.nan
plt.plot(x,y)
plt.savefig('fig')
2:
from pylab import *
x = linspace(0,10,100)
y = linspace(0,10,100)
y[10:40] = np.nan
plot(x,y)
savefig('fig')
Code #1 produces a straight line with the NaN region filled in with a solid line of a different color
Code #2 produces a figure with a straight line but does not fill in the NaN region with a line. Instead there is a gap there.
How can I make code # 1 produce a gap in place of NaN's like code #2. I have been googling for a couple of days and have come up with nothing. Any help or advice would be appreciated. Thanks in advance
Just to explain what's probably happening:
The two pieces of code you showed are identical. They will always produce the same output if called by themselves. pylab is basically a just a few lines of code that does: (There's a bit more to it than this, but it's the basic idea.)
from numpy import *
from matplotlib.mlab import *
from matplotlib.pyplot import *
There's absolutely no way for pylab.plot to reference a different function than plt.plot
However, if you just call plt.plot (or pylab.plot, they're the same function), it plots on the current figure.
If you plotted something on that figure before, it will still be there. (If you're familiar with matlab, matplotlib defaults to hold('on'). You can change this with plt.hold, but it's best to be more explicit in python and just create a new figure.)
Basically, you probably did this:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0,10,100)
y = np.linspace(0,10,100)
plt.plot(x,y)
plt.savefig('fig')
And then, in the same interactive ipython session, you did this:
y[10:40] = np.nan
plt.plot(x, y)
plt.savefig('fig')
Because you didn't call show, the current figure is still the same one as it was before. The "full" line is still present beneath the second one, and the second line with the NaN's is a different color because you've plotted on the same axes.
This is one of the many reasons why it's a good idea to use the object-oriented interface. That way you're aware of exactly which axes and figure you're plotting on.
For example:
fig, ax = plt.subplots()
ax.plot(x, y)
fig.savefig('test.png')
If you're not going to do that, at very least always explicitly create a new figure and/or axes when you want a new figure. (e.g. start by calling plt.figure())
I have a strange error which I can't fix without your help. After I set an image with imshow in matplotlib it stays the same all the time even if I change it with the method set_data. Just take a look on this example:
import numpy as np
from matplotlib import pyplot as plt
def newevent(event):
haha[1,1] += 1
img.set_data(haha)
print img.get_array() # the data is change at this point
plt.draw()
haha = np.zeros((2,2))
img = plt.imshow(haha)
print img.get_array() # [[0,0],[0,0]]
plt.connect('button_press_event', newevent)
plt.show()
After I plot it, the method set_data doesn't change anything inside the plot. Can someone explain me why?
EDIT
Just added a few lines to point out what I actually want to do.
I want to redraw the data after I press a mouse button. I don't want to delete the whole figure, because it would be stupid if only one thing changes.
The problem is because you have not updated the pixel scaling after the first call.
When you instantiate imshow, it sets vmin and vmax from the initial data, and never touches it again. In your code, it sets both vmin and vmax to 0, since your data, haha = zeros((2,2)), is zero everywhere.
Your new event should include autoscaling with img.autoscale() , or explicitly set new scaling terms by setting img.norm.vmin/vmax to something you prefer.
The function to set the new vmin and vmax is:
img.set_clim(vmin=new_vim, vmax=new_vmax)
Does this give you the output you expect?
import numpy as np
from matplotlib import pyplot as plt
haha = np.zeros((2,2))
img = plt.imshow(haha)
print img.get_array() # [[0,0],[0,0]]
haha[1,1] += 1
img.set_data(haha)
img = plt.imshow(haha) # <<------- added this line
print img.get_array() # [[0,0],[0,1]]
plt.show()
When I display the plot twice (once before the change to haha, and at the end), it does change.