Reputation: 83
I'm trying to plot an audio waveform using PyQt5 and Matplotlib, and despite trying several suggestions from other questions, I can't get the inner margins to disappear. I must be doing something wrong.
The audio waveform should be touching the edges of the widget, but as you can see in this screengrab, there is a large black inner margin on all four sides:
My code includes tight_layout()
and subplots_adjust()
calls from examples found online, but they don't seem to be having any effect. (The audio is maximised so the peak values should be hitting 100% of the available plot.)
Can somebody point out why the margins are still persisting please?
Full sample code:
import sys
import wave
import matplotlib as mpl
import numpy as np
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QLabel
from PyQt5.QtWidgets import QDialog, QGridLayout
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
class MatplotlibWidget(FigureCanvas):
def __init__(self, parent=None):
super(MatplotlibWidget, self).__init__(Figure())
self.setParent(parent)
self.figure = Figure(tight_layout=True)
self.figure.tight_layout(pad=0)
self.canvas = FigureCanvas(self.figure)
self.plot = None
self.figure.set_facecolor("black")
mpl.rcParams["lines.linewidth"] = 1
mpl.rcParams["lines.color"] = "b"
def plotAudio(self, waveformData):
self.plot = self.figure.add_subplot(111, position=[0, 0, 1, 1])
self.plot.clear()
self.plot.axis("off")
self.plot.use_sticky_edges = True
self.plot.set_title(None)
self.plot.set_xlabel(None)
self.plot.set_ylabel(None)
self.plot.margins(0)
self.figure.subplots_adjust(left=0, right=1, top=1, bottom=0, wspace=0, hspace=0)
self.figure.tight_layout(pad=0)
self.plot.plot(waveformData)
self.canvas.draw()
self.draw()
class WaveformTest(QDialog):
def __init__(self):
super().__init__()
self.title = 'PyQt5 tests'
self.setMinimumSize(200, 200)
self.setWindowFlags(QtCore.Qt.Window |
QtCore.Qt.WindowTitleHint |
QtCore.Qt.WindowCloseButtonHint)
self.label = QLabel("Waveform")
self.waveformWidget = MatplotlibWidget()
self.layout = QGridLayout(self)
self.layout.addWidget(self.label, 0, 0)
self.layout.addWidget(self.waveformWidget, 1, 0)
def plotAudio(self, sourceFile):
spf = wave.open(str(sourceFile), "r")
signal = spf.readframes(-1)
signal = np.fromstring(signal, "Int16")
self.waveformWidget.plotAudio(signal)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = WaveformTest()
ex.show()
sourceFile = "C:\\temp\\937-01400_20200622091518.wav"
ex.plotAudio(sourceFile)
sys.exit(app.exec_())
Upvotes: 2
Views: 1413
Reputation: 1291
I think what you want to get might be obtained using the xlim and ylim methods inside your plotAudio
function. Since I don't have your data set, I will show you its application in a hypothetical noisy function example:
import numpy as np
import matplotlib.pyplot as plt
num = np.random.uniform(-np.pi, np.pi, 10000)
sig = np.sin(num) + np.random.normal(0, 1, 10000)
figure = plt.Figure(tight_layout=True)
plot = figure.add_subplot(111, position=[0, 0, 1, 1])
plot.axis("off")
plot.use_sticky_edges = True
plot.set_title(None)
plot.set_xlabel(None)
plot.set_ylabel(None)
plot.margins(0)
figure.subplots_adjust(left=0, right=1, top=1, bottom=0, wspace=0, hspace=0)
figure.tight_layout(pad=0)
plt.xlim([-np.pi, np.pi])
plt.ylim([sig.min(), sig.max()])
plt.scatter(num, sig)
plt.show()
Here I include the plots with and without the explicit limits (basically commenting out the lines I added to your matplotlib code):
I hope this gives you some hints.
After debugging your code with the supplied input file, I found that something very close to the desired output can be found by modifying the MatplotlibWidget
class like this:
class MatplotlibWidget(FigureCanvas):
def __init__(self, parent=None):
super(MatplotlibWidget, self).__init__(Figure())
self.setParent(parent)
self.figure = Figure(constrained_layout=True)
self.figure.set_facecolor("black")
self.canvas = FigureCanvas(self.figure)
mpl.rcParams["lines.linewidth"] = 1
mpl.rcParams["lines.color"] = "b"
def plotAudio(self, waveformData):
plot = self.figure.add_subplot(111)
plot.margins(0)
plot.axis("off")
plot.plot(waveformData)
By setting the constrained_layout
keyword argument one can obtain the following plot:
Upvotes: 1
Reputation: 244132
You are creating a canvas inside the canvas unnecessarily, and that adds the margins. So the solution is to remove the unnecessary canvas:
class MatplotlibWidget(FigureCanvas):
def __init__(self, parent=None):
super(MatplotlibWidget, self).__init__(Figure())
self.setParent(parent)
self.figure.tight_layout(pad=0)
self.plot = None
self.figure.set_facecolor("black")
mpl.rcParams["lines.linewidth"] = 1
mpl.rcParams["lines.color"] = "b"
def plotAudio(self, waveformData):
self.plot = self.figure.add_subplot(111, position=[0, 0, 1, 1])
self.plot.clear()
self.plot.axis("off")
self.plot.use_sticky_edges = True
self.plot.set_title(None)
self.plot.set_xlabel(None)
self.plot.set_ylabel(None)
self.plot.margins(0)
self.figure.subplots_adjust(
left=0, right=1, top=1, bottom=0, wspace=0, hspace=0
)
self.figure.tight_layout(pad=0)
self.plot.plot(waveformData)
self.draw()
Before
After
Upvotes: 2