Let's go in parts:
-
To get the style you show in the graph, the simplest way is to use the style that is already predefined in Matplotlib, dark_background
. It would also be possible to do so by manually changing the color to each element of course.
-
To embed the graph in your Qt application, the simplest and most direct is to use the backend provided by matplotlib, specifically matplotlib.backends.backend_qt5agg.FigureCanvasQTAgg
. Currently it is a widget, so you can handle it as such.
-
To allow dragging and dropping the files to analyze, you must enable Drag and Drop in the widget using the Qwidget.setAcceptDrops(True)
method and overwrite the event dropEvent
so that when the file is released the File above the widget will run the necessary code to generate the spectrogram.
The code as an example could look something like this:
import sys
import matplotlib
matplotlib.use('Qt5Agg')
from PyQt5 import QtCore, QtWidgets
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import soundfile as sf
class Spectrograph(FigureCanvas):
def __init__(self, parent=None, width=5, height=4, dpi=100):
plt.style.use('dark_background')
self.fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = self.fig.add_subplot(111)
self.cbar = None
self.compute_initial_figure()
super(Spectrograph, self).__init__(self.fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,
QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
self.setAcceptDrops(True)
def dragEnterEvent(self, e):
if e.mimeData().hasFormat('text/uri-list'):
e.accept()
else:
e.ignore()
def dropEvent(self, e):
if e.mimeData().hasUrls:
for url in e.mimeData().urls():
e.setDropAction(QtCore.Qt.CopyAction)
e.accept()
file = str(url.toLocalFile())
self.update_graph(file)
else:
e.ignore()
def update_graph(self, file):
self.axes.cla()
if self.cbar:
self.cbar.remove()
data, samplerate = sf.read(file)
y = data.sum(axis=1)/2
Pxx, freqs, bins, im = self.axes.specgram(y, NFFT=256, Fs=samplerate, cmap='jet')
plt.gcf().set_size_inches(10,5)
self.axes.set_xlim(0, len(y) / samplerate)
self.axes.set_ylim(0, 23000)
self.cbar = self.fig.colorbar(im)
self.cbar.set_label('Intensidad (dB)')
self.axes.set_xlabel('Tiempo (s)')
self.axes.set_ylabel('Frecuencia (Hz)')
self.a = 0
self.draw()
def compute_initial_figure(self):
pass
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.setWindowTitle("Audio Spectrograph")
self.main_widget = QtWidgets.QWidget(self)
self.graph = Spectrograph(self.main_widget, width=5, height=4, dpi=100)
layout = QtWidgets.QVBoxLayout(self.main_widget)
layout.addWidget(self.graph)
self.main_widget.setStyleSheet("QWidget {background-color: black}")
self.main_widget.setFocus()
self.setCentralWidget(self.main_widget)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = ApplicationWindow()
window.show()
sys.exit(app.exec_())
Note: I have not touched the way you get the data from the audio file and the graphics, it has only been adapted. All this procedure is done within the SpectroGraph.update_graph
method in this case.
And this is the behavior: