简体   繁体   English

从 matplotlib 中的图形中删除颜色条

[英]remove colorbar from figure in matplotlib

This should be easy but I'm having a hard time with it.这应该很容易,但我很难做到。 Basically, I have a subplot in matplotlib that I'm drawing a hexbin plot in every time a function is called, but every time I call the function I get a new colorbar, so what I'd really like to do is update the colorbar.基本上,我在 matplotlib 中有一个子图,每次调用函数时我都会在其中绘制一个十六进制图,但是每次调用该函数时我都会得到一个新的颜色条,所以我真正想做的是更新颜色条. Unfortunately, this doesn't seem to work since the object the colorbar is attached to is being recreated by subplot.hexbin.不幸的是,这似乎不起作用,因为颜色条附加到的对象正在由 subplot.hexbin 重新创建。

def foo(self):
   self.subplot.clear()
   hb = self.subplot.hexbin(...)
   if self.cb:
      self.cb.update_bruteforce() # Doesn't work (hb is new)
   else:
      self.cb = self.figure.colorbar(hb)

I'm now in this annoying place where I'm trying to delete the colorbar axes altogether and simply recreate it.我现在在这个烦人的地方,我试图完全删除颜色条轴并简单地重新创建它。 Unfortunately, when I delete the colorbar axes, the subplot axes don't reclaim the space, and calling self.subplot.reset_position() isn't doing what I thought it would.不幸的是,当我删除颜色条轴时,子图轴不会回收空间,并且调用 self.subplot.reset_position() 并没有按照我的想法去做。

def foo(self):
   self.subplot.clear()
   hb = self.subplot.hexbin(...)
   if self.cb:
      self.figure.delaxes(self.figure.axes[1])
      del self.cb
      # TODO: resize self.subplot so it fills the 
      #    whole figure before adding the new colorbar
   self.cb = self.figure.colorbar(hb)

Does anyone have any suggestions?有没有人有什么建议?

Much appreciated!非常感激! Adam亚当

I think the problem is that with del you cancel the variable, but not the referenced object colorbar.我认为问题在于使用del取消变量,而不是引用的对象颜色条。 If you want the colorbar to be removed from plot and disappear, you have to use the method remove of the colorbar instance and to do this you need to have the colorbar in a variable, for which you have two options:如果要从绘图中删除颜色条并消失,则必须使用颜色条实例的remove方法,为此,您需要将颜色条置于变量中,对此您有两个选择:

  1. holding the colorbar in a value at the moment of creation, as shown in other answers eg cb=plt.colorbar()在创建时将cb=plt.colorbar()保持在一个值中,如其他答案所示,例如cb=plt.colorbar()
  2. retrieve an existing colorbar, that you can do following (and upvoting :)) what I wrote here: How to retrieve colorbar instance from figure in matplotlib then:检索现有的颜色条,您可以执行以下操作(并投票:))我在这里写的内容: How to retrieve colorbar instance from figure in matplotlib then:

cb.remove() plt.draw() #update plot

Alright, here's my solution.好的,这是我的解决方案。 Not terribly elegant, but not a terrible hack either.不是非常优雅,但也不是一个可怕的黑客。

def foo(self):
   self.subplot.clear()
   hb = self.subplot.hexbin(...)
   if self.cb:
      self.figure.delaxes(self.figure.axes[1])
      self.figure.subplots_adjust(right=0.90)  #default right padding
   self.cb = self.figure.colorbar(hb)

This works for my needs since I only ever have a single subplot.这适合我的需要,因为我只有一个子图。 People who run into the same problem when using multiple subplots or when drawing the colorbar in a different position will need to tweak.在使用多个子图或在不同位置绘制颜色条时遇到相同问题的人需要进行调整。

I managed to solve the same issue using fig.clear() and display.clear_output()我设法使用 fig.clear() 和 display.clear_output() 解决了同样的问题

import matplotlib.pyplot as plt
import IPython.display as display
import matplotlib.tri as tri
from pylab import *
%matplotlib inline

def plot_res(fig):
    ax=fig.add_axes([0,0,1,1])
    ax.set_xlabel("x")
    ax.set_ylabel('y')
    plotted=ax.imshow(rand(250, 250))
    ax.set_title("title")
    cbar=fig.colorbar(mappable=plotted)
    display.clear_output(wait=True)
    display.display(plt.gcf())
    fig.clear()

