在使用ipywidgets为一个图调用多个交互式函数时遇到了困难



我希望有一个主图像,我可以在上面绘制螺旋、椭圆等,变量可以改变强加图形的形状。主图像还需要具有对比度变量。

我的代码当前如下所示;



###############################################BASIC FIGURE PLOT####################################
plt.figure(figsize=(24,24))
@interact
def spiral(Spiral=False,n=2000,x1=50,y1=50,z1=50,k1=300):
if Spiral == False:
x = 0;
y = 0;
plt.scatter(x,y,s = 3, c = 'black');
else:
angle = np.linspace(x1,y1*1*np.pi, n)
radius = np.linspace(z1,k1,n)
x = radius * np.cos(angle) + 150
y = radius * np.sin(angle) + 150
plt.scatter(x,y,s = 3, c = 'black');
@interact        
def contrast(vuc=(0.2,1,0.01),vlc=(0.1,1,0.01)):  
vu = np.quantile(qphi, vuc);
vl = np.quantile(qphi, vlc);
print("upper =",vu, " lower=",vl);

plt.imshow(qphi, origin='lower',vmin=vl,vmax=vu);
plt.show() 

这产生了两个情节;此处可见一张图可以创建一个螺旋,我可以自由编辑,另一张图是具有可变对比度的主图像。

如能就如何将这两个地块结合起来提出任何建议,我们将不胜感激;非常感谢。

有几种方法可以使用ipywidgets控制matplotlib绘图。下面我已经创建了输出,我认为您正在使用每个选项寻找输出。这些方法按自然发现顺序列出,但我建议按以下顺序尝试:4, 2, 1, 3

方法1-内联后端

如果使用%matplotlib inline,则matplotlib图形将不具有交互性,并且每次时都需要重新创建整个绘图

%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from ipywidgets import interact
# load fake image data
from matplotlib import cbook
img = plt.imread(cbook.get_sample_data("grace_hopper.jpg")).mean(axis=-1)

@interact
def graph(
Spiral=True,
n=2000,
x1=50,
y1=50,
z1=50,
k1=300,
vlc=(0.1, 1, 0.01),
vuc=(0.1, 1, 0.01),
):
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,5))
if Spiral == False:
x = 0
y = 0
else:
angle = np.linspace(x1, y1 * 1 * np.pi, n)
radius = np.linspace(z1, k1, n)
x = radius * np.cos(angle) + 150
y = radius * np.sin(angle) + 150
ax1.scatter(x, y, s=3, color="k")
vu = np.quantile(img, vuc)
vl = np.quantile(img, vlc)
ax2.imshow(img, vmin=vl, vmax=vu)

方法2-交互式后端+cla

您可以使用一个交互式maptlotlib后端,以避免每次更改时都必须完全重新生成图形。要做到这一点,第一种方法是在每次使用cla方法更改滑块时简单地清除轴。

这将适用于%matplotlib notebook%matplotlib ipympl。前者将只在jupyter笔记本中工作,后者将在jupyter笔记本和juptyellab中工作。(此处为ipympl的安装信息:https://github.com/matplotlib/ipympl#installation)

%matplotlib ipympl
import matplotlib.pyplot as plt
import numpy as np
from ipywidgets import interact, interactive, interactive_output
# load fake image data
from matplotlib import cbook
img = plt.imread(cbook.get_sample_data("grace_hopper.jpg")).mean(axis=-1)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,5))

@interact
def graph(
Spiral=True,
n=2000,
x1=50,
y1=50,
z1=50,
k1=300,
vlc=(0.1, 1, 0.01),
vuc=(0.1, 1, 0.01),
):
ax1.cla()
ax2.cla()
if Spiral == False:
x = 0
y = 0
else:
angle = np.linspace(x1, y1 * 1 * np.pi, n)
radius = np.linspace(z1, k1, n)
x = radius * np.cos(angle) + 150
y = radius * np.sin(angle) + 150
ax1.scatter(x, y, s=3, color="k")
vu = np.quantile(img, vuc)
vl = np.quantile(img, vlc)
ax2.imshow(img, vmin=vl, vmax=vu)

方法3-交互式后端+set_data

当您绘制更大的数据集或绘制的某些部分需要从一个交互持续到下一个交互时,完全清除轴可能效率低下。因此,您可以使用set_dataset_offsets方法来更新已绘制的内容。

%matplotlib ipympl
import matplotlib.pyplot as plt
import numpy as np
from ipywidgets import interact, interactive, interactive_output
# load fake image data
from matplotlib import cbook
img = plt.imread(cbook.get_sample_data("grace_hopper.jpg")).mean(axis=-1)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,5))
scat = ax1.scatter([0]*2000,[0]*2000,s=3, color='k')
im = ax2.imshow(img)
out = widgets.Output()
display(out)
@interact
def graph(
Spiral=True,
n=2000,
x1=50,
y1=50,
z1=50,
k1=300,
vlc=(0.1, 1, 0.01),
vuc=(0.1, 1, 0.01),
):
if Spiral == False:
x = 0
y = 0
else:
angle = np.linspace(x1, y1 * 1 * np.pi, n)
radius = np.linspace(z1, k1, n)
x = radius * np.cos(angle) + 150
y = radius * np.sin(angle) + 150
scat.set_offsets(np.c_[x, y])
# correctly scale the x and y limits
ax1.dataLim = scat.get_datalim(ax1.transData)
ax1.autoscale_view()
vu = np.quantile(img, vuc)
vl = np.quantile(img, vlc)
im.norm.vmin = vl
im.norm.vmax = vu

方法4-mpl_交互

使用set_offsets和等效的set_data将是性能最高的解决方案,但也可能很难弄清楚如何使其工作,甚至更难记住。为了更容易,我创建了一个库(mpl交互(,它自动化了方法3的样板。

除了简单和高效之外,它的优点是您不负责更新绘图,只负责返回正确的值。这还有一个附带的好处,现在像spiral这样的函数可以在代码的其他部分中使用,因为它们只是返回值,而不是处理绘图。

另一个优点是,mpl交互还可以创建matplotlib小部件,因此这是唯一一种在笔记本电脑之外也能工作的方法。

%matplotlib ipympl
import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np
import mpl_interactions.ipyplot as iplt
img = plt.imread(cbook.get_sample_data("grace_hopper.jpg")).mean(axis=-1)
# define the functions to be plotted
def spiral(Spiral=False, n=2000, x1=50, y1=50, z1=50, k1=300):
if Spiral == False:
x = 0
y = 0
return x, y
else:
angle = np.linspace(x1, y1 * 1 * np.pi, n)
radius = np.linspace(z1, k1, n)
x = radius * np.cos(angle) + 150
y = radius * np.sin(angle) + 150
return x, y

def vmin(vuc, vlc):
return np.quantile(img, vlc)
def vmax(vlc, vuc):
return np.quantile(img, vuc)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
controls = iplt.scatter(
spiral,
Spiral={(True, False)},
n=np.arange(1800, 2200),
x1=(25, 75),
y1=(25, 75),
z1=(25, 75),
k1=(200, 400),
parametric=True,
s=3,
c="black",
ax=ax1,
)
controls = iplt.imshow(
img,
vmin=vmin,
vmax=vmax,
vuc=(0.1, 1, 1000),
vlc=(0.1, 1, 1000),
controls=controls[None],
ax=ax2,
)

相关内容

最新更新