本文介绍了在 Matplotlib 中交互式调整图形大小并切换绘图可见性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想做的是:

  • 以两个子图开始图(一个叠在一起)
  • 按键盘上的"x"以:调整图形的大小,并在右侧显示第三幅图.
  • 再次按"x"键:将图形调整为原始大小,并隐藏第三幅图(没有空间留出第三幅图).

通过下面的示例代码,我得到了这个(matplotlib 3.1.2,MINGW64 中的 Python3,Windows 10):

With the example code below, I got to this (matplotlib 3.1.2, Python3 in MINGW64, Windows 10):

如gif所示-即使在开始状态下,右侧也有一些空白(因为除了定义网格外,我不知道如何解决此问题的更好方法).然后,当图形窗口扩展/调整大小时,它不会精确地"调整大小,因此适合第三幅图.

As it is shown on the gif - even in the starting state, there is some empty space on the right (since I didn't know any better way how to solve this, other than define a grid). Then, when the figure window extends/resizes, it is not "exactly" resized so it fits the third plot.

我怎样才能实现第三个图的切换,这样当它被隐藏时,右边就没有多余的空间 - 当它显示时,图正好延伸到第三个图适合(包括边距)(现有/初始的两个图的大小都不会改变)?

How can I achieve a toggling of this third plot, such that when it is hidden, there is no extra empty space on the right - and when it is shown, the figure extends exactly so the third plot fits (including margins) ( and the existing/initial two plots do not change in size)?

代码:

#!/usr/bin/env python3

import matplotlib
print("matplotlib.__version__ {}".format(matplotlib.__version__))
import matplotlib.pyplot as plt
import numpy as np

default_size_inch = (9, 6)
showThird = False

def onpress(event):
  global fig, ax1, ax2, ax3, showThird
  if event.key == 'x':
    showThird = not showThird
    if showThird:
      fig.set_size_inches(default_size_inch[0]+3, default_size_inch[1], forward=True)
      plt.subplots_adjust(right=0.85) # leave a bit of space on the right
      ax3.set_visible(True)
      ax3.set_axis_on()
    else:
      fig.set_size_inches(default_size_inch[0], default_size_inch[1], forward=True)
      plt.subplots_adjust(right=0.9) # default
      ax3.set_visible(False)
      ax3.set_axis_off()
    fig.canvas.draw()


def main():
  global fig, ax1, ax2, ax3
  xdata = np.arange(0, 101, 1) # 0 to 100, both included
  ydata1 = np.sin(0.01*xdata*np.pi/2)
  ydata2 = 10*np.sin(0.01*xdata*np.pi/4)

  fig = plt.figure(figsize=default_size_inch, dpi=120)
  ax1 = plt.subplot2grid((3,3), (0,0), colspan=2, rowspan=2)
  ax2 = plt.subplot2grid((3,3), (2,0), colspan=2, sharex=ax1)
  ax3 = plt.subplot2grid((3,3), (0,2), rowspan=3)

  ax3.set_visible(False)
  ax3.set_axis_off()

  ax1.plot(xdata, ydata1, color="Red")
  ax2.plot(xdata, ydata2, color="Khaki")

  fig.canvas.mpl_connect('key_press_event', lambda event: onpress(event))
  plt.show()


# ENTRY POINT
if __name__ == '__main__':
  main()

推荐答案

如前所述,您实际上有两个选择;使用单个gridspec,或者对每个状态使用两个.让我们使用单个gridspec查看第一个选项.为此,您将首先以英寸为单位定义所有需要的参数,然后为两个所需状态中的每一个计算子图参数(以相对单位表示).

As commented, you essentially have two options; use a single gridspec, or use two, one for each state. Let's look at the first option, using a single gridspec. To this end you would first define all needed parameters in inches, then calculate the subplot parameters (in relative units) for each of the two desired states.

当按下 时,您将通过 .update() 更新 gridspec 参数来在状态之间切换.

When pressing you would toggle between the states by updating the gridspec parameters via .update().

import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec

w,h = plt.rcParams["figure.figsize"]
# Define dimensions in inches (could also just put numbers here)
left = plt.rcParams["figure.subplot.left"] * w
right = (1 - plt.rcParams["figure.subplot.right"]) * w
wspace = plt.rcParams["figure.subplot.wspace"] * w

figw1, figh1 = (7,5)
ax1width = figw1 - left - right
ax2width = 3.5

#calculate remaining free parameter, the figure width of the enlarged figure
figh2 = figh1
figw2 = left + ax1width + wspace + ax2width + right

#calculate subplot parameters for both cases
subplotpars1 = dict(left = left/figw1, right=(left + ax1width + wspace + ax2width)/figw1,
                    wspace=wspace/(ax1width+ax2width), )
subplotpars2 = dict(left = left/figw2, right=(left + ax1width + wspace + ax2width)/figw2,
                    wspace=wspace/(ax1width+ax2width), )

# create GridSpec
gs = GridSpec(2,2, width_ratios=(ax1width, ax2width), **subplotpars1)
# Create figure with 3 axes
fig = plt.figure(figsize=(figw1, figh1))
ax1 = fig.add_subplot(gs[0,0])
ax2 = fig.add_subplot(gs[1,0])
ax3 = fig.add_subplot(gs[:,1])

ax1.plot([2,4], color="C0")
ax2.plot([0,11], color="C1")
ax3.plot([5,15], color="C2")


# Updating machinery
current_state = [0]
subplotspars = [subplotpars1, subplotpars2]
figsizes = [(figw1, figh1), (figw2, figh2)]

def key_press(evt):
    if evt.key == "x":
        current_state[0] = (current_state[0] + 1) % 2
        gs.update(**subplotspars[current_state[0]])
        fig.set_size_inches(figsizes[current_state[0]], forward=True)
        fig.canvas.draw_idle()

fig.canvas.mpl_connect("key_press_event", key_press)


plt.show()

这篇关于在 Matplotlib 中交互式调整图形大小并切换绘图可见性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-29 04:09