fig=plt.figure()
N=20
for j in range(N):
    plot_res(fig)

I had a similar problem and played around a little bit.我有一个类似的问题,玩了一点。 I came up with two solutions which might be slightly more elegant:我想出了两个可能更优雅的解决方案:

  1. Clear the whole figure and add the subplot (+colorbar if wanted) again.清除整个图形并再次添加子图(如果需要,请添加颜色条)。

  2. 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.我已经用 imshow 尝试过这个,但我想它对其他绘图方法的工作方式类似。

from pylab import *
close('all') #close all figures in memory

#1. Figures for fig.clf method
fig1 = figure()
fig2 = figure()
cbar1=None
cbar2=None
data = rand(250, 250)

def makefig(fig,cbar):
  fig.clf()
  ax = fig.add_subplot(111)
  im = ax.imshow(data)
  if cbar:
    cbar=None
  else:
    cbar = fig.colorbar(im)
  return cbar


#2. Update method
fig_update = figure()
cbar3=None
data_update = rand(250, 250)
img=None

def makefig_update(fig,im,cbar,data):
  if im:
    data*=2 #change data, so there is change in output (look at colorbar)
    #im.set_data(data) #use this if you use new array
    im.autoscale()
    #cbar.update_normal(im) #cbar is updated automatically
  else:
    ax = fig.add_subplot(111)
    im = ax.imshow(data)
    cbar=fig.colorbar(im)
  return im,cbar,data

#Execute functions a few times
for i in range(3):
  print i
  cbar1=makefig(fig1,cbar1)
  cbar2=makefig(fig2,cbar2)
  img,cbar3,data_update=makefig_update(fig_update,img,cbar3,data_update)
cbar2=makefig(fig2,cbar2)

fig1.show()
fig2.show()
fig_update.show()

I needed to remove colorbars because I was plotting a pcolormesh and adding colorbar to a figure in a loop.我需要删除颜色条,因为我正在绘制 pcolormesh 并将颜色条添加到循环中的图形中。 Each loop would create a new colorbar and after ten loops I would have ten colorbars.每个循环都会创建一个新的颜色条,十个循环后我会有十个颜色条。 That was bad.那很糟糕。

To remove colorbars, I name the pcolormesh and colorbar a variable, then at the end of my loop I remove each.要删除颜色条,我将 pcolormesh 和颜色条命名为变量,然后在循环结束时删除每个。 It is important to remove the colorbar before removing the pcolormesh.移除 pcolormesh之前移除颜色条很重要。

Psudo Code:伪代码:

 for i in range(0,10):
   p = plt.pcolormesh(datastuff[i])
   cb = plt.colorbar(p)
   plt.savefig('name_'+i)

   cb.remove()
   p.remove()

Again, it was necessary to remove the colorbar before the pcolormesh同样,有必要在 pcolormesh 之前删除颜色条

If you have a matplotlib figure object you just need to do fig.delaxes(fig.axes[1])如果你有一个 matplotlib 图形对象,你只需要执行fig.delaxes(fig.axes[1])

For example:例如:

Plot with colorbar用颜色条绘图

import matplotlib.pyplot as plt

# setup some generic data
N = 37
x, y = np.mgrid[:N, :N]
Z = (np.cos(x*0.2) + np.sin(y*0.3))

# mask out the negative and positive values, respectively
Zpos = np.ma.masked_less(Z, 0)
Zneg = np.ma.masked_greater(Z, 0)

fig, ax1 = plt.subplots(figsize=(13, 3), ncols=1)

# plot just the positive data and save the
# color "mappable" object returned by ax1.imshow
pos = ax1.imshow(Zpos, cmap='Blues', interpolation='none')

# add the colorbar using the figure's method,
# telling which mappable we're talking about and
# which axes object it should be near
fig.colorbar(pos, ax=ax1)

在此处输入图片说明

Remove colorbar删除颜色条

import matplotlib.pyplot as plt

# setup some generic data
N = 37
x, y = np.mgrid[:N, :N]
Z = (np.cos(x*0.2) + np.sin(y*0.3))

# mask out the negative and positive values, respectively
Zpos = np.ma.masked_less(Z, 0)
Zneg = np.ma.masked_greater(Z, 0)

fig, ax1 = plt.subplots(figsize=(13, 3), ncols=1)

