I am currently working on creating a Qt window with 3 matplotlib colormaps.
The process is something like this:
I am currently working on the script that will real-time graph these colormaps in a Qt window as the data is being taken. I can find readily accessible resources on how to real-time plot line graphs; however, I am unable to find anything for colormaps. Here is the code I have so far:
import sys
import time
import random
import numpy as np
from matplotlib.backends.qt_compat import QtWidgets
from matplotlib.backends.backend_qt5agg import (
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
import matplotlib as mpl
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
# Quick note, this will need to be a widget class in the final version so it can be run from the kalamari main window
# but I think that will just change how the class is initalized
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
# set up the window
super().__init__()
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
# It seems as though this layout is what is going to allow me to
# orient all 3 subplots onto the same y axis
layout = QtWidgets.QVBoxLayout(self._main)
# create seperate canvas objects
first_canvas = FigureCanvas(Figure(figsize=(9, 6)))
layout.addWidget(NavigationToolbar(first_canvas, self))
layout.addWidget(first_canvas)
second_canvas = FigureCanvas(Figure(figsize=(9, 3)))
layout.addWidget(second_canvas)
layout.addWidget(NavigationToolbar(second_canvas, self))
# add subplots to the first canvas
self._first_axs = first_canvas.figure.subplots(1, 3)
# create data and colormap
# Here I replace X and Y with coordinate vectors which are just np.linspace
x = np.linspace(0, 10, 10)
y = np.linspace(0, 10, 10)
# For the final version you can use x for flux and y for biases and then have
# each row of z be the voltages, such that:
# z[i,j] is V(bias[j], flux[i])
# Then here is the data I will use to determine the color,
# this needs to have the same dimension as the coordinates
z = np.random.rand(10, 10)
custom_cmap = mpl.colors.LinearSegmentedColormap.from_list(
"custom", ["#00008B", "blue", "cyan", "green", "yellow", "orange", "red", "#8B0000"])
# access each subplot using regular indexing
self._first_axs[0].set_title(
'I' + u'\u209B' + u'\u2092' + u'\u209C', size=40)
self._first_axs[1].set_title(
'dI' + u'\u209B' + u'\u2092' + u'\u209C' + '/dt', size=40)
self._first_axs[2].set_title('Noise', size=40)
# plot data and create colorbars
self.plot1 = self._first_axs[0].contourf(
x, y, z, levels=20, cmap=custom_cmap)
self.plot2 = self._first_axs[1].contourf(
x, y, z, levels=20, cmap=custom_cmap)
self.plot3 = self._first_axs[2].contourf(
x, y, z, levels=20, cmap=custom_cmap)
self.cbar1 = first_canvas.figure.colorbar(
self.plot1, ax=self._first_axs[0], orientation='horizontal')
self.cbar2 = first_canvas.figure.colorbar(
self.plot2, ax=self._first_axs[1], orientation='horizontal')
self.cbar3 = first_canvas.figure.colorbar(
self.plot3, ax=self._first_axs[2], orientation='horizontal')
# make the second canvas a dynamic plot
self._second_ax = second_canvas.figure.subplots()
t = list(range(50))
self.yData = [random.randint(0, 10) for i in range(50)]
# Set up a Line2D.
self._line, = self._second_ax.plot(t, self.yData)
self._timer = second_canvas.new_timer(50)
self._timer.add_callback(self._update_canvas)
self._timer.start()
def _update_canvas(self):
t = list(range(50))
self.yData = self.yData[1:] + [random.randint(0, 10)]
# set line data
self._line.set_data(t, self.yData)
self._line.figure.canvas.draw()
if __name__ == "__main__":
# Check for open QApplication.instance()
qapp = QtWidgets.QApplication.instance()
if not qapp:
qapp = QtWidgets.QApplication(sys.argv)
# run it!
app = ApplicationWindow()
app.show()
app.activateWindow()
app.raise_()
qapp.exec()
This code currently produces 1 Qt window with 2 separate "canvases". The first canvas is the 3 colormaps, the second is a line plot that real-time graphs.
You can try replotting the contour with every update call. I use ax.cla()
to clear the current plot, before plotting new information. This script is an example of what that might look like.
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng()
N = 25
x = np.linspace(-1, 1, N)
y = np.linspace(-1, 1, N)
Niter = 25
fig, ax = plt.subplots()
ax.set_aspect(1)
for _ in range(Niter):
ax.cla()
z = rng.uniform(size=(N,N))
ax.contourf(x, y, z)
fig.canvas.draw()
renderer = fig.canvas.renderer
ax.draw(renderer)
plt.pause(0.01)