How to fix BarGraphItem height of a plot using PyQtgraph - python

How to fix BarGraphItem height when zoom in or zoom out pyqtgraph plot, it should be similar with axis font, the font size is in pixel, please someone helps, thank you very much, basic code as below:
import numpy as np
import pyqtgraph as pg
pg.setConfigOption('leftButtonPan', False)
win = pg.plot()
win.setWindowTitle('pyqtgraph example: BarGraphItem')
x = np.arange(10)
bg1 = pg.BarGraphItem(x=x, height=5, width=1,brush='r')
win.addItem(bg1)
win.setYRange(0,110)
win.setLimits(yMin=0,yMax=110,xMin=-0.5,xMax=11)
if name == 'main':
pg.exec()

Related

Matplotlib subplot on QLabel gives different colormap

When I draw a Matplotlib subplot on a QLabel, I get a different colormap than when I save it to file. How can I show the real colormap with QT? For example, in my code below, the image on disk has the good red-blue colormap, but the QT one is a blue-dark orange one. I tried other QImage formats but no good so far.
import sys
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
from PyQt5.QtGui import QImage, QPixmap
class Window(QMainWindow):
def __init__(self):
# window design
super().__init__()
self.setFixedSize(1000, 400)
# create QT element
self.wid_labelGraph = QLabel(self)
self.wid_labelGraph.setStyleSheet("background-color : white;")
self.setCentralWidget(self.wid_labelGraph)
self.make_graphs()
def make_graphs(self):
# generate graph
heatmaps = [ np.ones((50, 50)), np.zeros((50, 50)), -1 * np.ones((50, 50)) ]
fig, axs = plt.subplots(1, 3, figsize = (10, 4))
for i in range(3):
im = axs[i].imshow(heatmaps[i], cmap = 'RdBu_r', clim = (-1, 1))
axs[i].set_axis_off()
fig.colorbar(im, ax = axs.ravel().tolist())
fig.savefig('temp.png')
canvas = FigureCanvas(fig)
canvas.draw()
width, height = fig.figbbox.width, fig.figbbox.height
img = QImage(canvas.buffer_rgba(), width, height, QImage.Format_ARGB32)
self.wid_labelGraph.setPixmap(QPixmap(img))
# free memory
plt.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
app.exec()
The format is wrong.
You're using Format_ARGB32:
The image is stored using a 32-bit ARGB format (0xAARRGGBB).
But, as the function name buffer_rgba() suggests, the format is rgba, so Format_RGBA8888:
The image is stored using a 32-bit byte-ordered RGBA format (8-8-8-8). Unlike ARGB32 this is a byte-ordered format, which means the 32bit encoding differs between big endian and little endian architectures, being respectively (0xRRGGBBAA) and (0xAABBGGRR). The order of the colors is the same on any architecture if read as bytes 0xRR,0xGG,0xBB,0xAA.
You got the wrong colors because the bits referring to the components are shifted: the red was interpreted as alpha, the green as red, the blue as green, and the alpha as blue.

Polar coordinate system in pyqtgraph

