6

我正在为特定实验构建一类绘图工具。我目前有两种绘图方法,一个使用 imshow() 的静态绘图,以及一个也使用 imshow() 的“电影”格式。

对于我可能编写的任何特定绘图方法,方法和任何未来的方法都获得相同的参数。在使用绘图类时,我在配置对象中拥有所有这些参数。

我不想在每个绘图方法中重写代码。我想初始化一个将设置这些参数的对象(我认为是 AxesImage):vmin、vmax、extent_dim、Xlocs、Xlabels、Ylocs、Ylabels。

然后我只是将该对象传递给执行其他特定操作的各种方法。我不明白如何做到这一点...

import matplotlib.pyplot as plt

data = data_dict[type] # could be real part of a complex number, phase, or the mag...
v_min, v_max = self.get_data_type_scale(data_dict, Type)
freq = data_dict['freq']

# essentially sets the aspect of the plot since the x and y resolutions could be different   
extent_dim = self._get_extent(2)
# gets the labels for physical dimensions of the experiment
Xlocs,Xlabels,Ylocs,Ylabels = self._get_ticks(5,5,extent_dim)

# in the guts of a plot method, the basic idea is the call below.  

plt.imshow(data[0,:,:],cmap='jet',vmin=v_min,...
vmax=v_max,origin='lower', extent = extent_dim)

plt.title('Type:  %s  Freq: %.3e Hz' %(Type,data_dict['freq'][0]) )
plt.xticks(Xlocs, Xlabels)
plt.yticks(Ylocs,Ylabels)
4

2 回答 2

12

您首先需要了解一点架构matplotlib(请参阅此处查看创始人和当前首席开发人员的长文)。backend在处理渲染和与硬件对话的层的底部。在该层之上,artists它们知道如何通过告诉backend对象要做什么来自己绘制它们。在该层之上是pyplot 模仿MATLAB.

您在图中看到的所有内容都在内部表示为 an Artist,并且艺术家可以包含其他艺术家。例如,Axes对象跟踪它的子Artists节点,即轴脊、刻度、标签、您的线条或图像等,并且Axes对象是对象的子节点Figure。当您告诉一个图形自己(通过fig.canvas.draw())绘制自己时,所有儿童艺术家都会递归绘制。

这种设计的一个缺点是,一个给定的实例Artist可以恰好在一个图形中(并且在图形之间移动它们很困难),因此您不能制作一个AxesImage对象然后继续重用它。

这种设计也将所Artists知道的分开。 Axes对象知道诸如刻度位置和标签以及显示范围之类的事情(它通过了解Axis对象来做到这一点,但这会更加深入杂草)。像vmin和之类的东西vmax被封装在Normalizedoc)对象中,并被AxesImage跟踪。这意味着您需要区分如何处理列表中的所有内容。

我建议要么在这里使用类似工厂的模式,要么使用类似咖喱的模式

工厂式:

def set_up_axes(some, arguements):
    '''
    Factory to make configured axes (
    '''
    fig, ax = plt.subplots(1, 1) # or what ever layout you want
    ax.set_*(...)
    return fig, ax


my_norm = matplotlib.colors.Normalize(vmin, mmax) # or write a factory to do fancier stuff
fig, ax = set_up_axes(...)
ax.imshow(..., norm=my_norm)
fig2, ax2 = set_up_axes(...)
ax2.imshow(..., norm=mynorm)

您可以包装一整套 kwargs 以便轻松地重用它们:

my_imshow_args = {'extent':[...],
                  'interpolation':'nearest',
                  'norm': my_norm,
                   ...}

ax2.imshow(..., **my_imshow_args)

咖喱味:

def my_imshow(im, ax=None, *args, **kwargs):
    if ax is None:
        ax = plt.gca()
    # do all of your axes set up
    ax.set_xlim(..)

    # set default vmin and vmax
    # you can drop some of these conditionals if you don't want to be
    # able to explicitly override the defaults
    if 'norm' not in kwargs:
        vmin = kwargs.pop('vmin', None)
        vmax = kwargs.pop('vmax', None)
        if vmin is None:
            vmin = default_vmin # or what ever
        if vmax is None:
            vmax = default_vmax
        my_norm = matplotlib.colors.Normalize(vmin, mmax)
        kwargs['norm'] = norm

    # add a similar block for `extent` 
    # or any other kwargs you want to change the default of

    ax.figure.canvas.draw() # if you want to force a re-draw
    return ax.imshow(im, *args, **kwargs)

如果你想变得超级聪明,你可以plt.imshow用你的版本进行猴子补丁

plt.imshow = my_imshow

还有一个rcParams接口,它允许您以matplotlib全局方式更改许多位和片段的默认值。

还有另一种方法来实现这一点(通过partial

于 2013-08-18T17:55:43.263 回答
2

要显示一个绘图,您需要使用fig.canvas.draw()wherefigFigure类的一个实例。fig.canvas.draw()是交互式 shell(读取:)pylab函数的 API 版本draw()

如果您需要从对象中获取Axesor ,您可以分别调用or 。FigureAxesImageim.get_axes()im.get_figure()

就编写“好的”面向对象代码而言,用户界面示例可能是一个很好的起点。

于 2013-08-18T00:30:52.600 回答