I would like to show a context menu on the position of mouse click and then create a new line on that position in the graph.
For that I need both the PyQt position and the graph data position. I thought that I could use the matplotlib transformation functions, but somehow when clicking the lower left and upper right corners of the graph I get in the print values [-0.34, 30.73], [3.02, -1.49] instead of ~[-0.3, -0.9], ~[4.3, 42].
Can anyone fix the mistake I make in the code?
P.S. I know I can connect a matplotlib signal and get the correct data positions. But I would then need to transform those positions to PyQt positions in order to place the widget correctly, resulting in the same issue.
Follows a simplified code:
import sys
import matplotlib
matplotlib.use('Qt5Agg')
from PyQt5 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
super(MplCanvas, self).__init__(fig)
self._menuPoint = None
self.canvasMenu = QtWidgets.QMenu(self)
ca = QtWidgets.QAction('Add line', self)
ca.triggered.connect(self.onAddLineClicked)
self.canvasMenu.addAction(ca)
def mouseReleaseEvent(self, event):
super().mouseReleaseEvent(event)
self._menuPoint = event.pos()
print(self.axes.transData.inverted().transform((self._menuPoint.x(), self._menuPoint.y())))
if event.button() == QtCore.Qt.RightButton:
self.canvasMenu.exec_(self.mapToGlobal(self._menuPoint))
def onAddLineClicked(self):
pass
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
sc = MplCanvas(self)
sc.axes.plot([0, 1, 2, 3, 4], [10, 1, 20, 3, 40])
self.setCentralWidget(sc)
self.show()
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
app.exec_()
Thanks.
The coordinates returned by QMouseEvent.pos() are comprised between [0 – widget width] and [0 - widget height], while the figure coordinates are between [0 – 1]. You therefore need to divide the mouse pos() by the widget width and height. There is also the subtlety that the Qt coordinates are from the upper left corner, while the matplotlib coordinates are from the lower left corner.
Once you have your position in figure coordinates, it is relatively straightforward to convert them in data coordinates. You could also convert them to Axes coordinates to test whether the click was inside the axes or not.
def mouseReleaseEvent(self, event):
super().mouseReleaseEvent(event)
self._menuPoint = event.pos()
w, h = self.get_width_height()
xfig = event.x()/w
yfig = 1-(event.y()/h) # necessary because Qt coordinates are from upper left, while matplotlib's are from
# lower left
x, y = self.axes.transData.inverted().transform(self.fig.transFigure.transform([xfig, yfig]))
print(event.pos(), x, y)
if event.button() == QtCore.Qt.RightButton:
self.canvasMenu.exec_(self.mapToGlobal(self._menuPoint))
Related
I have some noisy data which I'm trying to fit with a gaussian. The problem is that I have to do it manually. By that, I mean I have to move the point on the curve (see figure below). When I move the point I have to update the curve so the curve it self can move.
For example on this curve if I move the upper point it changes the mu of my gaussian and if I move the point in the middle it update the sigma parameter. On this example, I've plotted the two curve in a FigureCanvas of matplotlib that I've embedded in a QMainWindow.
I've seached and found no way to do that in a matplotlib figure embedded in a PyQt widget. So, I've changed and tried to use PyQtGraph with the ROI tools but it didn't work very well.
Do you have any idea how i can achieve this? Is there a simple python library to do that? Thanks
EDIT :
Here is the code I've used to produce the image :
from PySide2 import QtCore, QtGui, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import numpy as np
class PainterCanvas(FigureCanvas):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
FigureCanvas.__init__(self, fig)
self.setParent(parent)
self._instructions = []
self.axes = self.figure.add_subplot(111)
def paintEvent(self, event):
super().paintEvent(event)
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
width, height = self.get_width_height()
for x, y, rx, ry, br_color in self._instructions:
x_pixel, y_pixel_m = self.axes.transData.transform((x, y))
# In matplotlib, 0,0 is the lower left corner,
# whereas it's usually the upper right
# for most image software, so we'll flip the y-coor
y_pixel = height - y_pixel_m
painter.setBrush(QtGui.QColor(br_color))
painter.drawEllipse( QtCore.QPoint(x_pixel, y_pixel), rx, ry)
def create_oval(self, x, y, radius_x=2, radius_y=2, brush_color="red"):
self._instructions.append([x, y, radius_x, radius_y, brush_color])
self.update()
class MyPaintWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.canvas = PainterCanvas()
self.canvas.mpl_connect("button_press_event", self._on_left_click)
x = np.arange(0, 10, 0.1)
rand = [np.random.uniform(-0.1, 0.2) for _ in x]
y0 = np.exp(- (x - 5) ** 2 / 2) + rand
y1 = np.exp(- (x - 3) ** 2 / 0.5)
self.canvas.axes.plot(x, y0)
self.canvas.axes.plot(x, y1)
layout_canvas = QtWidgets.QVBoxLayout(self)
layout_canvas.addWidget(self.canvas)
self.canvasMenu = QtWidgets.QMenu(self)
self.canvasMenu.addAction("test")
self.canvas.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.canvas.customContextMenuRequested.connect(self._on_left_click)
def _on_left_click(self, event):
self.canvas.create_oval(event.xdata, event.ydata, brush_color="green")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MyPaintWidget()
w.show()
sys.exit(app.exec_())
To Add point I've added them by clicking on the curve. I know that code won't work to do what I've asked but it was just to produce an image to explain my idea.
As suggested by mkrieger1, I will briefly describe my solution :
First I've used PyQtGraph to plot my data to draw updates more efficiently than when I was using Matplotlib.
To control curves I've used QSliders (modified to support double) to control the parameters of each curve. When I move one slider it emits an event and in the function handling this event, I update my pyqtgraph plotwidget with the function setData.
I get my inspiration from to do my double cursor : Use float for QSlider
and I've used the pyqtgraph documentation : http://www.pyqtgraph.org/documentation/graphicsItems/plotdataitem.html
There is too much code to put it there but the solution is on my GitHub in the spectrofit project: https://github.com/fulmen27/SpectroFit (It's UI to process and study stellar spectrums). The solution is in the spectrofit.tools.Interactive_Fit.py file.
Hope this can help!
I am implemented two graphs in pyqt5 with pyqtgraph, and want to share cursor between two graphs.
I have a program result at the following:
And I want to share the crosshair like:
Can pyqtgraph do it ? Many thanks.
Following is my code (update), it will show 2 graph and the cursor will only allow move in graph2 only. However, I want the cursor can move and get data from graph1 and graph2.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
from pyqtgraph import MultiPlotWidget
class GUI_create_main_window(QWidget):
def __init__(self):
super().__init__()
main_layout = QVBoxLayout(self)
self.plot1 = pg.PlotWidget()
main_layout.addWidget(self.plot1)
self. plot2 = pg.PlotWidget()
main_layout.addWidget(self.plot2)
self.draw_cursor()
self.setLayout(main_layout)
self.show()
#hair cross event
def eventFilter(self, source, event):
try:
if (event.type() == QtCore.QEvent.MouseMove and
source is self.plot2.viewport()):
pos = event.pos()
if self.plot2.sceneBoundingRect().contains(pos):
mousePoint = self.vb.mapSceneToView(pos)
self.vLine.setPos(mousePoint.x())
self.hLine.setPos(mousePoint.y())
return QtGui.QWidget.eventFilter(self, source, event)
except Exception as e:
traceback.print_exc()
err = sys.exc_info()[1]
print(str(err))
def draw_cursor(self):
#cross hair
self.vLine = pg.InfiniteLine(angle=90, movable=False, pen=pg.mkPen('k', width=1))
self.hLine = pg.InfiniteLine(angle=0, movable=False, pen=pg.mkPen('k', width=1), label='{value:0.1f}',
labelOpts={'position':0.98, 'color': (200,0,0), 'movable': True, 'fill': (0, 0, 200, 100)})
self.plot2.addItem(self.vLine, ignoreBounds=True)
self.plot2.addItem(self.hLine, ignoreBounds=True)
self.vb = self.plot2.plotItem.vb
#set mouse event
self.plot2.setMouseTracking(True)
self.plot2.viewport().installEventFilter(self)
if __name__ == '__main__':
pg.setConfigOption('background', 'w')
pg.setConfigOption('foreground', 'k')
app = QApplication(sys.argv)
gui = GUI_create_main_window()
currentExitCode = app.exec_()
I know that it is kind of late but after struggling with similar problem I came up with a solution.
First of all we can capture mouse movements on pyqtgraph plots by installing 'SignalProxy' on their scene.
For example:
self.proxy = pg.SignalProxy(self.p.scene().sigMouseMoved, rateLimit=120, slot=self.mouseMoved)
This will call mouseMoved method on when mouse move signal is emitted.
We can get mouse position converted to scene position with
def mouseMoved(self, evt):
pos = evt[0]
mousePoint = self.p.vb.mapSceneToView(pos)
x, y = int(mousePoint.x()), int(mousePoint.y())
now we can set vLine pos to x and hLine pos to y on if we can have access to other graph's plot we can also set their vLine pos to x (since x axis should match)
we can link their x axis together (same movement on x axis is applied on other graph) by:
plot.setXLink(other_plot)
Side notes:
I set up two graphs by subclassing pyqtgraph's GraphicsLayoutWidget and adding plots to them individually I'm sure there should be a way of doing it in a single subclass but doing something like...
self.addPlot(title="Plot 1")
self.addPlot(title="Plot 2")
...creates two plots next to each other rather than stacked on top of
each other - we want to only link vLines anyways.
we can access other graph by something like this:
self.top_graph = TopGraph()
self.bottom_graph = BottomGraph()
self.top_graph.other_graph = self.bottom_graph # set bottom graph in top graph to access it in bottom graph
self.bottom_graph.other_graph = self.top_graph # set top graph in bottom graph to access it in top graph
maybe we can do global variables as well but I'm not sure that it is a good practice.
So it all adds up to:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import pyqtgraph as pg
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
main_widget = QWidget()
main_layout = QVBoxLayout()
main_widget.setLayout(main_layout)
self.setCentralWidget(main_widget)
self.top_graph = TopGraph()
self.bottom_graph = BottomGraph()
self.top_graph.other_graph = self.bottom_graph # set bottom graph in top graph to access it in bottom graph
self.bottom_graph.other_graph = self.top_graph # set top graph in bottom graph to access it in top graph
self.top_graph.p.setXLink(self.bottom_graph.p)
#example plot
x = range(-50, 51)
y1 = [i**2 for i in x]
y2 = [-i**2 for i in x]
self.top_graph.p.plot(x, y1, pen=pg.mkPen("r", width=3))
self.bottom_graph.p.plot(x, y2, pen=pg.mkPen("g", width=3))
splitter = QSplitter(Qt.Vertical)
splitter.addWidget(self.top_graph)
splitter.addWidget(self.bottom_graph)
main_layout.addWidget(splitter)
class TopGraph(pg.GraphicsLayoutWidget):
def __init__(self):
super().__init__()
self.p = self.addPlot()
self.p.hideAxis("bottom")
self.vLine = pg.InfiniteLine(angle=90, movable=False, pen=pg.mkPen('k', width=1))
self.hLine = pg.InfiniteLine(angle=0, movable=False, pen=pg.mkPen('k', width=1), label='{value:0.1f}',
labelOpts={'position':0.98, 'color': (200,0,0), 'movable': True, 'fill': (0, 0, 200, 100)})
self.p.addItem(self.vLine, ignoreBounds=True)
self.p.addItem(self.hLine, ignoreBounds=True)
self.proxy = pg.SignalProxy(self.p.scene().sigMouseMoved, rateLimit=120, slot=self.mouseMoved)
def mouseMoved(self, evt):
pos = evt[0]
if self.p.sceneBoundingRect().contains(pos):
self.hLine.show() # show this graph's h line since we are now in control
mousePoint = self.p.vb.mapSceneToView(pos)
x, y = int(mousePoint.x()), int(mousePoint.y())
self.vLine.setPos(x)
self.hLine.setPos(y)
self.other_graph.vLine.setPos(x)
self.other_graph.hLine.hide() # hide other graphs h line since we don't controll it here
class BottomGraph(pg.GraphicsLayoutWidget):
def __init__(self):
super().__init__()
self.p = self.addPlot()
self.vLine = pg.InfiniteLine(angle=90, movable=False, pen=pg.mkPen('k', width=1))
self.hLine = pg.InfiniteLine(angle=0, movable=False, pen=pg.mkPen('k', width=1), label='{value:0.1f}',
labelOpts={'position':0.98, 'color': (200,0,0), 'movable': True, 'fill': (0, 0, 200, 100)})
self.p.addItem(self.vLine, ignoreBounds=True)
self.p.addItem(self.hLine, ignoreBounds=True)
self.proxy = pg.SignalProxy(self.p.scene().sigMouseMoved, rateLimit=120, slot=self.mouseMoved)
def mouseMoved(self, evt):
pos = evt[0]
if self.p.sceneBoundingRect().contains(pos):
self.hLine.show() # show this graph's h line since we are now in control
mousePoint = self.p.vb.mapSceneToView(pos)
x, y = int(mousePoint.x()), int(mousePoint.y())
self.vLine.setPos(x)
self.hLine.setPos(y)
self.other_graph.vLine.setPos(x)
self.other_graph.hLine.hide() # hide other graphs h line since we don't controll it here
def main():
pg.setConfigOption('background', 'w')
pg.setConfigOption('foreground', 'k')
app = QApplication([])
window = MainWindow()
window.setMinimumSize(600, 400)
window.show()
app.exec()
if __name__ == "__main__":
main()
I would like to add mathematical expressions to the table labels (e.g.: 2^3 should be properly formatted)
Here is a simple example of a table:
http://thomas-cokelaer.info/blog/2012/10/pyqt4-example-of-tablewidget-usage/
setHorizontalHeaderLabels accepts string, only.
I wonder if is it possible to implement somehow this matplotlib approach:
matplotlib - write TeX on Qt form
are there other options?
I've also been trying for some time to display complex labels in the header of a QTableWidget. I was able to do it by reimplementing the paintSection method of a QHeaderView and painting manually the label with a QTextDocument as described in a thread on Qt Centre.
However, this solution was somewhat limited compared to what could be done with LaTex. I thought this could be a good idea to try the approach you suggested in your OP, i.e. using the capability of matplotlib to render LaTex in PySide.
1. Convert matplotlib Figure to QPixmap
First thing that is required in this approach is to be able to convert matplotlib figure in a format that can be easily painted on any QWidget. Below is a function that take a mathTex expression as input and convert it through matplotlib to a QPixmap.
import sys
import matplotlib as mpl
from matplotlib.backends.backend_agg import FigureCanvasAgg
from PySide import QtGui, QtCore
def mathTex_to_QPixmap(mathTex, fs):
#---- set up a mpl figure instance ----
fig = mpl.figure.Figure()
fig.patch.set_facecolor('none')
fig.set_canvas(FigureCanvasAgg(fig))
renderer = fig.canvas.get_renderer()
#---- plot the mathTex expression ----
ax = fig.add_axes([0, 0, 1, 1])
ax.axis('off')
ax.patch.set_facecolor('none')
t = ax.text(0, 0, mathTex, ha='left', va='bottom', fontsize=fs)
#---- fit figure size to text artist ----
fwidth, fheight = fig.get_size_inches()
fig_bbox = fig.get_window_extent(renderer)
text_bbox = t.get_window_extent(renderer)
tight_fwidth = text_bbox.width * fwidth / fig_bbox.width
tight_fheight = text_bbox.height * fheight / fig_bbox.height
fig.set_size_inches(tight_fwidth, tight_fheight)
#---- convert mpl figure to QPixmap ----
buf, size = fig.canvas.print_to_buffer()
qimage = QtGui.QImage.rgbSwapped(QtGui.QImage(buf, size[0], size[1],
QtGui.QImage.Format_ARGB32))
qpixmap = QtGui.QPixmap(qimage)
return qpixmap
2. Paint the QPixmaps to the header of a QTableWidget
The next step is to paint the QPixmap in the header of a QTableWidget. As shown below, I've done it by sub-classing QTableWidget and reimplementing the setHorizontalHeaderLabels method, which is used to convert the mathTex expressions for the labels into QPixmap and to pass it as a list to a subclass of QHeaderView. The QPixmap are then painted within a reimplementation of the paintSection method of QHeaderView and the height of the header is set up to fit the height of the mathTex expression in the reimplementation of the sizeHint methods.
class MyQTableWidget(QtGui.QTableWidget):
def __init__(self, parent=None):
super(MyQTableWidget, self).__init__(parent)
self.setHorizontalHeader(MyHorizHeader(self))
def setHorizontalHeaderLabels(self, headerLabels, fontsize):
qpixmaps = []
indx = 0
for labels in headerLabels:
qpixmaps.append(mathTex_to_QPixmap(labels, fontsize))
self.setColumnWidth(indx, qpixmaps[indx].size().width() + 16)
indx += 1
self.horizontalHeader().qpixmaps = qpixmaps
super(MyQTableWidget, self).setHorizontalHeaderLabels(headerLabels)
class MyHorizHeader(QtGui.QHeaderView):
def __init__(self, parent):
super(MyHorizHeader, self).__init__(QtCore.Qt.Horizontal, parent)
self.setClickable(True)
self.setStretchLastSection(True)
self.qpixmaps = []
def paintSection(self, painter, rect, logicalIndex):
if not rect.isValid():
return
#------------------------------ paint section (without the label) ----
opt = QtGui.QStyleOptionHeader()
self.initStyleOption(opt)
opt.rect = rect
opt.section = logicalIndex
opt.text = ""
#---- mouse over highlight ----
mouse_pos = self.mapFromGlobal(QtGui.QCursor.pos())
if rect.contains(mouse_pos):
opt.state |= QtGui.QStyle.State_MouseOver
#---- paint ----
painter.save()
self.style().drawControl(QtGui.QStyle.CE_Header, opt, painter, self)
painter.restore()
#------------------------------------------- paint mathText label ----
qpixmap = self.qpixmaps[logicalIndex]
#---- centering ----
xpix = (rect.width() - qpixmap.size().width()) / 2. + rect.x()
ypix = (rect.height() - qpixmap.size().height()) / 2.
#---- paint ----
rect = QtCore.QRect(xpix, ypix, qpixmap.size().width(),
qpixmap.size().height())
painter.drawPixmap(rect, qpixmap)
def sizeHint(self):
baseSize = QtGui.QHeaderView.sizeHint(self)
baseHeight = baseSize.height()
if len(self.qpixmaps):
for pixmap in self.qpixmaps:
baseHeight = max(pixmap.height() + 8, baseHeight)
baseSize.setHeight(baseHeight)
self.parentWidget().repaint()
return baseSize
3. Application
Below is an example of a simple application of the above.
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
w = MyQTableWidget()
w.verticalHeader().hide()
headerLabels = [
'$C_{soil}=(1 - n) C_m + \\theta_w C_w$',
'$k_{soil}=\\frac{\\sum f_j k_j \\theta_j}{\\sum f_j \\theta_j}$',
'$\\lambda_{soil}=k_{soil} / C_{soil}$']
w.setColumnCount(len(headerLabels))
w.setHorizontalHeaderLabels(headerLabels, 25)
w.setRowCount(3)
w.setAlternatingRowColors(True)
k = 1
for j in range(3):
for i in range(3):
w.setItem(i, j, QtGui.QTableWidgetItem('Value %i' % (k)))
k += 1
w.show()
w.resize(700, 200)
sys.exit(app.exec_())
which results in:
The solution is not perfect, but it is a good starting point. I'll update it when I will improve it for my own application.
I want to rotate QRectF in PyQT4 by given angle around bottom left corner. I know how to draw a rectangle but I'm stuck on how to rotate it. I tried with rotate(), but it rotates the coordinate system the given angle clockwise.
Is there any easy solution (except drawing a Polygon by changing coordinates)?
margin = 10
width = 100
depth = 20
self.p = QPainter(self)
self.rectangle = QRectF(margin, margin, width, depth)
self.angle = 30
self.p.rotate(self.angle)
self.p.drawRect(self.rectangle)
self.p.end()
you can move the rotation center (always top left corner) to an arbitrary point of the widget by painter.translate(), paint the rectangle with top left corner in the rotation center, calculate the x- and y- offset of your wanted rotation center and move the object again, then rotate the coordinate system for the next object. here a working example in pyqt5, replace QtWidgets by QtGui for pyqt4:
import sys
import math
from PyQt5 import QtCore, QtGui, QtWidgets
class MeinWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
self.setGeometry(200,50,300,300)
self.pen1 = QtGui.QPen(QtGui.QColor(0,0,0))
self.pen2 = QtGui.QPen(QtGui.QColor(255,0,0))
self.pen3 = QtGui.QPen(QtGui.QColor(0,255,0))
self.pen4 = QtGui.QPen(QtGui.QColor(0,0,255))
self.brush = QtGui.QBrush(QtGui.QColor(255,255,255))
self.pens = (self.pen1, self.pen2, self.pen3, self.pen4)
self.rw = 100
self.rh = 50
def paintEvent(self, event):
painter = QtGui.QPainter(self)
painter.translate(QtCore.QPointF(self.rw,self.rh)) # move rotation center to an arbitrary point of widget
angle = 10
for i in range(0,len(self.pens)):
dy = self.rh - self.rh*math.cos(math.radians(angle)) # vertical offset of bottom left corner
dx = self.rh*math.sin(math.radians(angle)) # horizontal offset of bottom left corner
p = self.pens[i]
p.setWidth(3)
painter.setPen(p)
painter.drawRect(0,0,self.rw,self.rh)
painter.translate(QtCore.QPointF(dx,dy)) # move the wanted rotation center to old position
painter.rotate(angle)
angle += 10
app = QtWidgets.QApplication(sys.argv)
widget = MeinWidget()
widget.show()
sys.exit(app.exec_())
looks like this:
I have matplotlib embedded in a PyQt4 app that I'm working on. The problem is when I dynamically add a subplot to the figure, the figures compress with every added subplot. I thought I could solve this by setting the figure to a QScrollArea but that doesn't work (as far as I can tell). Here's an example of what I thought would work
import os
os.environ['QT_API'] = 'pyside'
from PySide.QtGui import *
from PySide.QtCore import *
import matplotlib
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
class Canvas(FigureCanvasQTAgg):
def __init__(self, parent=None):
self.figure = Figure()
super(Canvas, self).__init__(self.figure)
ax = self.figure.add_subplot(1,1,1)
ax.plot([1,2,3])
self.draw()
def add_subplot(self, data=[]):
rows = len(self.figure.axes) + 1
for index, axes in enumerate(self.figure.axes, start=1):
axes.change_geometry(rows, 1, index)
ax = self.figure.add_subplot(rows, 1, index+1)
ax.plot(data)
self.draw()
class Main(QWidget):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.canvas = QScrollArea(self)
self.canvas.setWidget(Canvas(self))
self.canvas.setWidgetResizable(True)
for x in range(5):
self.canvas.widget().add_subplot()
layout = QVBoxLayout(self)
layout.addWidget(self.canvas)
app = QApplication([])
main = Main()
main.show()
app.exec_()
Notice how all the graphs are smashed together to show then in the same visible space? I wan't have to scroll to see the other graphs. I'm not sure how to do this exactly.
Anyone know how to do this or another way of doing this?
Two steps to sketch an idea to solve this:
Unset the resizing of the ScollArea to display scroll bars. Change the line:
self.canvas.setWidgetResizable(True)
to
self.canvas.setWidgetResizable(False)
Then when adding a subplot change the figure height, because the canvas will determine it's height by checking the size of the figure:
def add_subplot(self, data=[]):
rows = len(self.figure.axes) + 1
for index, axes in enumerate(self.figure.axes, start=1):
axes.change_geometry(rows, 1, index)
ax = self.figure.add_subplot(rows, 1, index+1)
ax.plot(data)
self.figure.set_figheight(self.figure.get_figheight()*1.25)
self.draw()
In the Main you have to let PySide know, that the it has to resize the widget in the scroll area:
for x in range(5):
self.canvas.widget().add_subplot()
self.canvas.widget().adjustSize()