【问题标题】:Hierarchy in matplotlibmatplotlib 中的层次结构
【发布时间】:2015-06-10 11:40:41
【问题描述】:

根据this 的文章,matplotlib 中的所有内容都是按层次结构组织的。层次结构的顶部是matplotlib“状态机环境”,它由matplotlib.pyplot 模块提供。在此级别,使用简单函数将绘图元素(线条、图像、文本等)添加到当前图形中的当前轴。层次结构的下一层是面向对象接口的第一层,其中pyplot 仅用于图形创建等少数功能,用户显式创建并跟踪图形和轴对象。在这一层,用户使用pyplot创建图形,通过这些图形,可以创建一个或多个轴对象。这些坐标区对象随后用于大多数绘图操作。 还有其他术语,如 Figure、Axes、Axis、Artist(在提到的页面上有一张很好的图片解释了所有这些)。总结:

  1. 一切都属于matplotlib.pyplot模块
  2. Figure - 跟踪所有子 Axes,少量“特殊”艺术家(标题、人物图例等)
  3. 轴 - 具有数据空间的图像区域 - 属于图
  4. 轴 - 标记刻度的字符串(x、y、z 坐标等) - 属于轴
  5. 艺术家 - 您可以在图形上看到的所有内容(甚至是图形、轴和轴对象)- 属于图形

创建新图形最简单的方法是使用 pyplot:

fig = plt.figure()  # an empty figure with no axes
fig, ax_lst = plt.subplots(2, 2)  # a figure with a 2x2 grid of Axes

我经常看到这两种方法可以互换使用,我希望它们基本上是等价的。但是我无法使用fig, ax = plt.subplots() 获得与使用fig = plt.figure()ax = fig.add_subplot(111, projection='3d') 相同的结果

这是我的实验,plt.figure()

In [1]: from mpl_toolkits.mplot3d import Axes3D

In [2]: import matplotlib.pyplot as plt

In [3]: fig = plt.figure()

In [4]: ax = fig.add_subplot(111, projection='3d')

In [5]: fig
Out[5]: <matplotlib.figure.Figure at 0x7f8377ca0610>

In [6]: ax
Out[6]: <matplotlib.axes._subplots.Axes3DSubplot at 0x7f8377bfb310>

In [7]: 

这是我的实验,plt.subplots()

In [1]: from mpl_toolkits.mplot3d import Axes3D

In [2]: import matplotlib.pyplot as plt

In [3]: fig, ax = plt.subplots()

In [4]: fig
Out[4]: <matplotlib.figure.Figure at 0x7f3dcf96e710>

In [5]: ax
Out[5]: <matplotlib.axes._subplots.AxesSubplot at 0x7f3dced564d0>

In [6]: 

如您所见,第一个创建matplotlib.axes._subplots.Axes3DSubplot 对象,而第二个创建matplotlib.axes._subplots.AxesSubplot 对象。我一直在通过help(plt.subplots) 搜索projection 关键字,但我没有找到任何东西。所以我尝试对plt.subplots 使用与fig.add_subplot 相同的参数,但出现以下错误:

In [7]: fig, ax = plt.subplots(111, projection='3d')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-7-a905adad48f5> in <module>()
----> 1 fig, ax = plt.subplots(111, projection='3d')

/usr/lib/python2.7/dist-packages/matplotlib/pyplot.pyc in subplots(nrows, ncols, sharex, sharey, squeeze, subplot_kw, gridspec_kw, **fig_kw)
   1076         gridspec_kw = {}
   1077 
-> 1078     fig = figure(**fig_kw)
   1079     gs = GridSpec(nrows, ncols, **gridspec_kw)
   1080 

/usr/lib/python2.7/dist-packages/matplotlib/pyplot.pyc in figure(num, figsize, dpi, facecolor, edgecolor, frameon, FigureClass, **kwargs)
    433                                         frameon=frameon,
    434                                         FigureClass=FigureClass,
--> 435                                         **kwargs)
    436 
    437         if figLabel:

