Reputation: 6295
I have a pyqt5 gui which has two pyqtgraphs inside. The left graph will plot the speed of some object, so will need a dynamically changing y axis and the right plot will show the position, which will be inside a box which is 61m x 121m. Currently, the graphs are plotting but the axis are overlapping the edges and cutting off the axis/numbers. In addition, I have added a title to the plots but they arent showing either. How do I fit the plot correctly?
Here is my code:
from PyQt5 import QtWidgets, uic, QtCore
from pyqtgraph import PlotWidget
import pyqtgraph as pg
import sys
import numpy as np
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
#Load the UI Page
uic.loadUi('mainwindow.ui', self)
self.position.setXRange(0,60)
self.position.setYRange(0,120)
self.position.setWindowTitle("Position")
def plot(self):
x = np.random.rand(100)
y = np.random.rand(100)
self.position.plot(x, y)
def main():
app = QtWidgets.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
and my mainwindow.ui file is:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>791</width>
<height>597</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="styleSheet">
<string notr="true">background-color: black;</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>110</y>
<width>771</width>
<height>451</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>16</number>
</property>
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item>
<widget class="PlotWidget" name="speed" native="true"/>
</item>
<item>
<widget class="PlotWidget" name="position" native="true"/>
</item>
</layout>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>791</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<customwidgets>
<customwidget>
<class>PlotWidget</class>
<extends>QWidget</extends>
<header>pyqtgraph</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
Upvotes: 1
Views: 2662
Reputation: 21
To prevent the overlapping axis you could make use of the fact that the PlotWidget
inherits from QGraphicsView
. QGraphicsView
has a fitInView()
method that can be used to fit a rectangle in the current view.
The method sceneRect()
returns a rectangle that describes "the area of the scene visualized by this view". By slightly growing this rectangle you can add some padding. This is done in the example below in the _add_padding_to_plot_widget()
method. Please note that this only works after the QT app is started, that's why the function gets called from showEvent
. Directly calling it from __init__
does not work.
example code:
import sys
import numpy as np
from PyQt5 import QtWidgets, uic, QtCore
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
# Load the UI Page
uic.loadUi('mainwindow.ui', self)
self.position.setXRange(0, 60)
self.position.setYRange(0, 120)
self.position.setTitle("Position")
self._add_padding_to_plot_widget(self.position)
def showEvent(self, e) -> None:
super().showEvent(e)
self._add_padding_to_plot_widget(self.position)
def plot(self):
x = np.random.rand(100)
y = np.random.rand(100)
self.position.plot(x, y)
@staticmethod
def _add_padding_to_plot_widget(plot_widget, padding=0.1):
"""
zooms out the view of a plot widget to show 'padding' around the contents of a PlotWidget
:param plot_widget: The widget to add padding to
:param padding: the percentage of padding expressed between 0.0 and 1.0
:return:
"""
width = plot_widget.sceneRect().width() * (1. + padding)
height = plot_widget.sceneRect().height() * (1. + padding)
center = plot_widget.sceneRect().center()
zoom_rect = QtCore.QRectF(center.x() - width / 2., center.y() - height / 2., width, height)
plot_widget.fitInView(zoom_rect)
def main():
app = QtWidgets.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
output:
Upvotes: 2
Reputation: 523
Currently, the graphs are plotting but the axis are overlapping the edges and cutting off the axis/numbers.
I am not quite sure what you mean, but I cannot comment. If you set the lower panning limits of both axis to zero, the two axis will overlap at zero. setLimit
function is inherited from class ViewBox
Edit: If you mean by cutting the number at max range just add a padding parameter to the setRange function to slightly widen the view range. See the example below.
In addition, I have added a title to the plots but they aren't showing either. How do I fit the plot correctly?
use setTitle
function inherited form class PlotItem
A simple example based on op's code.
from PyQt5 import QtWidgets
import pyqtgraph as pg
import sys
import numpy as np
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
# Set geometry of mainwindow
self.setGeometry(0, 0, 791, 597)
self.setWindowTitle("Main Window")
self.setStyleSheet("QWidget { background-color: white; }")
# Set the central widget and its layout
self.horizontalLayoutWidget= QtWidgets.QWidget()
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayoutWidget.setLayout(self.horizontalLayout)
self.setCentralWidget(self.horizontalLayoutWidget)
# Set the spacing and margins of the layout
self.horizontalLayout.setSpacing(16)
self.horizontalLayout.setContentsMargins(10,10,10,10)
# Add PlotWidget to layout
self.speed = pg.PlotWidget()
self.horizontalLayout.addWidget(self.speed)
self.position = pg.PlotWidget()
self.horizontalLayout.addWidget(self.position)
# Set the view limit of x and y axis so that the axis will overlap at (0,0)
self.position.setLimits(xMin = 0, yMin = 0)
# Set a small padding to avoid the number form cutting off the edge
self.position.setXRange(0,60, padding= 0.02)
self.position.setYRange(0,120)
# Use setTitle function, which is inherited form class PlotItem
self.position.setTitle("Position")
self.speed.setTitle("Speed")
self.plot()
def plot(self):
data = np.random.rand(60)*100
self.position.plot(data)
def main():
app = QtWidgets.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Upvotes: 3