I need to implement two graphs in Cartesian and polar coordinates. Everything is clear with Cartesian, but is it possible to make a polar coordinate system in pyqtgraph?
pyqtgraph does not provide by default the ability to make polar plots, I have requested the feature through the issue #452, in that discussion it is indicated that you can create that type plot easily by giving an example here.
The example is as follows:
import numpy as np
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
plot = pg.plot()
plot.setAspectLocked()
# Add polar grid lines
plot.addLine(x=0, pen=0.2)
plot.addLine(y=0, pen=0.2)
for r in range(2, 20, 2):
circle = pg.QtGui.QGraphicsEllipseItem(-r, -r, r * 2, r * 2)
circle.setPen(pg.mkPen(0.2))
plot.addItem(circle)
# make polar data
theta = np.linspace(0, 2 * np.pi, 100)
radius = np.random.normal(loc=10, size=100)
# Transform to cartesian and plot
x = radius * np.cos(theta)
y = radius * np.sin(theta)
plot.plot(x, y)
if __name__ == "__main__":
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, "PYQT_VERSION"):
QtGui.QApplication.instance().exec_()
Probably in future release pyqtgraph will offer that feature.
I can offer you to use the QPolarChart from PyQt5.QtChart. It's really easy. For example:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtChart import QPolarChart, QChartView, QValueAxis, QScatterSeries
self.polar = QPolarChart()
chartView = QChartView(self.polar)
layout = QVBoxLayout()
layout.addWidget(chartView)
#Let's create container widget for our chart, for example QFrame
#Instead the MainWindow you should to substitute your own Widget or Main Form
self.MyFrame = QtWidgets.QFrame(MainWindow)
self.MyFrame.setGeometry(QtCore.QRect(0, 0, 1000, 1000))
self.MyFrame.setLayout(layout)
#setting axis
axisy = QValueAxis()
axisx = QValueAxis()
axisy.setRange(0,500)
axisy.setTickCount(4)
self.polar.setAxisY(axisy)
axisx.setRange(0,360)
axisx.setTickCount(5)
self.polar.setAxisX(axisx)
#Let's draw scatter series
self.polar_series = QScatterSeries()
self.polar_series.setMarkerSize(5.0)
self.polar_series.append(0, 0);
self.polar_series.append(360, 500);
#Why not draw archimedes spiral
for i in range(0,360,10):
self.polar_series.append(i, i)
self.polar.addSeries(self.polar_series)

Embedding matplotlib into tkinter canvas opens two windows

The following code I am working on in not behaving the way I wish it to. I have embedded a matplotlib graph into a tkinter canvas. The program opens up two windows, one of which functions properly, and one of which is not necessary.I am not sure how to fix this. Here is the code, please ignore the unnecessary imports :)
import numpy as np
import sys
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib as mpl
from matplotlib import cm
from numpy.random import random
from matplotlib.widgets import Button
import matplotlib.colors
import tkinter as tk
import matplotlib.backends.tkagg as tkagg
from matplotlib.backends.backend_agg import FigureCanvasAgg
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
DEBUG_MODE = False #Debug mode - True = ON
MATRIX_WIDTH = 50
MATRIX_HEIGHT = 50
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600
LED_COUNT = MATRIX_WIDTH * MATRIX_HEIGHT
REFRESH_RATE = 30 #REFRESH_RATE used to control FuncAnimation interval
MATRIX = random((50,50)) #Fills MATRIX as not to be null for first print
plt.rcParams['toolbar'] = 'None' #Disables matplotlib toolbar
fig = plt.figure(figsize=(3,3)) #'figsize' measured in inches
im = plt.imshow(MATRIX, interpolation='nearest', cmap=cm.Spectral)
plt.axis('off') #Turns off x, y axis
def data_gen(): #Generates amd populates MATRIX with pattern data
while True:
MATRIX = random((MATRIX_WIDTH, MATRIX_HEIGHT))
yield MATRIX
if (DEBUG_MODE): print("MATRIX yeilded")
def update(data): #Updates/prints new MATRIX from data_gen()
im.set_array(data)
if (DEBUG_MODE): print("Updated data")
root = tk.Tk()
label = tk.Label(root,text="Matrix Program").grid(column=0, row=0)
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.get_tk_widget().grid(column=0,row=1)
ani = animation.FuncAnimation(fig, update, data_gen, interval=REFRESH_RATE)
plt.show()
What needs to be done to this code so that it opens only one canvas from tkinter with the live matplotlib graph embedded?
How can I set the size of the canvas?
Do not call plt.show() if you want to show your figure inside a tk GUI. Best do not use pyplot at all when embedding.
On the other hand, you probably want to start the mainloop, tk.mainloop(), at some point.
Refer to the matplotlib example on how to embedd a matplotlib figure into tk.

pyqtgraph: align the ticks of the x-axes in different plots

