Matplotlib:在创建轮廓后将轮廓绘制到轴上

时间:2018-04-19 19:35:31

标签: python matplotlib contour

我将轮廓图添加到轴上。现在我想在其他轴上绘制相同的轮廓而不重新创建轮廓(因为创建轮廓可能非常复杂)。我将函数创建的轮廓保存为CS。有没有办法在所有其他轴上重绘相同的轮廓?

import numpy as np
import matplotlib.mlab as mlab

def draw_contour():
    delta = 0.025
    x = np.arange(-3.0, 3.0, delta)
    y = np.arange(-2.0, 2.0, delta)
    X, Y = np.meshgrid(x, y)
    Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
    Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
    # difference of Gaussians
    Z = 10.0 * (Z2 - Z1)
    C = plt.contour(X, Y, Z, linewidth=2, colors='k')
    return C

fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2,2)
plt.sca(ax1)
CS = draw_contour()
plt.clabel(CS, inline=1, fontsize=10)

plt.sca(ax2)
# redraw CS

plt.sca(ax3)
# redraw CS

plt.sca(ax3)
# redraw CS

enter image description here

如果可以这样做,我怎么能为plt.pcolormesh()和plt.scatter()

做同样的事情

1 个答案:

答案 0 :(得分:1)

这是一种可行的方法。您可以将带有等值线图的Axes的内容复制到另一个Axes

import numpy as np
import matplotlib as mpl
import matplotlib.mlab as mlab

def draw_contour(ax):
    delta = 0.025
    x = np.arange(-3.0, 3.0, delta)
    y = np.arange(-2.0, 2.0, delta)
    X, Y = np.meshgrid(x, y)
    Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
    Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
    # difference of Gaussians
    Z = 10.0 * (Z2 - Z1)
    C = ax.contour(X, Y, Z, colors='k')
    return C

# dfix is a hack to fix dashing size in copied lines. May need to adjust
def copy_linecollection(x, axdst, dfix=1.5):
    ls = [(ls[0], (ls[1][0]/dfix, ls[1][1]/dfix)) if ls[0] is not None else ls for ls in x.get_linestyles()]

    axdst.add_collection(mpl.collections.LineCollection(
        [p.vertices for p in x.get_paths()],
        linewidths=x.get_linewidths(), 
        colors=x.get_colors(),
        linestyles=ls,
    ))

def copy_text(x, axdst):
    axdst.text(
        *x.get_position(), 
        s=x.get_text(),
        color=x.get_color(), 
        verticalalignment=x.get_verticalalignment(), 
        horizontalalignment=x.get_horizontalalignment(), 
        fontproperties=x.get_fontproperties(), 
        rotation=x.get_rotation(),
        clip_box=axdst.get_position(),
        clip_on=True
    )

def copy_ax(axsrc, axdst):
    for c in axsrc.get_children():
        if isinstance(c, mpl.collections.LineCollection):
            copy_linecollection(c, axdst)

        elif isinstance(c, mpl.text.Text) and c.get_text():
            copy_text(c, axdst)

subplots_kw = {
    'sharex': True, 
    'sharey': True, 
    'figsize': (10,10),
    'gridspec_kw': {
        'hspace': 0,
        'wspace': 0
    }
}
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, **subplots_kw)

CS = draw_contour(ax1)
ax1.clabel(CS, inline=1, fontsize=10)

for ax in (ax2,ax3,ax4):
    copy_ax(ax1, ax)

输出:

enter image description here

这种方法不能用于其他类型的图(或者甚至是所有contour图),但它可以推广。例如,您需要运行ax.scatter(...),然后查看ax.get_children()返回的列表的内容。然后,您需要为子列表中的所有不同类型编写copy_x函数,并更新copy_ax以合并这些新的复制函数。

修改

提出了更简单,更通用的copy_ax版本:

from copy import copy as shallowcopy

def copy_artist(x, axdst):
    xc = shallowcopy(x)
    xc.axes = None
    xc.figure = None
    xc.set_transform(axdst.transData)
    axdst.add_artist(xc)

def copy_ax(axsrc, *axdsts):
    for axdst in axdsts:
        # don't need the last 10 items (frame, spines, etc) in get_children
        for c in axsrc.get_children()[:-10]:
            copy_artist(c, axdst)

此版本的copy_ax适用于许多不同绘图功能的结果(例如plt.plot)......但遗憾的是plt.scatterplt.pcolormesh。我实际上现在不认为这个或我之前的方法可以与其中任何一个一起使用。至少作为scatter的替代方案,您可以使用plot制作散点图:

def draw_scatter(ax):
    x = np.random.uniform(-2,2,size=100)
    y = np.random.uniform(-2,2,size=100)
    return ax.plot(x,y,ls='none',marker='.')

subplots_kw = {
    'sharex': True, 
    'sharey': True, 
    'figsize': (10,10),
    'gridspec_kw': {
        'hspace': 0,
        'wspace': 0
    }
}
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, **subplots_kw)

draw_scatter(ax1)
copy_ax(ax1, ax2, ax3, ax4)

输出:

enter image description here