如何在Matplotlib中缩放图像的一部分并将其插入到同一图中

69
我想放大数据/图像的一部分并将其绘制在同一图中。它看起来像这个图。

zoomed plot

请问是否有可能在同一图中插入放大后的图像部分?我认为可以使用subplot绘制另一个图形,但这会绘制两个不同的图形。我也看到可以添加patch来插入矩形/圆形,但不确定是否适用于将图像部分插入到图形中。我基本上从文本文件中加载数据,并使用下面显示的简单绘图命令绘制它。
我在matplotlib图像库中找到了一个相关的示例here,但不确定它是如何工作的。非常感谢您的帮助。
from numpy import *
import os
import matplotlib.pyplot as plt
data = loadtxt(os.getcwd()+txtfl[0], skiprows=1)
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.semilogx(data[:,1],data[:,2])
plt.show()

你已经找到了与你所需相似的代码,做研究很棒。现在,那段代码中哪一部分需要解释?我们如何帮助你学会钓鱼而不是直接给你鱼呢?(作为一个通用工具,我发现注释掉一些语句并修改它们的数字是一种粗糙但有效的方法来查找语句的作用...) - unutbu
感谢您的回复。我看了那些代码,但无法理解。我是一个基本的 matplotlib 用户,并开始学习 matplotlib。我尝试应用这些代码,但对我来说并没有起作用。例如,我尝试分配 ax2 = ax1.axes([0.2amin(data[:,1], 0.5amax(data[:,1]),0.5amin(data[:,2]),0.8amax(data[:,2])]),然后尝试绘图:ax2.semilogx(data[3:8,1],data[3:8,2])。我以这种方式得到错误。不确定如何分配轴参数,然后绘制它。 - Elect28
4个回答

44

最简单的方法是结合使用“zoomed_inset_axes”和“mark_inset”,其中它们的描述和相关示例可以在此处找到:AxesGrid 工具包概述

enter image description here

import matplotlib.pyplot as plt

from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes
from mpl_toolkits.axes_grid1.inset_locator import mark_inset

import numpy as np

def get_demo_image():
    from matplotlib.cbook import get_sample_data
    import numpy as np
    f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False)
    z = np.load(f)
    # z is a numpy array of 15x15
    return z, (-3,4,-4,3)

fig, ax = plt.subplots(figsize=[5,4])

# prepare the demo image
Z, extent = get_demo_image()
Z2 = np.zeros([150, 150], dtype="d")
ny, nx = Z.shape
Z2[30:30+ny, 30:30+nx] = Z

# extent = [-3, 4, -4, 3]
ax.imshow(Z2, extent=extent, interpolation="nearest",
          origin="lower")

axins = zoomed_inset_axes(ax, 6, loc=1) # zoom = 6
axins.imshow(Z2, extent=extent, interpolation="nearest",
             origin="lower")

# sub region of the original image
x1, x2, y1, y2 = -1.5, -0.9, -2.5, -1.9
axins.set_xlim(x1, x2)
axins.set_ylim(y1, y2)

plt.xticks(visible=False)
plt.yticks(visible=False)

# draw a bbox of the region of the inset axes in the parent axes and
# connecting lines between the bbox and the inset axes area
mark_inset(ax, axins, loc1=2, loc2=4, fc="none", ec="0.5")

plt.draw()
plt.show()

4
只想更新matplotlib 3.xx的链接(该答案中的链接为1.xx)https://matplotlib.org/stable/gallery/axes_grid1/inset_locator_demo2.html#sphx-glr-gallery-axes-grid1-inset-locator-demo2-py - Cuong

43

玩转可运行代码是学习Python最快的方式之一。

所以,让我们从matplotlib示例库中的代码开始。

根据代码中的注释,该代码似乎分为4个主要部分。第一部分生成一些数据,第二部分生成主要图形,第三和第四部分创建插入轴。

我们知道如何生成数据和绘制主要图形,因此让我们专注于第三部分:

a = axes([.65, .6, .2, .2], axisbg='y')
n, bins, patches = hist(s, 400, normed=1)
title('Probability')
setp(a, xticks=[], yticks=[])

将示例代码复制到一个新文件中,命名为 test.py

如果我们将 .65 改为 .3 会发生什么?

a = axes([.35, .6, .2, .2], axisbg='y')

运行脚本:

python test.py

你会发现“Probability”插图被移到了左边。因此,axes函数控制插图的位置。如果你再试一下不同的数字,你会发现(.35, .6)是插图左下角的位置,(.2, .2)是插图的宽度和高度。这些数字的范围从0到1,(0,0)是图形左下角的位置。
好的,现在我们继续。下一行是:
n, bins, patches = hist(s, 400, normed=1)

你可能会认出这是用于绘制直方图的matplotlib命令, 如果不知道,将数字400更改为例如10,将生成一个更加粗糙的直方图图像,因此通过调整数字,您很快就会发现此行与插图内部的图像有关。
在这里,您需要调用semilogx(data[3:8,1],data[3:8,2])
显然,title('Probability')会在插图上方生成文本。
最后,我们来到setp(a, xticks=[], yticks=[])。没有可以操作的数字,所以如果我们在行首添加一个#注释掉整行,会发生什么:
# setp(a, xticks=[], yticks=[])

重新运行脚本。哦!现在插入轴上有很多刻度线和刻度标签。好的。所以现在我们知道setp(a, xticks=[], yticks=[])会从轴a中删除刻度线和标签。
理论上,您已经拥有足够的信息来将此代码应用于您的问题。但是还有一个可能的绊脚石:Matplotlib示例使用from pylab import *,而您使用import matplotlib.pyplot as pltMatplotlib FAQ说当编写脚本时,推荐使用import matplotlib.pyplot as plt来使用Matplotlib,而from pylab import *用于交互式会话。因此,您正在正确地使用它(虽然我建议使用import numpy as np代替from numpy import *)。
那么,我们如何将Matplotlib示例转换为使用import matplotlib.pyplot as plt运行呢?
做这个转换需要一些matplotlib的经验。通常,您只需在像axes和setp这样的裸名称前面添加plt.,但有时函数来自numpy,有时调用应该来自于一个轴对象,而不是模块plt。知道所有这些函数来自哪里需要经验。在Google中搜索函数名称以及"matplotlib"可以帮助。阅读示例代码可以建立经验,但没有简单的捷径。
因此,转换后的代码如下:
ax2 = plt.axes([.65, .6, .2, .2], axisbg='y')
ax2.semilogx(t[3:8],s[3:8])
plt.setp(ax2, xticks=[], yticks=[])

你可以像这样在你的代码中使用它:

from numpy import *
import os
import matplotlib.pyplot as plt
data = loadtxt(os.getcwd()+txtfl[0], skiprows=1)
fig1 = plt.figure()
ax1 = fig1.add_subplot(111)
ax1.semilogx(data[:,1],data[:,2])

ax2 = plt.axes([.65, .6, .2, .2], axisbg='y')
ax2.semilogx(data[3:8,1],data[3:8,2])
plt.setp(ax2, xticks=[], yticks=[])

plt.show()

谢谢,这回答了我的问题。不知道为什么ax2 = fig1.axes([.65. 0.6, 0.2, 0.2], axisbg = 'y') 不起作用。例如,如果我想绘制两个图形,并且我想在两个图形中添加插入图。如果我使用ax3 = fig2.add_subplot(111),然后ax3.semilogx(x,y),然后ax4 = plt.axes([.2, 0.5, 0.2, 0.2], axisbg = 'y') 和 ax4.semilogx(x1,y1)。它会将两个插入图添加到第二个图中。 - Elect28
plt.axes 创建一个新的坐标轴。它将该轴添加到当前图形中。(将图形视为整个窗口区域,将坐标轴视为仅绘制图形的部分。)fig1.axes 返回包含在 fig1 中的坐标轴列表。我很惊讶 fig1.axes([...]) 没有给您带来 TypeError。所以首先将 fig1.axes 更改为 plt.axes。接下来,请注意调用 fig2 = plt.figure() 会使 fig2 成为活动图形。因此,任何随后调用的 plt.axes 都将将插入轴添加到 fig2 中。plt.figureplt.axes 调用的顺序很重要。 - unutbu
1
谢谢。在 ax2.semilogx([...]) 后面加上 fig2 = plt.figure() 和 ax3 = fig2.add_subplot(111) 就可以了。 - Elect28

28

20

使用matplotlib放大图形的基本步骤

import numpy as np
from matplotlib import pyplot as plt

# Generate the main data
X = np.linspace(-6, 6, 1024)
Y = np.sinc(X)

# Generate data for the zoomed portion
X_detail = np.linspace(-3, 3, 1024)
Y_detail = np.sinc(X_detail)

# plot the main figure
plt.plot(X, Y, c = 'k')  

 # location for the zoomed portion 
sub_axes = plt.axes([.6, .6, .25, .25]) 

# plot the zoomed portion
sub_axes.plot(X_detail, Y_detail, c = 'k') 

# insert the zoomed figure
# plt.setp(sub_axes)

plt.show()

在此输入图片描述


1
非常清晰的解释 - ABIM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接