This is a follow up to this question.
The question is how to adapt the x-axis scaling of multiple pyqtgraphs when one of the graphs is rescaled. My desired result is that the ticks of all graphs align perfectly, so that you can directly compare the content of both graphs.
The given answer archives that task, of rescaling the graphs on changes but when the content of the graphs differs the y-Axis description tends to be of different size which somehow messes everything up.
For example in the image below I adjusted the bottom plot to roughly cover the 0-100 range. Strangely the upper plot is showing a bigger interval.
Any ideas how to align the ticks while rescaling?
Source code of the example:
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
from pyqtgraph.dockarea import *
import sys
def onSigRangeChanged(r):
w1.sigRangeChanged.disconnect(onSigRangeChanged)
w2.sigRangeChanged.disconnect(onSigRangeChanged)
if w1==r:
w2.setRange(xRange=r.getAxis('bottom').range)
elif w2 == r:
w1.setRange(xRange=r.getAxis('bottom').range)
w1.sigRangeChanged.connect(onSigRangeChanged)
w2.sigRangeChanged.connect(onSigRangeChanged)
app = QtGui.QApplication(sys.argv)
win = QtGui.QMainWindow()
area = DockArea()
win.setCentralWidget(area)
win.resize(1000,500)
win.setWindowTitle('pyqtgraph example: dockarea')
d1 = Dock("Dock1")
d2 = Dock("Dock2")
area.addDock(d1, 'bottom')
area.addDock(d2, 'bottom', d1)
w1 = pg.PlotWidget(title="Dock 1 plot")
w1.plot(np.random.normal(size=100)*1e12)
w1.plotItem.showGrid(x=True,y=True,alpha=1)
d1.addWidget(w1)
w2 = pg.PlotWidget(title="Dock 2 plot")
w2.plot(np.random.normal(size=100))
w2.plotItem.showGrid(x=True,y=True,alpha=1)
d2.addWidget(w2)
w1.sigRangeChanged.connect(onSigRangeChanged)
w2.sigRangeChanged.connect(onSigRangeChanged)
win.show()
sys.exit(app.exec_())
I just found the answer in this question.
Instead of connecting to the sigRangeChanged event we can directly link the axes scales by w2.setXLink(w1). Of course we have to remove the connections to sigRangeChanged or the scales will shoot to the sky. Here is the example code:
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
from pyqtgraph.dockarea import *
import sys
app = QtGui.QApplication(sys.argv)
win = QtGui.QMainWindow()
area = DockArea()
win.setCentralWidget(area)
win.resize(1000,500)
win.setWindowTitle('pyqtgraph example: dockarea')
d1 = Dock("Dock1")
d2 = Dock("Dock2")
area.addDock(d1, 'bottom')
area.addDock(d2, 'bottom', d1)
w1 = pg.PlotWidget(title="Dock 1 plot")
w1.plot(np.random.normal(size=100)*1e12)
w1.plotItem.showGrid(x=True,y=True,alpha=1)
d1.addWidget(w1)
w2 = pg.PlotWidget(title="Dock 2 plot")
w2.plot(np.random.normal(size=100))
w2.plotItem.showGrid(x=True,y=True,alpha=1)
w2.setXLink(w1)
d2.addWidget(w2)
win.show()
sys.exit(app.exec_())

Python Matplotlib : Just the graph image

I cannot get pyplot to produce "cropped" images, that is, get rid of the grey left and right borders, as it is, it is not an accurate representation of the sound waveform : This sound file has no silence before and after.
My code :
import gtk
from matplotlib.figure import Figure
from numpy import arange, sin, pi
import scipy.io.wavfile as wavfile
from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas
win = gtk.Window()
win.connect("destroy", lambda x: gtk.main_quit())
win.set_default_size(400,300)
win.set_title("Cropping figure")
rate, data = wavfile.read(open('/home/px/gare_du_nord-catchlak.wav', 'r'))
f = Figure()
a = f.add_subplot(111, axisbg=(0.1843, 0.3098, 0.3098))
a.plot(range(len(data)),data, color="OrangeRed", linewidth=0.5, linestyle="-")
a.axis('off')
a.autoscale_view('tight')
canvas = FigureCanvas(f) # a gtk.DrawingArea
win.add(canvas)
win.show_all()
gtk.main()
OK, I got my answer :
f.subplots_adjust(0, 0, 1, 1)
EDIT:
This also works, in fact it works even better:
a.margins(0, 0)

Categories

Resources