【问题标题】:How should I pass a matplotlib object through a function; as Axis, Axes or Figure?我应该如何通过函数传递 matplotlib 对象;作为轴,轴或图形?
【发布时间】:2014-07-07 12:05:21
【问题描述】:

如果这有点冗长,请提前抱歉,但如果我把它删掉太多,问题就消失了。我正在尝试在 pandas 和 matplotlib 之上制作一个模块,这将使我能够制作类似于 scatter_matrix 的轮廓图和轮廓矩阵。我很确定我的问题归结为我需要从 Profile() 返回什么对象,以便我可以在 Profile_Matrix() 中处理 Axes 操作。那么问题是从 Profile_Matrix() 中返回什么,以便我可以编辑子图。

我的模块(ProfileModule.py)从https://github.com/pydata/pandas/blob/master/pandas/tools/plotting.py借了很多东西,看起来像:

import pandas as pd
from pandas import Series, DataFrame
import numpy as np
import matplotlib.pyplot as plt

def Profile(x,y,nbins,xmin,xmax):
    df = DataFrame({'x' : x , 'y' : y})

    binedges = xmin + ((xmax-xmin)/nbins) * np.arange(nbins+1)
    df['bin'] = np.digitize(df['x'],binedges)

    bincenters = xmin + ((xmax-xmin)/nbins)*np.arange(nbins) + ((xmax-xmin)/(2*nbins))
    ProfileFrame = DataFrame({'bincenters' : bincenters, 'N' : df['bin'].value_counts(sort=False)},index=range(1,nbins+1))

    bins = ProfileFrame.index.values
    for bin in bins:
        ProfileFrame.ix[bin,'ymean'] = df.ix[df['bin']==bin,'y'].mean()
        ProfileFrame.ix[bin,'yStandDev'] = df.ix[df['bin']==bin,'y'].std()
        ProfileFrame.ix[bin,'yMeanError'] = ProfileFrame.ix[bin,'yStandDev'] / np.sqrt(ProfileFrame.ix[bin,'N'])

    fig = plt.figure(); 
    ax = ProfilePlot.add_subplot(1, 1, 1)
    plt.errorbar(ProfileFrame['bincenters'], ProfileFrame['ymean'], yerr=ProfileFrame['yMeanError'], xerr=(xmax-xmin)/(2*nbins), fmt=None)

    return ax
    #or should I "return fig"


def Profile_Matrix(frame):

    import pandas.core.common as com
    import pandas.tools.plotting as plots
    from pandas.compat import lrange
    from matplotlib.artist import setp

    range_padding=0.05


    df = frame._get_numeric_data()
    n = df.columns.size

    fig, axes = plots._subplots(nrows=n, ncols=n, squeeze=False)

    # no gaps between subplots
    fig.subplots_adjust(wspace=0, hspace=0)

    mask = com.notnull(df)

    boundaries_list = []
    for a in df.columns:
        values = df[a].values[mask[a].values]
        rmin_, rmax_ = np.min(values), np.max(values)
        rdelta_ext = (rmax_ - rmin_) * range_padding / 2.
        boundaries_list.append((rmin_ - rdelta_ext, rmax_+ rdelta_ext))

    for i, a in zip(lrange(n), df.columns):
        for j, b in zip(lrange(n), df.columns):
            ax = axes[i, j]
            common = (mask[a] & mask[b]).values
            nbins = 100
            (xmin,xmax) = boundaries_list[i]

            ax=Profile(df[b][common],df[a][common],nbins,xmin,xmax)
            #Profile(df[b][common].values,df[a][common].values,nbins,xmin,xmax)

            ax.set_xlabel('')
            ax.set_ylabel('')

            plots._label_axis(ax, kind='x', label=b, position='bottom', rotate=True)
            plots._label_axis(ax, kind='y', label=a, position='left')

            if j!= 0:
                ax.yaxis.set_visible(False)
            if i != n-1:
                ax.xaxis.set_visible(False)

    for ax in axes.flat:
        setp(ax.get_xticklabels(), fontsize=8)
        setp(ax.get_yticklabels(), fontsize=8)

    return axes

这将运行类似:

import pandas as pd
from pandas import Series, DataFrame
import numpy as np
import matplotlib.pyplot as plt

import ProfileModule as pm

x = np.random.uniform(0, 100, size=1000)
y = x *x  +  50*x*np.random.randn(1000)
z = x *y  +  50*y*np.random.randn(1000)

nbins = 25
xmax = 100
xmin = 0

ProfilePlot = pm.Profile(x,y,nbins,xmin,xmax)
plt.title("Look this works!")

#This does not work as expected
frame = DataFrame({'z' : z,'x' : x , 'y' : y})
ProfileMatrix = pm.Profile_Matrix(frame)
plt.show()

这有望产生一个简单的剖面图和一个 3x3 剖面矩阵,但它不会。我尝试了各种不同的方法来让它发挥作用,但我认为不值得一一解释。

我应该提到我在 Windows 7 上使用 Enthought Canopy Express。很抱歉发了这么长的帖子,再次感谢您对代码的任何帮助。这是我使用 Python 的第一周。

【问题讨论】:

  • 我认为您应该返回整个图形fig,您始终可以使用fig.axes 访问轴,并且无论如何您都需要它,以防您想调整整个图形或其他东西的大小。
  • 这本可以在不丢失问题的情况下进一步减少。去掉任何涉及熊猫的东西,使用合成数据。

标签: python matplotlib pandas histogram canopy


【解决方案1】:

您应该传递Axes 对象并将您的函数分解为一次在单个轴上操作。你很亲密,但只是改变

import numpy as np
import matplotlib.pyplot as plt

def _profile(ax, x, y):
    ln, = ax.plot(x, y)
    # return the Artist created
    return ln


def profile_matrix(n, m):
    fig, ax_array = plt.subplots(n, m, sharex=True, sharey=True)
    for ax in np.ravel(ax_array):
        _profile(ax, np.arange(50), np.random.rand(50))

profile_matrix(3, 3)

【讨论】:

  • 谢谢,但我仍然需要“fig = plt.figure(); ax = fig.add_subplot(1, 1, 1)”,它不能解决我在 Profile_Matrix 中遇到的问题。它给出了图中未分开的 9 个图。我认为这是因为我无法通过 ax 将 Profile() 与 axes[i,j] 相关联。注释掉的方式也不起作用。
  • 你不需要这些行。请编辑您的问题以删除所有 pandas 调用并传递 np.random.rand(50) 作为您的数据。这段代码太杂乱了,无法清楚地看到发生了什么。
猜你喜欢
  • 1970-01-01
  • 2022-08-17
  • 1970-01-01
  • 1970-01-01
  • 2016-10-26
  • 2021-08-26
  • 1970-01-01
  • 2013-01-28
  • 2021-09-17
相关资源
最近更新 更多