简体   繁体   English

Matplotlib:使用图形对象初始化绘图

[英]Matplotlib: using a figure object to initialize a plot

I am building a class of plot tools for a specific experiment. 我正在为特定的实验构建一类绘图工具。 I currently have two plot methods, a static plot using imshow(), and a "movie" format also using imshow() . 我目前有两种绘图方法,一种是使用imshow()的静态绘图,另一种是使用imshow()的“movie”格式。

Both methods and any future methods, get parameters that are the same for any specific plotting method that I might write. 这两种方法和任何将来的方法都可以获得与我可能编写的任何特定绘图方法相同的参数。 I have all those parameters in a config object at the time the plot class is used. 我在使用plot类时在config对象中拥有所有这些参数。

I don't want to rewrite code in every plot method. 我不想在每个绘图方法中重写代码。 I would like to initialize an object (AxesImage I think) that will have these args set: vmin, vmax, extent_dim, Xlocs, Xlabels, Ylocs, Ylabels. 我想初始化一个对象(AxesImage,我认为)将设置这些args:vmin,vmax,extent_dim,Xlocs,Xlabels,Ylocs,Ylabels。

Then I just pass that object to various methods that do some other specific thing. 然后我将该对象传递给执行其他特定操作的各种方法。 I don't understand how to do this... 我不明白怎么做...

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)

You need to understand a bit of architecture of matplotlib first (see here for a long article by the founder and current lead developer). 您需要首先了解matplotlib的一些架构(请参阅此处以获取创始人和当前首席开发人员的长篇文章)。 At the bottom of the backend layer which deals with rendering and talking to the hardware. backend层的底部,处理渲染和与硬件交谈。 On top of that layer are artists which know how to draw them selves by tell the backend object what to do. 在该层之上是artists ,他们知道如何通过告诉backend对象做什么来绘制自己。 On top of that layer is the pyplot state machine interface which mimics MATLAB . 在该层之上是模拟MATLABpyplot 状态机接口。

Everything you see in a figure is represented internally as an Artist and artists can contain other artists. 您在图中看到的所有内容都在内部表示为Artist ,艺术家可以包含其他艺术家。 For example, the Axes object keeps track of it's children Artists which are the axes spines, tickes, labels, your lines or images etc and Axes objects are children of Figure objects. 例如, Axes对象跟踪它的子项Artists ,它们是轴刺,标记,标签,线或图像等, Axes对象是Figure对象的子对象。 When you tell a figure to draw itself (via fig.canvas.draw() ) all the children artists are drawn recursively. 当你告诉一个人物画自己时(通过fig.canvas.draw() ),所有的儿童艺术家都是递归绘制的。

One draw back of this design is that a given instantiation of an Artist can be in exactly one figure (and moving them between figures is hard) so you can't make a AxesImage object and then keep reusing it. 这个设计的一个AxesImage是, Artist的给定实例可以只是一个图形(并且在图形之间移动它们很难),因此您不能创建AxesImage对象然后继续重复使用它。

This design also separates what Artists know about. 这种设计也将Artists了解的内容分开。 Axes objects know about things like tick location and labels and the display range (which it does by knowing about Axis object, but that is getting even more into the weeds). Axes对象知道诸如刻度位置和标签之类的事情以及显示范围(通过了解Axis对象来做到这一点,但这会更多地进入杂草)。 Things like vmin and vmax are encapsulated in Normalize ( doc ) objects which the AxesImage keeps track of. vminvmax这样的东西被封装在AxesImage跟踪的Normalizedoc )对象中。 This means that you will need to separate how you deal with everything on your list. 这意味着您需要分清处理列表中所有内容的方式。

I would suggest either using a factory-like pattern here, or a curry-like pattern 我建议在这里使用类似工厂的图案,或者像咖喱一样的图案

Factory-like: 工厂类:

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)

You can wrap up a whole set of kwargs to easily re-use them as such: 您可以将一整套kwargs包装起来,以便轻松地重复使用它们:

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

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

Curry-like: 咖喱,如:

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)

If you want to be super clever, you can monkey-patch plt.imshow with your version 如果你想变得非常聪明,你可以用你的版本修补plt.imshow

plt.imshow = my_imshow

There is also the rcParams interface which will allow you to change the default values of many bits and pieces of matplotlib in a global way. 还有rcParams接口,它允许您以全局方式更改matplotlib的许多位和默认值。

And yet another way to accomplish this (through partial ) 另一种方法来实现这一目标(通过partial

To show a plot you'll want to use fig.canvas.draw() where fig is an instance of the Figure class. 要显示一个图,你需要使用fig.canvas.draw() ,其中figFigure类的一个实例。 fig.canvas.draw() is the API version of the interactive shell (read: pylab ) function draw() fig.canvas.draw()是交互式shell的API版本(读取: pylab )函数draw()

If you need to get the Axes or Figure from an AxesImage object you can call either im.get_axes() or im.get_figure() , respectively. 如果需要从AxesImage对象获取AxesFigure ,则可以分别调用im.get_axes()im.get_figure()

As far as writing "good" object-oriented code the user interface examples might be good place to start. 就编写“好的”面向对象代码而言,用户界面示例可能是开始的好地方。

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

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