Source code for kf.QtWaves

"""PyQt5 widgets to render wave generator systems.
"""

################################################################
# Written in 2019 by Garth Zeglin <garthz@cmu.edu>

# To the extent possible under law, the author has dedicated all copyright
# and related and neighboring rights to this software to the public domain
# worldwide. This software is distributed without any warranty.

# You should have received a copy of the CC0 Public Domain Dedication along with this software.
# If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.

################################################################
import math, logging
import numpy as np

# for documentation on the PyQt5 API, see http://pyqt.sourceforge.net/Docs/PyQt5/index.html
from PyQt5 import QtCore, QtGui, QtWidgets

# set up logger for module
log = logging.getLogger('QtConcentricLoops')

# filter out most logging; the default is NOTSET which passes along everything
# log.setLevel(logging.WARNING)

################################################################
[docs]class QtWaves1D(QtWidgets.QWidget): """Custom widget representing a 1D wave system generator.""" def __init__(self, channels=1): super().__init__() self.setMinimumSize(QtCore.QSize(100, 100)) self.setAutoFillBackground(True) # graphical state variables self.W = channels # the number of waves to show superimposed # q is a (W, N) matrix representing W waves of N sample points # the values are vertical position ranging over [-1,1] N = 20 self.q = np.zeros((self.W, N)) # finish initialization self.show() return
[docs] def update_positions(self, positions): """Update the wave display with a (W, N) numpy matrix of position values.""" self.q = positions self.repaint()
# === element drawing methods ============================================================ # === Qt API methods ============================================================
[docs] def paintEvent(self, e): """Subclass implementation of parent QWidget class callback to repaint the graphics.""" geometry = self.geometry() view_width = geometry.width() view_height = geometry.height() # clear the background qp = QtGui.QPainter() qp.begin(self) qp.fillRect(QtCore.QRectF(0, 0, view_width, view_height), QtCore.Qt.white) # qp.setRenderHint(QtGui.QPainter.Antialiasing) # Set up a coordinate system centered in the visible area. scene_width = 22 # define minimum visible area scene_height = 2 scene_aspect = scene_width / scene_height view_aspect = view_width / view_height if scene_aspect > view_aspect: scaling = view_width / scene_width else: scaling = view_height/scene_height qp.save() qp.translate(QtCore.QPointF(view_width/2, view_height/2)) qp.scale(scaling, scaling) # draw the wave as a set of circular masses pen = QtGui.QPen(QtCore.Qt.black) pen.setWidthF(0.01) qp.setPen(pen) W = len(self.q) for i, wave in enumerate(self.q[:]): color = QtGui.QColor() hue = i / W color.setHsvF(hue, 1.0, 1.0, 1.0) brush = QtGui.QBrush(color) qp.setBrush(brush) N = len(wave) x_delta = 21 / N for i, pos in enumerate(wave): x = -10 + i*x_delta qp.drawEllipse(QtCore.QPointF(x, -pos), 0.2, 0.2) # restore the initial unscaled coordinates qp.restore() qp.end()
################################################################