Generate frames in the worker:
- cf-python worker generates contour maps as matplotlib figures
- Convert each to an image (PNG bytes or QPixmap)
- Store them in a queue or list that the main PySide thread can access
Animate in PySide:
- Use a QTimer to cycle through frames at a set interval
- Update the image frame's pixmap on each timer tick
- (This gives smooth animation without blocking the UI)
Basic implementation pattern could be based on
from PySide6.QtWidgets import QLabel, QVBoxLayout, QWidget
from PySide6.QtGui import QPixmap, QImage
from PySide6.QtCore import QTimer, Qt
from io import BytesIO
import matplotlib.pyplot as plt
class AnimatedContourWidget(QWidget):
def __init__(self, frames_queue):
super().__init__()
self.frames_queue = frames_queue
self.frames = []
self.current_frame = 0
# Image label
self.image_label = QLabel()
self.image_label.setAlignment(Qt.AlignCenter)
layout = QVBoxLayout()
layout.addWidget(self.image_label)
self.setLayout(layout)
# Animation timer
self.timer = QTimer()
self.timer.timeout.connect(self.show_next_frame)
self.timer.setInterval(100) # 100ms between frames = 10 FPS
def set_frames(self, frames_list):
"""Called once all frames are ready from worker"""
self.frames = frames_list
self.current_frame = 0
self.timer.start()
def show_next_frame(self):
if not self.frames:
return
# Get current frame (matplotlib figure as bytes)
fig_bytes = self.frames[self.current_frame]
# Convert to QPixmap
pixmap = QPixmap()
pixmap.loadFromData(fig_bytes, 'PNG')
self.image_label.setPixmap(pixmap)
# Next frame
self.current_frame = (self.current_frame + 1) % len(self.frames)
with server side:
def generate_contours(field_data, num_frames=50):
"""Worker function that generates 50 contour maps"""
frames = []
for i in range(num_frames):
fig, ax = plt.subplots(figsize=(8, 6))
# Generate/slice your field data for this frame
data_slice = field_data[i] # or however you're iterating
contour = ax.contourf(data_slice, levels=20, cmap='viridis')
ax.set_title(f'Frame {i+1}/{num_frames}')
plt.colorbar(contour, ax=ax)
# Convert to PNG bytes
buf = BytesIO()
fig.savefig(buf, format='png', dpi=100, bbox_inches='tight')
buf.seek(0)
frames.append(buf.getvalue())
plt.close(fig)
return frames
Generate frames in the worker:
Animate in PySide:
Basic implementation pattern could be based on
with server side: