i am enfacing a problem i do not know how to solve properly.
I am trying to create a set of subplots in a window that are capable of moving on click. The functionality should work like this: 1 major plot is appearing in the “center” of the canvas. 3 minor plots are appearing on the side. When clicking on the minor windows, the plot changes its position with the big one and becomes large.
A few problems i encountered on the way:
How can i identify which of the plots is the big plot right now? (figure.get_axes() apparently always returns the axes in the order they were created)
Can i adjust the gridspec of an axis after creating it?
Is there a way to plot an existing axis in a new subplot with a specified gridspec?
(I dont know if i can just use set_position for an axis since the size of the different axes in the differenz subplots varies)
Heres my code, feel free to test and play around.
Thank you very much
from PySide6 import QtWidgets
import sys
import traceback
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg
import matplotlib.pyplot as plt
import matplotlib.figure
import matplotlib.gridspec as gridspec
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setFixedSize(650, 650)
self.figure = matplotlib.figure.Figure(figsize=(5,5))
self.canvas = FigureCanvasQTAgg(self.figure)
self.setCentralWidget(self.canvas)
ax1 = self.figure.add_subplot(1, 2, 1)
ax2 = self.figure.add_subplot(3, 4, 4)
ax3 = self.figure.add_subplot(3, 4, 8)
ax4 = self.figure.add_subplot(3, 4, 12)
ax1.plot([1, 2, 3], [1, 2, 3], color='r')
ax1.set_title('1')
ax2.plot([1, 2, 3], [1, 2, 3], color='g')
ax2.set_title('2')
ax3.plot([1, 2, 3], [1, 2, 3], color='y')
ax3.set_title('3')
ax4.plot([1, 2, 3], [1, 2, 3], color='b')
ax4.set_title('4')
plt.tight_layout()
cid = self.figure.canvas.mpl_connect('button_press_event', self.onclick)
def onclick(self, event):
for ax in self.figure.get_axes():
ax_i = ax.get_gridspec().get_geometry()[0]
ax_j = ax.get_gridspec().get_geometry()[1]
ax_k = ax.get_subplotspec().num1 + 1
if ax_i == 1 and ax_j == 2 and ax_k == 1:
big_ax_i = ax_i
big_ax_j = ax_j
big_ax_k = ax_k
big_ax = ax
gs = gridspec.GridSpec(2,2)
for ax in self.figure.get_axes():
if ax == event.inaxes:
if not ax == big_ax:
title_big_ax = big_ax.get_title()
lines_big_ax = big_ax.get_lines()
xdata_big_ax = [line.get_xdata() for line in lines_big_ax]
ydata_big_ax = [line.get_ydata() for line in lines_big_ax]
color_big_ax = [line.get_color() for line in lines_big_ax]
big_ax.remove()
title_ax = ax.get_title()
lines_ax = ax.get_lines()
xdata_ax = [line.get_xdata() for line in lines_ax]
ydata_ax = [line.get_ydata() for line in lines_ax]
color_ax = [line.get_color() for line in lines_ax]
ax_i = ax.get_gridspec().get_geometry()[0]
ax_j = ax.get_gridspec().get_geometry()[1]
ax_k = ax.get_subplotspec().num1 + 1
ax.remove()
new_big = self.figure.add_subplot(big_ax_i, big_ax_j, big_ax_k)
new_big.set_title(title_ax)
for x, y, c in zip(xdata_ax, ydata_ax, color_ax):
new_big.plot(x, y, color=c)
new_ax = self.figure.add_subplot(ax_i, ax_j, ax_k)
new_ax.set_title(title_big_ax)
for x, y, c in zip(xdata_big_ax, ydata_big_ax, color_big_ax):
new_ax.plot(x, y, color=c)
self.canvas.draw()
def excepthook(exc_type, exc_value, exc_tb):
tb = "".join(traceback.format_exception(exc_type, exc_value, exc_tb))
print("error caught!:")
print("error message:n", tb)
QtWidgets.QApplication.quit()
sys.excepthook = excepthook
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
ret = app.exec()
sys.exit(ret)
Right now i have this solution, but it destroys the axes, collects its lines and creates new subplots instead. If i bring this functionality from the demo to the program, plots can get more elaborate and then collecting lines might not be the best idea. Keeping the axis and changing its position with respect to the gridspec seems better to me.