remove colorbars from plot - python

I wrote some code to create a png of a raster object (self[:] = a np array).
it's supposed to be a method, to easily make a plot
Problem with the code is that it runs fine the first time,
but when i run this method multiple times i get a picture with multiple legends.
I tried to get rid of it with delaxes, but this legend is really stubborn.
Any Idea's how to solve this are welcome
Here's the code:
def plot(self,image_out,dpi=150, rotate = 60):
xur = self.xur()
xll = self.xll()
yur = self.yur()
yll = self.yll()
fig = plt.figure()
#tmp = range(len(fig.axes))
#tmp = tmp[::-1]
#for x in tmp:
# fig.delaxes(fig.axes[x])
ax = fig.add_subplot(111)
cax = ax.imshow(self[:],cmap='jet', extent = [yll,yur,xll,xur],
interpolation = 'nearest')
cbar = fig.colorbar()
plt.xticks(rotation=70)
plt.tight_layout(pad = 0.25)
plt.savefig(image_out,dpi=dpi)
return

You need to close the plot. I had this same problem
After plt.savefig, add plt.close()

A better option is to specify to colorbar which axes you would like to see it render into, see the example here.

I encountered the same problem and the answers in another post solved it
remove colorbar from figure in matplotlib
Please refer to the second answer
I had a similar problem and played around a little bit. I came up with two solutions which might be slightly more elegant:
Clear the whole figure and add the subplot (+colorbar if wanted) again.
If there's always a colorbar, you can simply update the axes with autoscale which also updates the colorbar.
I've tried this with imshow, but I guess it works similar for other plotting methods.
In particular, I used the first approach, which is to clear the figure by clf() and then re-add the axis each time.

You can remove the colorbar by its .remove() method:
cbar = fig.colorbar()
...
cbar.remove()

Related

Saving matplotlib subplot figure to image file

I'm fairly new to matplotlib and am limping along. That said, I haven't found an obvious answer to this question.
I have a scatter plot I wanted colored by groups, and it looked like plotting via a loop was the way to roll.
Here is my reproducible example, based on the first link above:
import matplotlib.pyplot as plt
import pandas as pd
from pydataset import data
df = data('mtcars').iloc[0:10]
df['car'] = df.index
fig, ax = plt.subplots(1)
plt.figure(figsize=(12, 9))
for ind in df.index:
ax.scatter(df.loc[ind, 'wt'], df.loc[ind, 'mpg'], label=ind)
ax.legend(bbox_to_anchor=(1.05, 1), loc=2)
# plt.show()
# plt.savefig('file.png')
Uncommenting plt.show() yields what I want:
Searching around, it looked like plt.savefig() is the way to save a file; if I re-comment out plt.show() and run plt.savefig() instead, I get a blank white picture. This question, suggests this is cause by calling show() before savefig(), but I have it entirely commented out. Another question has a comment suggesting I can save the ax object directly, but that cuts off my legend:
The same question has an alternative that uses fig.savefig() instead. I get the same chopped legend.
There's this question which seems related, but I'm not plotting a DataFrame directly so I'm not sure how to apply the answer (where dtf is the pd.DataFrame they're plotting):
plot = dtf.plot()
fig = plot.get_figure()
fig.savefig("output.png")
Thanks for any suggestions.
Edit: to test the suggestion below to try tight_layout(), I ran this and still get a blank white image file:
fig, ax = plt.subplots(1)
plt.figure(figsize=(12, 9))
for ind in df.index:
ax.scatter(df.loc[ind, 'wt'], df.loc[ind, 'mpg'], label=ind)
ax.legend(bbox_to_anchor=(1.05, 1), loc=2)
fig.tight_layout()
plt.savefig('test.png')
Remove the line plt.figure(figsize=(12, 9)) and it will work as expected. I.e. call savefig before show.
The problem is that the figure being saved is the one created by plt.figure(), while all the data is plotted to ax which is created before that (and in a different figure, which is not the one being saved).
For saving the figure including the legend use the bbox_inches="tight" option
plt.savefig('test.png', bbox_inches="tight")
Of course saving the figure object directly is equally possible,
fig.savefig('test.png', bbox_inches="tight")
For a deeper understanding on how to move the legend out of the plot, see this answer.
Additional add-up on #ImportanceOfBeingErnest's answer, when bbox_inches='tight', 'pad_inches=0.1' may need to set to larger values.

Matplotlib: Hiding specific y-tick labels not working when ticks on the right side of plot

I'm creating a subplot figure with 2 columns and a number of rows. I'm using the following code to move my tick labels and axis label to the right side for the right column (but still keeping the tick marks on both sides):
fig, ax = plt.subplots(4, 2, sharex=False, sharey=False)
fig.subplots_adjust(wspace=0, hspace=0)
for a in ax[:,1]:
a.yaxis.tick_right()
a.yaxis.set_ticks_position('both')
a.yaxis.set_label_position('right')
Then, because the subplots are close together (which is what I want, I don't want any padding in between the plots), the top and bottom y-tick labels overlap between plots. I have attempted to fix this using the method described here (this selects only those ticks that are inside the view interval - check the link for more info):
import matplotlib.transforms as mtransforms
def get_major_ticks_within_view_interval(axis):
interval = axis.get_view_interval()
ticks_in_view_interval = []
for tick, loc in zip(axis.get_major_ticks(), axis.get_major_locator()()):
if mtransforms.interval_contains(interval, loc):
ticks_in_view_interval.append(tick)
return ticks_in_view_interval
for i,a in enumerate(ax.ravel()):
nplots = len(ax.ravel())
yticks = get_major_ticks_within_view_interval(a.yaxis)
if i != 0 and i != 1:
yticks[-1].label.set_visible(False)
if i != nplots-2 and i != nplots-1:
yticks[0].label.set_visible(False)
This seems to work fine for the left column, but in the right column the overlapping ticks are still visible. Does anyone know why this happens, and how to fix it? I just can't seem to figure it out.
I have finally found the solution, so I figured I'd put it here as well in case someone ever has the same problem (or if I forget what I did, haha). I found out when I happened upon the following page: http://matplotlib.org/1.3.1/users/artists.html
What I didn't realize is that the labels on the left and the right of the y-axis can be modified independently of each other. When using yticks[0].label.set_visible(False), the label refers only to the left side labels, so the right side labels stay unchanged. To fix it, I replaced
yticks[0].label.set_visible(False)
by
yticks[0].label1.set_visible(False)
yticks[0].label2.set_visible(False)
(and the same for yticks[-1]). Now it works like a charm!
Generally I've found that problems with overlap in matplotlib can be solved by using
plt.tight_layout()
have you tried that?

Clear overlay scatter on matplotlib image

So I am back again with another silly question.
Consider this piece of code
x = linspace(-10,10,100);
[X,Y]=meshgrid(x,x)
g = np.exp(-(square(X)+square(Y))/2)
plt.imshow(g)
scat = plt.scatter(50,50,c='r',marker='+')
Is there a way to clear only the scatter point on the graph without clearing all the image?
In fact, I am writing a code where the appearance of the scatter point is bound with a Tkinter Checkbutton and I want it to appear/disappear when I click/unclick the button.
Thanks for your help!
The return handle of plt.scatter has several methods, including remove(). So all you need to do is call that. With your example:
x = np.linspace(-10,10,100);
[X,Y] = np.meshgrid(x,x)
g = np.exp(-(np.square(X) + np.square(Y))/2)
im_handle = plt.imshow(g)
scat = plt.scatter(50,50,c='r', marker='+')
# image, with scatter point overlayed
scat.remove()
plt.draw()
# underlying image, no more scatter point(s) now shown
# For completeness, can also remove the other way around:
plt.clf()
im_handle = plt.imshow(g)
scat = plt.scatter(50,50,c='r', marker='+')
# image with both components
im_handle.remove()
plt.draw()
# now just the scatter points remain.
(almost?) all matplotlib rendering functions return a handle, which have some method to remove the rendered item.
Note that you need the call to redraw to see the effects of remove() -- from the remove help (my emphasis):
Remove the artist from the figure if possible. The effect will not be
visible until the figure is redrawn, e.g., with
:meth:matplotlib.axes.Axes.draw_idle.

Using matplotlib, is it possible to set properties for all subplots on a figure at once?

Using matplotlib (with Python), is it possible to set properties for all subplots on a figure at once?
I've created a figure with multiple subplots, and I currently have something like this:
import numpy as np
import matplotlib.pyplot as plt
listItems1 = np.arange(0, 100)
listItems8 = np.arange(0, 100)
listItems11 = np.arange(0, 100)
figure1 = plt.figure(1)
# First graph on Figure 1
graphA = figure1.add_subplot(2, 1, 1)
graphA.plot(listItems1, listItems8, label='Legend Title')
graphA.legend(loc='upper right', fontsize='10')
graphA.grid(True)
plt.xticks(range(0, len(listItems1) + 1, 36000), rotation='20', fontsize='7', color='white', ha='right')
plt.xlabel('Time')
plt.ylabel('Title Text')
# Second Graph on Figure 1
graphB = figure1.add_subplot(2, 1, 2)
graphB.plot(listItems1, listItems11, label='Legend Title')
graphB.legend(loc='upper right', fontsize='10')
graphB.grid(True)
plt.xticks(range(0, len(listItems1) + 1, 36000), rotation='20', fontsize='7', color='white', ha='right')
plt.xlabel('Time')
plt.ylabel('Title Text 2')
plt.show()
Question, is there a way to set any or all of those properties at once? I'm going to have 6 different subplots on one figure, and it's a bit tedious to keep copy/pasting the same "xticks" settings and "legend" settings over and over again.
Is there some kind of "figure1.legend(..." kind of thing?
Thanks. First post for me. Hello world! ;)
If your subplots are actually sharing an axis/some axes, you may be interested in specifying the sharex=True and/or sharey=True kwargs to subplots.
See John Hunter explaining more in this video. It can give your graph a much cleaner look and reduce code repetition.
I would suggest using a for loop:
for grph in [graphA, graphB]:
grph.#edit features here
You can also structure the for loop differently depending on how you want to do this, e.g.
graphAry = [graphA, graphB]
for ind in range(len(graphAry)):
grph = graphAry[ind]
grph.plot(listItems1, someList[ind])
#etc
The nice thing about subplots is that you can use a for loop to plot them too!
for ind in range(6):
ax = subplot(6,1,ind)
#do all your plotting code once!
You'll have to think about how to organize the data you want to plot to make use of the indexing. Make sense?
Whenever I do multiple subplots I think about how to use a for loop for them.

matplotlib colorbar in subplots: labels are vanishing

I am developing some code to produce an arbitrary number of 2D plots (maps and simple contour plots) on a figure. The matplotlib subplots routine works great for this. In the simplified example below, everything works as it should. However, in my real application - which uses the exact same commands for subplots, contourf and colorbar, only that these are dispersed across several routines - the labels on the colorbars are not showing up (the color patches seem to be ok though). Even after hours of reading documentation and searching the web, I don't even have a clue where I could start looking for what the problem is. If I have my colorbar instance (cbar), I should be able to find out if the ticklabel position makes sense, if the ticklabels are set to visible, if my font settings make sense, etc.... But how do I actually check these properties? Has anyone encountered similar problems already? (and even better: found a solution?) Oh yes: if I manually create a new figure and axes in the actual plotting routine (where the contourf command is issued), then it will work again. But that means losing all control over the figure layout etc. Could it be that I am not passing my axes instance correctly? Here is what I do:
fig, ax = plt.subplots(nrows, ncols)
row, col = getCurrent(...)
plotMap(x, y, data, ax=ax[row,col], ...)
Then, inside plotMap:
c = ax.contourf(x, y, data, ...)
ax.figure.colorbar(c, ax=ax, orientation="horizontal", shrink=0.8)
As said above, the example below with simplified plots and artificial data works fine:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0.,360.,5.)*np.pi/180.
y = np.arange(0.,360.,5.)*np.pi/180.
data = np.zeros((y.size, x.size))
for i in range(x.size):
data[:,i] = np.sin(x[i]**2*y**2)
fig, ax = plt.subplots(2,1)
contour = ax[0].contourf(x, y, data)
cbar = ax[0].figure.colorbar(contour, ax=ax[0], orientation='horizontal', shrink=0.8)
contour = ax[1].contourf(x, y, data, levels=[0.01,0.05,0.1,0.05])
cbar = ax[1].figure.colorbar(contour, ax=ax[1], orientation='horizontal', shrink=0.8)
plt.show()
Thanks for any help!
Addition after some further poking around:
for t in cbar.ax.get_xticklabels():
print t.get_position(), t.get_text(), t.get_visible()
shows me the correct text and visible=True, but all positions are (0.,0.). Could this be a problem?
BTW: axis labels are also missing sometimes... and I am using matplotlib version 1.1.1 with python 2.7.3 on windows.
OK - I could track it down: matplotlib is working as it should!
The error was embedded in a utility routine that adds some finishing touches to each page (=figure) once the given number of plot panels has been produced. In this routine I wanted to hide empty plot panels (i.e. on the last page) and I did this with
ax = fig.axes
for i in range(axCurrent, len(ax)):
ax[i].set_axis_off()
However, axCurrent was already reset to zero when the program entered this routine for any page but the last, hence the axes were switched off for all axes in figure. Adding
if axCurrent > 0:
before the for i... solves the problem.
Sorry if I stole anyone's time. Thanks anyway to everyone who was considering to help!

Categories