/usr/lib/python2.7/dist-packages/matplotlib/backends/backend_tkagg.pyc in new_figure_manager(num, *args, **kwargs)
     78     """
     79     FigureClass = kwargs.pop('FigureClass', Figure)
---> 80     figure = FigureClass(*args, **kwargs)
     81     return new_figure_manager_given_figure(num, figure)
     82 

TypeError: __init__() got an unexpected keyword argument 'projection'

问题:

fig, ax = plt.subplots()fig = plt.figure(); ax = fig.add_subplot(111, projection='3d') 是否等效,如果是,我如何在示例中使用 fig, ax = plt.subplots()

在提到的页面上还有以下代码:

#!/bin/env python

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 2, 100)

# The first call to plt.plot will automatically create the necessary figure and axes to achieve the desired plot.
plt.plot(x, x, label='linear')

# Subsequent calls to plt.plot re-use the current axes and each add another line.
plt.plot(x, x**2, label='quadratic')
plt.plot(x, x**3, label='cubic')

# Setting the title, legend, and axis labels also automatically use the current axes and set the title, create the legend, and label the axis respectively.
plt.xlabel('x label')
plt.ylabel('y label')

plt.title("Simple Plot")

plt.legend()

plt.show()

如您所见,fig = plt.figure()fig, ax_lst = plt.subplots(2, 2) 都没有这样的功能

问题:

这个例子中的层次结构是如何维护的,Figure是默认创建的还是怎么回事?

【问题讨论】:

    标签: python matplotlib plot


    【解决方案1】:

    问题 1

    我认为您已经为自己证明了这些命令并不完全等效,只是希望对此有所保证。

    要做你想做的事 - 你可以通过设置子情节参数字典并将它们传递给例如,将 projection 传递给“在幕后”使用的 add_subplot() 调用

    from mpl_toolkits.mplot3d import Axes3D
    import matplotlib.pyplot as plt
    subplot_args = {'projection':'3d'}
    fig, ax = plt.subplots(subplot_kw=subplot_args)
    

    命名参数subplot_kw的使用描述为in the docs here

    问题 2

    图形轴等都是由以plt.plot 开头的第一行“在幕后”创建的。 pyplot 模块正在维护状态并重用相同的图形实例和轴实例,直到您调用 plt.show()

    注意 - 就目前而言,您没有这些实例的句柄。如果你想,你总是可以得到一个句柄,例如通过调用

    fig = plt.gcf()
    

    ax = plt.gca()
    

    其中gcf() and gca() 分别获取当前图形和获取当前坐标轴。这是基于 matplotlib 最初所基于的 matlab 功能建模的。

    如果您真的很想看看自动创建是如何完成的 - 它都是开源的。您可以看到对plot() 的调用通过在the code here 中对gca() 的调用创建了一个Axes 实例。这又是calls gcf()looks for a FigureManager(实际上是保持状态)。如果存在,它返回它正在管理的图形,否则它使用plt.figure() 创建一个新图形。同样,这个过程在某种程度上继承自 matlab,在任何绘图操作之前,初始调用通常是 figure


    附录

    我认为您可能想要了解的是如何使用 matplotlib.pyplot 函数(如 plt.plot() 等)让您访问文档描述的层次结构.答案是,如果你想要真正细粒度的控制,它有时不会。这就是为什么人们使用

    fig, ax = plt.subplots()
    

    pattern 或类似的,以便它们直接具有图形和轴对象的句柄,并且可以随意操作它们。

    【讨论】:

    • 谢谢您的回复,请问您是否对matplotlib如此熟悉或者您使用了一些代码(跟踪)检查工具来回答这个问题?
    • 嗨 - 我只是(相当)熟悉代码库。我发现文档在某些地方可能有点难以理解,所以经常发现自己深入研究我不理解的代码。 pyplot 维护 Figure 实例的模型在我看来是不寻常的 - 正如我所说,我认为这是 Matlab 遗产的遗产。
    猜你喜欢
    • 2012-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多