# plot just the positive data and save the
# color "mappable" object returned by ax1.imshow
pos = ax1.imshow(Zpos, cmap='Blues', interpolation='none')

# add the colorbar using the figure's method,
# telling which mappable we're talking about and
# which axes object it should be near
fig.colorbar(pos, ax=ax1)

fig.delaxes(fig.axes[1])

在此处输入图片说明

I am using matplotlib 1.4.0.我正在使用 matplotlib 1.4.0。 This is how I solve this problem:这是我解决这个问题的方法:

import matplotlib
import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt

# A contour plot example:
delta = 0.025
x = np.arange(-3.0, 3.0, delta)
y = np.arange(-2.0, 2.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = 10.0 * (Z2 - Z1)
#

# first drawing
fig = plt.figure()
ax = fig.add_subplot(111)  # drawing axes
c = ax.contourf(Z)   # contour fill c
cb = fig.colorbar(c)  # colorbar for contour c

# clear first drawimg
ax.clear()  # clear drawing axes
cb.ax.clear()  # clear colorbar axes

# replace with new drawing
# 1. drawing new contour at drawing axes
c_new = ax.contour(Z)  
# 2. create new colorbar for new contour at colorbar axes
cb_new = ax.get_figure().colorbar(c_new, cax=cb.ax) 

plt.show()

Above code draws a contour fill plot with colorbar, clear it and draw a new contour plot with new colorbar at the same figure.上面的代码绘制了一个带有颜色条的轮廓填充图,清除它并在同一图形上绘制一个带有新颜色条的新轮廓图。

By using cb.ax i am able to identify the colorbar axes and clear the old colorbar.通过使用cb.ax我能够识别cb.ax轴并清除旧的颜色条。 And specifying cax=cb.ax simply draws the new colorbar in the old colorbar axes.并且指定cax=cb.ax只是在旧的cax=cb.ax绘制新的cax=cb.ax

Don't want to take anything away from the author of this blog post (Joseph Long) but this is clearly the best solution I've found so far.不想从这篇博文(Joseph Long)的作者那里拿走任何东西,但这显然是我迄今为止找到的最好的解决方案。 It includes pieces of code, great explanations and many examples.它包括代码片段、很好的解释和许多示例。

To summarize, from any output of an axis ax of the command: plot , image , scatter , collection , etc. such as:总而言之,从命令的轴ax的任何输出: plotimagescattercollection等,例如:

import matplotlib.pyplot as plt
fig = plt.figure(figsize=(5,5), dpi=300)
ax = fig.add_subplot(1, 1, 1)

data = ax.plot(x,y)
# or
data = ax.scatter(x, y, z)
# or
data = ax.imshow(z)
# or 
data = matplotlib.collection(patches)
ax.add_collection(data)

You create a color bar axis using the make_axes_locatable and the original axis of the plot.您可以使用make_axes_locatable和绘图的原始轴创建颜色条轴。

from mpl_toolkits.axes_grid1 import make_axes_locatable

# the magical part
divider = make_axes_locatable(ax)
caxis = divider.append_axes("right", size="5%", pad=0.05)
fig.colorbar(data, cax=caxis)

plt.show()

The created colorbar will have the same size as the figure or subplot and you can modify it's width , location , padding when using the divider.append_axes command.创建的颜色条将与图形或子图具有相同的大小,您可以在使用divider.append_axes命令时修改它的宽度位置填充

My solution consists in having an Axes whose only purpose is to hold the colorbar, and clear it entirely when needed.我的解决方案包括拥有一个轴,其唯一目的是保持颜色条,并在需要时完全清除它。

For example, define those once:例如,定义一次:

figure, ax = plt.subplots() # All the plotting is done on `ax`.
cax = ax.inset_axes([1.03, 0, 0.1, 1], transform=ax.transAxes) # Colorbar is held by `cax`. 

Then do this as many times as needed:然后根据需要多次执行此操作:

cax.clear()
colorbar = figure.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=cmap),
                           ax=ax,
                           cax=cax,
                           **kwargs)

在此处输入图片说明

"on_mappable_changed" worked in my case. “on_mappable_changed”在我的情况下有效。 However, according to docs, the method "Typically ... should not be called manually."但是,根据文档,该方法“通常......不应手动调用”。

if self.cb:
    self.cb.on_mappable_changed(hb)
else:
    self.cb = self.fig.colorbar(hb)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM