2016-12-14 22 views
2

我正在生成一组3D数据的2D热图图。我希望能够有一种机制来交互式地浏览每个窗格。下面是一个简单的示例代码,我希望能够通过滑动条(或其他方式)交互式地查看这两个窗格(即z = [0,1])。这是可能的matplotlib或这是我需要做后处理后生成的图像文件?在matplotlib中分页/滚动2D热图集

import numpy as np 
from matplotlib import pyplot as plt 
data = np.random.randint(10, size=(5, 5, 2)) 
data_slice = np.zeros((5,5)) 
for i in range(0, 5): 
    for j in range(0, 5): 
    data_slice[i][j] = data[i][j][0] 
plt.imshow(data_slice, cmap='hot', interpolation='nearest') 
plt.show() 

编辑:我希望能够做到这一点交互和它看来,possible duplicate正在尝试自动执行此操作。

+1

的可能的复制[如何更新matplotlib的imshow()窗口交互?](http://stackoverflow.com/questions/17835302/how-to-update-matplotlibs-imshow-window -interactively) – Andrew

+1

没有重复!这个问题询问有关手动更新matplotlib窗口,而建议的问题询问有关自动做这件事。该解决方案显着不同,因为这里必须使用手动元素(如答案中的Slider),而在自动更新中需要使用定时器(FuncAnimation)。 – ImportanceOfBeingErnest

回答

4

您可以动画层由安德鲁的意见的建议,或者您可以通过该层使用滑块如下手动走:

import numpy as np 
from matplotlib import pyplot as plt 
from matplotlib.widgets import Slider 

# generate a five layer data 
data = np.random.randint(10, size=(5, 5, 5)) 
# current layer index start with the first layer 
idx = 0 

# figure axis setup 
fig, ax = plt.subplots() 
fig.subplots_adjust(bottom=0.15) 

# display initial image 
im_h = ax.imshow(data[:, :, idx], cmap='hot', interpolation='nearest') 

# setup a slider axis and the Slider 
ax_depth = plt.axes([0.23, 0.02, 0.56, 0.04]) 
slider_depth = Slider(ax_depth, 'depth', 0, data.shape[2]-1, valinit=idx) 

# update the figure with a change on the slider 
def update_depth(val): 
    idx = int(round(slider_depth.val)) 
    im_h.set_data(data[:, :, idx]) 

slider_depth.on_changed(update_depth) 

plt.show() 

滑块是持续而层指数是离散的整数,我希望这不是问题。这里是由此得出的数字,

enter image description here

+0

是否可以通过使用'valfmt'来控制滑块旁显示的值?在我的情况下,该值表示分钟数量,但我想显示“01:32”(即更可读的时间格式)而不是“92”。 –

+0

您可以重新定义'matplotlib.widgets.Slider' - 特别是'set_val'方法,如https://stackoverflow.com/questions/13656387/can-i-make-matplotlib-sliders-more-discrete所示。为了格式化你的时间,你可以使用'datetime'模块中的'datetime'。 'datetime.fromtimestamp(92).strftime(“%M:%S”)'=> '01:32' – hashmuke

3

的解决方案确实能够使用滑块作为由@hashmuke的出色答卷。在他的答案,他提到, “滑块是连续的,而该层指数是离散的整数[...]”

这使我想到,不会有这样的限制,并且有
解决方案 更像页面的外观和感觉

结果是PageSlider。子类化Slider它利用滑块功能,但以从1开始的整数步骤显示滑块。它将页面数numpages作为初始参数,但除了从外部看到的Slider以外。另外它还提供了一个后退和前进按钮。

一个类似于@hashmuke的例子在类下面给出。

import matplotlib.widgets 
import matplotlib.patches 
import mpl_toolkits.axes_grid1 

class PageSlider(matplotlib.widgets.Slider): 

    def __init__(self, ax, label, numpages = 10, valinit=0, valfmt='%1d', 
       closedmin=True, closedmax=True, 
       dragging=True, **kwargs): 

     self.facecolor=kwargs.get('facecolor',"w") 
     self.activecolor = kwargs.pop('activecolor',"b") 
     self.fontsize = kwargs.pop('fontsize', 10) 
     self.numpages = numpages 

     super(PageSlider, self).__init__(ax, label, 0, numpages, 
          valinit=valinit, valfmt=valfmt, **kwargs) 

     self.poly.set_visible(False) 
     self.vline.set_visible(False) 
     self.pageRects = [] 
     for i in range(numpages): 
      facecolor = self.activecolor if i==valinit else self.facecolor 
      r = matplotlib.patches.Rectangle((float(i)/numpages, 0), 1./numpages, 1, 
           transform=ax.transAxes, facecolor=facecolor) 
      ax.add_artist(r) 
      self.pageRects.append(r) 
      ax.text(float(i)/numpages+0.5/numpages, 0.5, str(i+1), 
        ha="center", va="center", transform=ax.transAxes, 
        fontsize=self.fontsize) 
     self.valtext.set_visible(False) 

     divider = mpl_toolkits.axes_grid1.make_axes_locatable(ax) 
     bax = divider.append_axes("right", size="5%", pad=0.05) 
     fax = divider.append_axes("right", size="5%", pad=0.05) 
     self.button_back = matplotlib.widgets.Button(bax, label=ur'$\u25C0$', 
         color=self.facecolor, hovercolor=self.activecolor) 
     self.button_forward = matplotlib.widgets.Button(fax, label=ur'$\u25B6$', 
         color=self.facecolor, hovercolor=self.activecolor) 
     self.button_back.label.set_fontsize(self.fontsize) 
     self.button_forward.label.set_fontsize(self.fontsize) 
     self.button_back.on_clicked(self.backward) 
     self.button_forward.on_clicked(self.forward) 

    def _update(self, event): 
     super(PageSlider, self)._update(event) 
     i = int(self.val) 
     if i >=self.valmax: 
      return 
     self._colorize(i) 

    def _colorize(self, i): 
     for j in range(self.numpages): 
      self.pageRects[j].set_facecolor(self.facecolor) 
     self.pageRects[i].set_facecolor(self.activecolor) 

    def forward(self, event): 
     current_i = int(self.val) 
     i = current_i+1 
     if (i < self.valmin) or (i >= self.valmax): 
      return 
     self.set_val(i) 
     self._colorize(i) 

    def backward(self, event): 
     current_i = int(self.val) 
     i = current_i-1 
     if (i < self.valmin) or (i >= self.valmax): 
      return 
     self.set_val(i) 
     self._colorize(i) 


if __name__ == "__main__": 
    import numpy as np 
    from matplotlib import pyplot as plt 


    num_pages = 23 
    data = np.random.rand(9, 9, num_pages) 

    fig, ax = plt.subplots() 
    fig.subplots_adjust(bottom=0.18) 

    im = ax.imshow(data[:, :, 0], cmap='viridis', interpolation='nearest') 

    ax_slider = fig.add_axes([0.1, 0.05, 0.8, 0.04]) 
    slider = PageSlider(ax_slider, 'Page', num_pages, activecolor="orange") 

    def update(val): 
     i = int(slider.val) 
     im.set_data(data[:,:,i]) 

    slider.on_changed(update) 

    plt.show() 

enter image description here