I'm trying to create a plot using QChart with python. I have so far managed to plot and to create an x- and y-axis, however they do not seem to correspond. I assume there is link between the chart, the axis and the series I'm missing. My self object is a chart.
My code:
self.axis_x = QValueAxis()
self.axis_x.setTitleText("Second")
self.axis_x.setRange(0, 10)
self.setAxisX(self.axis_x)
self.addAxis(self.axis_x, Qt.AlignBottom)
self.axis_y = QValueAxis()
self.axis_y.setTitleText(str(template.primary_y_axis.unit))
self.axis_y.setRange(0, 10)
self.setAxisY(self.axis_y)
self.addAxis(self.axis_y, Qt.AlignLeft)
self.series = QLineSeries()
p1 = QPoint(2, 0)
self.series.append(p1)
p2 = QPoint(2, 1)
self.series.append(p2)
p3 = QPoint(4, 2)
self.series.append(p3)
p4 = QPoint(6, 3)
self.series.append(p4)
p5 = QPoint(8, 4)
self.series.append(p5)
self.createDefaultAxes()
self.series.attachAxis(self.axis_x)
self.series.attachAxis(self.axis_y)
self.series.setName("hei")
self.addSeries(self.series)
self.legend().setVisible(True)
The plot i am recieving:
I have tried using QPoint to plot, and have also tried without. No difference.
I'll try to help with a reproducible example.
I tried to make the example look like your Sofia information.
Basically, I added the series to the chart chart.addSeries(series) before the attachAxis definition series.attachAxis(axis_x).
If the series is added after attachAxis, the series will be readjusted to the external
import sys
from PyQt5.Qt import Qt
from PyQt5.QtGui import QPainter
from PyQt5.QtCore import QPoint
from PyQt5.QtChart import QCategoryAxis, QValueAxis
from PyQt5.QtChart import QChart, QChartView, QLineSeries
from PyQt5.QtWidgets import QApplication, QMainWindow
class MyChart(QMainWindow):
def __init__(self):
super().__init__()
axis_x = QValueAxis()
axis_x.setRange(0, 10)
axis_x.setTitleText("Second")
axis_y = QValueAxis()
axis_y.setRange(0, 10)
axis_y.setTitleText("Other")
series = QLineSeries()
p1 = QPoint(2, 0)
series.append(p1)
p2 = QPoint(2, 1)
series.append(p2)
p3 = QPoint(4, 2)
series.append(p3)
p4 = QPoint(6, 3)
series.append(p4)
p5 = QPoint(8, 4)
series.append(p5)
series.setName("hei")
chart = QChart()
chart.addSeries(series)
chart.legend().setVisible(True)
chart.createDefaultAxes()
chart.setAxisX(axis_x)
chart.setAxisY(axis_y)
#chart.addAxis(axis_x, Qt.AlignBottom)
#chart.addAxis(axis_y, Qt.AlignLeft)
series.attachAxis(axis_x)
series.attachAxis(axis_y)
chartView = QChartView(chart)
chartView.setRenderHint(QPainter.Antialiasing)
self.setCentralWidget(chartView)
self.resize(1200, 800)
if __name__ == '__main__':
app = QApplication(sys.argv)
chartDemo = MyChart()
chartDemo.show()
sys.exit(app.exec_())
Related
I'm trying to draw a region of interest on a color map that is embedded in a pyqt5 gui. This is an example of what I want.
import sys
from PyQt5.QtWidgets import (QWidget, QPushButton,
QHBoxLayout, QVBoxLayout, QApplication)
from PyQt5 import QtCore
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import ROI_class as roi # ROI_class.py
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.drawButton.clicked.connect(self.draw_map_Callback)
self.roiButton.clicked.connect(self.choose_roi)
def initUI(self):
self.drawButton = QPushButton("draw map")
self.roiButton = QPushButton("roi")
self.hbox = QHBoxLayout()
self.hbox.addStretch(1)
self.hbox.addWidget(self.drawButton)
self.hbox.addWidget(self.roiButton)
self.vbox = QVBoxLayout()
self.vbox.addStretch(1)
self.vbox.addLayout(self.hbox)
self.setLayout(self.vbox)
self.setGeometry(500, 500, 500, 500)
self.setWindowTitle('ROI')
self.show()
def draw_map_Callback(self):
img = np.ones((100, 100)) * range(0, 100)
fig, ax1 = plt.subplots()
self.con_canvas = FigureCanvas(plt.figure(tight_layout=True))
self.con_canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
self.con_canvas.setFocus()
self.con_toolbar = NavigationToolbar(self.con_canvas, self)
self.vbox.addWidget(self.con_toolbar)
self.vbox.addWidget(self.con_canvas)
self._con_ax = self.con_canvas.figure.subplots()
self.con_img = self._con_ax.imshow(img, cmap ='jet')
self._con_ax.set_xlabel('xlabel')
self._con_ax.set_ylabel('ylabel')
self.con_cbar = self.con_canvas.figure.colorbar(self.con_img)
self._con_ax.set_aspect('equal')
def choose_roi(self):
y = roi.new_ROI(self.con_img)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
It will draw a colormap when I click "draw map". Then I want it to allow me to draw a region of interest with my mouse and get a mask using the code on this link below.
https://github.com/martindurant/misc/blob/master/ROI.py
The "ROI_class" that is imported is just a copy and paste of the code in the link above.
I can successfully draw the plot on the GUI but when I click "roi", it doesn't allow me to draw the region of interest.
When I mad a new file and paste the code in the link above with something like
fig, ax1 = plt.subplots()
s = ax1.imshow(img, cmap ='jet')
ax1.set_xlabel('subcolor')
ax1.set_ylabel('ylabel')
y = new_ROI(s)
at the end of the code, it worked just fine and I was able to draw the region of interest and get the mask of it.
But when I try to do this in the GUI, it wouldn't let me draw the region of interest. I'm very confused why this isn't working.
The problem is that picker (the variable "y") is a local variable that gets destroyed instantly causing the desired behavior not to be executed. The solution is to make it an attribute of the class:
self.y = roi.new_ROI(self.con_img)
I am using the crosshair example from pyqtgraph examples. I am trying to get the coordinates of a point when clicked on plotted graph on some point. It gives error at the marked line as <<<<<<<<<< in the code.
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore
#generate layout
app = QtGui.QApplication([])
win = pg.GraphicsLayoutWidget(show=True)
win.setWindowTitle('pyqtgraph example: crosshair')
label = pg.LabelItem(justify='right')
win.addItem(label)
p1 = win.addPlot(row=1, col=0)
#pg.dbg()
p1.setAutoVisible(y=True)
#create numpy arrays
#make the numbers large to show that the xrange shows data from 10000 to all the way 0
data1 = 10000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000)
data2 = 15000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000)
p1.plot(data1, pen="r")
p1.plot(data2, pen="g")
vb = p1.vb
def mouseMoved(evt):
pos = evt[0] ## using signal proxy turns original arguments into a tuple
mousePoint = vb.mapSceneToView(pos) <<<<<<<<<<<<<<
print(mousePoint.x(), mousePoint.y())
proxy = pg.SignalProxy(p1.scene().sigMouseClicked, slot=mouseMoved)
# Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
I modified the code a little bit with a different approach. Now it works fine.
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore
#generate layout
app = QtGui.QApplication([])
win = pg.GraphicsLayoutWidget(show=True)
win.setWindowTitle('pyqtgraph example: crosshair')
label = pg.LabelItem(justify='right')
win.addItem(label)
p1 = win.addPlot(row=1, col=0)
#pg.dbg()
p1.setAutoVisible(y=True)
#create numpy arrays
#make the numbers large to show that the xrange shows data from 10000 to all the way 0
data1 = 10000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000)
data2 = 15000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000)
p1.plot(data1, pen="r")
p1.plot(data2, pen="g")
vb = p1.vb
def onClick(event):
items = p1.scene().items(event.scenePos())
mousePoint = vb.mapSceneToView(event._scenePos)
print(mousePoint.x(), mousePoint.y())
if p1.sceneBoundingRect().contains(event._scenePos):
mousePoint = vb.mapSceneToView(event._scenePos)
index = int(mousePoint.x())
if index > 0 and index < len(data1):
label.setText(
"<span style='font-size: 12pt'>x=%0.1f, <span style='color: red'>y1=%0.1f</span>, <span style='color: green'>y2=%0.1f</span>" % (
mousePoint.x(), data1[index], data2[index]))
p1.scene().sigMouseClicked.connect(onClick)
## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()```
Is it possible link the auto-scale of several plots?
I want to scale all the plots with which ever is the biggest range on all curves of all plots.
Is there way to make it with a pyqtgraph function, or should I find the max, min and set the scale with a custom function?
I am using pyqtgraph on PyQt5
Pyqtgraph should automatically scale the y-axis on multiple plots with which ever has the largest range. Here's an example widget with auto-scaling plots in PyQt4 but the concept should be the same for PyQt5.
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
import sys
import random
class AutoScaleMultiplePlotWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(AutoScaleMultiplePlotWidget, self).__init__(parent)
self.NUMBER_OF_PLOTS = 4
self.LEFT_X = 0
self.RIGHT_X = 5
self.SPACING = 1
self.x_axis = np.arange(self.LEFT_X, self.RIGHT_X + 1, self.SPACING)
self.buffer_size = int((abs(self.LEFT_X) + abs(self.RIGHT_X) + 1)/self.SPACING)
self.auto_scale_plot_widget = pg.PlotWidget()
self.auto_scale_plot_widget.setLabel('left', 'left axis')
# Create plots
self.left_plot1 = self.auto_scale_plot_widget.plot()
self.left_plot2 = self.auto_scale_plot_widget.plot()
self.left_plot3 = self.auto_scale_plot_widget.plot()
self.left_plot4 = self.auto_scale_plot_widget.plot()
self.left_plot1.setPen((173,255,129), width=1)
self.left_plot2.setPen((172,187,255), width=1)
self.left_plot3.setPen((255,190,116), width=1)
self.left_plot4.setPen((204,120,255), width=1)
self.initialize_plot_buffers()
self.initialize_data_buffers()
self.layout = QtGui.QGridLayout()
self.layout.addWidget(self.auto_scale_plot_widget)
self.start()
def initialize_data_buffers(self):
"""Create blank data buffers for each curve"""
self.data_buffers = []
for trace in range(self.NUMBER_OF_PLOTS):
self.data_buffers.append([0])
def initialize_plot_buffers(self):
"""Add plots into buffer for each curve"""
self.plots = []
self.plots.append(self.left_plot1)
self.plots.append(self.left_plot2)
self.plots.append(self.left_plot3)
self.plots.append(self.left_plot4)
def update_plot(self):
"""Generates new random value and plots curve onto plot"""
for trace in range(self.NUMBER_OF_PLOTS):
if len(self.data_buffers[trace]) >= self.buffer_size:
self.data_buffers[trace].pop(0)
data_point = self.data_buffers[trace][-1] + random.randint(10,50)
self.data_buffers[trace].append(float(data_point))
self.plots[trace].setData(self.x_axis[len(self.x_axis) - len(self.data_buffers[trace]):], self.data_buffers[trace])
def get_auto_scale_plot_layout(self):
return self.layout
def start(self):
self.multiple_axis_plot_timer = QtCore.QTimer()
self.multiple_axis_plot_timer.timeout.connect(self.update_plot)
self.multiple_axis_plot_timer.start(500)
if __name__ == '__main__':
# Create main application window
app = QtGui.QApplication([])
app.setStyle(QtGui.QStyleFactory.create("Cleanlooks"))
mw = QtGui.QMainWindow()
mw.setWindowTitle('Auto Scale Multiple Plot Example')
# Create plot
auto_scale_plot = AutoScaleMultiplePlotWidget()
# Create and set widget layout
# Main widget container
cw = QtGui.QWidget()
ml = QtGui.QGridLayout()
cw.setLayout(ml)
mw.setCentralWidget(cw)
# Add plot to main layout
ml.addLayout(auto_scale_plot.get_auto_scale_plot_layout(),0,0)
mw.show()
if(sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
I have some code very similar to the example given by PyQtGraph below. I also want to add to the label the color of the exact pixel being moused over (the pixel at the crosshair). How would I do this?
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore
from pyqtgraph.Point import Point
#generate layout
app = QtGui.QApplication([])
win = pg.GraphicsWindow()
win.setWindowTitle('pyqtgraph example: crosshair')
label = pg.LabelItem(justify='right')
win.addItem(label)
p1 = win.addPlot(row=1, col=0)
p2 = win.addPlot(row=2, col=0)
region = pg.LinearRegionItem()
region.setZValue(10)
# Add the LinearRegionItem to the ViewBox, but tell the ViewBox to exclude this
# item when doing auto-range calculations.
p2.addItem(region, ignoreBounds=True)
#pg.dbg()
p1.setAutoVisible(y=True)
#create numpy arrays
#make the numbers large to show that the xrange shows data from 10000 to all the way 0
data1 = 10000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000)
data2 = 15000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000)
p1.plot(data1, pen="r")
p1.plot(data2, pen="g")
p2.plot(data1, pen="w")
def update():
region.setZValue(10)
minX, maxX = region.getRegion()
p1.setXRange(minX, maxX, padding=0)
region.sigRegionChanged.connect(update)
def updateRegion(window, viewRange):
rgn = viewRange[0]
region.setRegion(rgn)
p1.sigRangeChanged.connect(updateRegion)
region.setRegion([1000, 2000])
#cross hair
vLine = pg.InfiniteLine(angle=90, movable=False)
hLine = pg.InfiniteLine(angle=0, movable=False)
p1.addItem(vLine, ignoreBounds=True)
p1.addItem(hLine, ignoreBounds=True)
vb = p1.vb
def mouseMoved(evt):
pos = evt[0] ## using signal proxy turns original arguments into a tuple
if p1.sceneBoundingRect().contains(pos):
mousePoint = vb.mapSceneToView(pos)
index = int(mousePoint.x())
#######
GET THE PIXEL COLOR AND ADD TO LABEL??? HOW?
#######
if index > 0 and index < len(data1):
label.setText("<span style='font-size: 12pt'>x=%0.1f, <span style='color: red'>y1=%0.1f</span>, <span style='color: green'>y2=%0.1f</span>" % (mousePoint.x(), data1[index], data2[index]))
vLine.setPos(mousePoint.x())
hLine.setPos(mousePoint.y())
proxy = pg.SignalProxy(p1.scene().sigMouseMoved, rateLimit=60, slot=mouseMoved)
#p1.scene().sigMouseMoved.connect(mouseMoved)
## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
You must override the mouseMoveEvent method, record the widget and get the pixel.
For this we will create a class that inherits from pg.GraphicsWindow:
class MyGraphicsWindow(pg.GraphicsWindow):
def __init__(self, parent=None):
pg.GraphicsWindow.__init__(self, parent=parent)
self.setMouseTracking(True)
def mouseMoveEvent(self, e):
image = QtGui.QPixmap.grabWidget(self).toImage()
color = QtGui.QColor(image.pixel(e.pos()))
print(color.name())
print("red:{}, green:{}, blue:{}".format(color.red(), color.green(), color.blue()))
pg.GraphicsWindow.mouseMoveEvent(self, e)
Then we will replace win = pg.GraphicsWindow() with win = MyGraphicsWindow()
Complete code:
class MyGraphicsWindow(pg.GraphicsWindow):
def __init__(self, parent=None):
pg.GraphicsWindow.__init__(self, parent=parent)
self.setMouseTracking(True)
def mouseMoveEvent(self, e):
image = QtGui.QPixmap.grabWidget(self).toImage()
color = QtGui.QColor(image.pixel(e.pos()))
print(color.name())
print("{}, {}, {}".format(color.red(), color.green(), color.blue()))
pg.GraphicsWindow.mouseMoveEvent(self, e)
#generate layout
app = QtGui.QApplication(sys.argv)
win = MyGraphicsWindow()
win.setWindowTitle('pyqtgraph example: crosshair')
label = pg.LabelItem(justify='right')
win.addItem(label)
p1 = win.addPlot(row=1, col=0)
p2 = win.addPlot(row=2, col=0)
region = pg.LinearRegionItem()
region.setZValue(10)
# Add the LinearRegionItem to the ViewBox, but tell the ViewBox to exclude this
# item when doing auto-range calculations.
p2.addItem(region, ignoreBounds=True)
#pg.dbg()
p1.setAutoVisible(y=True)
#create numpy arrays
#make the numbers large to show that the xrange shows data from 10000 to all the way 0
data1 = 10000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000)
data2 = 15000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000)
p1.plot(data1, pen="r")
p1.plot(data2, pen="g")
p2.plot(data1, pen="w")
def update():
region.setZValue(10)
minX, maxX = region.getRegion()
sys.exit(app.exec_())
I was trying to plot multiple line/dots using the mplwidget in Qtdesigner plugin. Usually when i use matplotlib in python by default it will keep the first line graph and plot another graph on top of that for comparison. But in Qtdesigner,after i am using matplotlib as a widget object, i select figure object then addsubplot and then plot the graph, it seems like it will delete the old line graph and plot the new one. I'm pretty sure there's something wrong with the coding, but i'm new to this GUI stuff, i'm not sure which part of it went wrong
import sys
from PyQt4 import QtGui, QtCore
from window import Ui_MainWindow
import sqlite3
import os
from datetime import datetime
import calendar
import numpy
os.chdir("C:\Data")
conn = sqlite3.connect('FBG.db')
c=conn.cursor()
class Main(QtGui.QMainWindow):
def searching_database(self):
self.ui.listWidget.clear()
data = self.ui.Inputname.text()
for df in c.execute("select name from sqlite_master where type='table'; "):
strdf=str(df)
if len(data)==0:
break
if strdf[3:(len(data)+3)] == data: # the name for df start from position 3 due to "[u "
self.ui.listWidget.addItem(strdf[3:-3])
else:
pass
def delete_selection(self):
self.ui.listWidget_3.takeItem(self.ui.listWidget_3.currentRow())
def clear_graph(self):
self.ui.listWidget_3.clear()
self.ax.clear()
self.ui.mplwidget.draw()
def plot_graph(self):
b=self.ui.listWidget.currentItem().text()
b=str(b)
self.ui.listWidget_3.addItem(b)
time1= QtCore.QDateTime(self.ui.dateTimeEdit.dateTime())
date1 = time1.toPyDateTime()
timestamp1 = calendar.timegm(date1.utctimetuple()) #return a integer value
time2= QtCore.QDateTime(self.ui.dateTimeEdit_2.dateTime())
date2 = time2.toPyDateTime()
timestamp2 = calendar.timegm(date2.utctimetuple())
time=[]
data=[]
for df in c.execute('''select * from '''+ b ):
time= numpy.append(time, df[0])
data= numpy.append(data, df[1])
self.ax.plot([2,4,5,6],[1,5,6,7],label=b) % set up for matplot widget
self.ax.plot([1,3,4,5],[2,4,5,6],label=b+"afasdasdasd") % set up for matplot widget
self.ax.legend() % set up for matplot widget
self.ui.mplwidget.draw() % set up for matplot widget
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.Inputname.textChanged.connect(self.searching_database)
self.ui.listWidget.itemDoubleClicked.connect(self.plot_graph)
self.ui.pushButton.clicked.connect(self.plot_graph)
self.ui.Delete.clicked.connect(self.delete_selection)
self.ui.Clear.clicked.connect(self.clear_graph)
self.ui.mplwidget.axes.set_title("Strain/Temperature vs Time") % set up for matplot widget
self.fig = self.ui.mplwidget.figure % set up for matplot widget
self.ax = self.fig.add_subplot(1,1,1) % set up for matplot widget
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window= Main()
window.show()
sys.exit(app.exec_())
The code is running fine. But i think there must be some code prevent me getting what i am trying to achieve. I think it might those codes with "% set up for matplot widget" following them. Any suggestions would be good.
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
class myWidget(QWidget):
def __init__(self, parent=None):
super(myWidget, self).__init__(parent)
self.fig = plt.figure()
self.canvas = FigureCanvas(self.fig)
self.vbox = QVBoxLayout()
self.vbox.addWidget(self.canvas)
self.setLayout(self.vbox)
self.plotCurve(self.canvas)
def plotCurve(self, FigureCanvas):
left, width = 0.1, 0.8
rect1 = [left, 0.2, width, 0.6]
FigureCanvas.figure.set_facecolor('white')
axescolor = '#f6f6f6' # the axies background color
FigureCanvas.figure.clear()
ax1 = FigureCanvas.figure.add_axes(rect1, axisbg=axescolor) #left, bottom, width, height
ax1.set_title('Some Curve')
x = range(10, 20)
y = range(10, 20)
z = range(20, 30)
p1, = ax1.plot(x, y, 'ro')
p2, = ax1.plot(x, z, '-')
ax1.set_ylabel('Some Label')
FigureCanvas.draw()
def main():
app = QApplication(sys.argv)
form = myWidget()
form.show()
app.exec_()
main()
Try this:
self.ui.mplwidget.axes.hold(True)
This should let you plot two data sets on the same axis, just like you can in interactive mode. Worked for me!