Say, I have a set of data of consists of the time sequence and the coordinates of X, Y, Z thousands points (sample data as below). I want to plot the data in 3D, in a way like the Earth orbiting the Sun, or the Earth orbiting the Sun with a trail of 10 faded Earth.
By following the 3D example code, currently I am able to plot all points together with fading at the same time. But I don't know how to iterate the points and update the plot with the timer start/stop properly.
(orbit.csv)
TimeDiff,X,Y,Z
0.0,0.00,0.27,-8.28
0.04,-0.96,0.27,-11.46
0.17,-0.96,-0.18,-13.81
0.36,-2.69,-0.18,-16.34
0.5,-2.69,-0.77,-17.69
0.73,-4.82,-0.77,-19.20
0.83,-4.82,-0.99,-19.43
1.04,-6.10,-0.99,-19.68
1.18,-6.10,-0.84,-18.87
1.39,-4.20,-0.84,-17.49
1.5,-4.20,-0.65,-15.63
1.72,-2.09,-0.65,-13.38
1.83,-2.09,-0.31,-10.49
2.05,-0.92,-0.31,-7.47
2.18,-0.92,0.09,-4.10
2.36,-0.12,0.09,-0.58
2.52,-0.12,0.20,2.71
2.7,-0.05,0.20,6.11
2.86,-0.05,0.11,9.12
3.03,-0.89,0.11,12.30
3.18,-0.89,-0.29,14.46
or in markdown format:
| Time | X | Y | Z |
| -------- | ----- | ----- | ------ |
| 0 | 0 | 0.27 | -8.28 |
| 0.04 | -0.96 | 0.27 | -11.46 |
| 0.17 | -0.96 | -0.18 | -13.81 |
| 0.36 | -2.69 | -0.18 | -16.34 |
| 0.5 | -2.69 | -0.77 | -17.69 |
| 0.73 | -4.82 | -0.77 | -19.2 |
| 0.83 | -4.82 | -0.99 | -19.43 |
| 1.04 | -6.1 | -0.99 | -19.68 |
| 1.18 | -6.1 | -0.84 | -18.87 |
| 1.39 | -4.2 | -0.84 | -17.49 |
| 1.5 | -4.2 | -0.65 | -15.63 |
| 1.72 | -2.09 | -0.65 | -13.38 |
| 1.83 | -2.09 | -0.31 | -10.49 |
| 2.05 | -0.92 | -0.31 | -7.47 |
| 2.18 | -0.92 | 0.09 | -4.1 |
| 2.36 | -0.12 | 0.09 | -0.58 |
| 2.52 | -0.12 | 0.2 | 2.71 |
from pyqtgraph.Qt import QtCore, QtGui, QtWidgets
import pyqtgraph.opengl as gl
from pyqtgraph import functions as fn
import numpy as np
import pandas as pd
import os
app = QtWidgets.QApplication([])
w = gl.GLViewWidget()
w.opts['distance'] = 500
w.show()
w.setWindowTitle('pyqtgraph example: GLVolumeItem')
ax = gl.GLAxisItem()
ax.setSize(900, 900, 900)
w.addItem(ax)
f = "Orbit.csv"
df = pd.read_csv(f)
timeList = df['TimeDiff'].tolist()
comp_x = df["X"].tolist()
comp_y = df["Y"].tolist()
comp_z = df["Z"].tolist()
w.setWindowTitle('pyqtgraph example: DateAxisItem')
speed = 1
measureTimeList = [x / speed for x in timeList]
line_x = [x for x in comp_x]
line_y = [x for x in comp_y]
line_z = [x for x in comp_z]
pos = np.empty((len(line_x), 3))
size = np.empty(len(line_x))
color = np.empty((len(line_x), 4))
pos[2] = (0, 0, 1);
size[2] = 1. / 1.0;
color[2] = (0.0, 1.0, 0.0, 1)
def update(): ## update volume colors
global phase, sp2, d2
s = -np.cos(d2*2+phase)
color = np.empty((len(line_x), 4), dtype=np.float32)
color[:, 3] = fn.clip_array(s * 0.1, 0., 1.)
color[:, 0] = fn.clip_array(s * 3.0, 0., 1.)
color[:, 1] = fn.clip_array(s * 1.0, 0., 1.)
color[:, 2] = fn.clip_array(s ** 3, 0., 1.)
sp2.setData(color=color)
phase -= 0.1
t = QtCore.QTimer()
t.timeout.connect(update)
t.start(20)
color = np.ones((pos.shape[0], 4))
for i in range(len(line_x)):
pos[i] = (line_z[i], line_x[i], line_y[i])
d2 = 2
phase = 90.
size = 2
s = -np.cos(d2 * 2 + phase)
color[:, 3] = fn.clip_array(s * 0.1, 0., 1.)
color[:, 0] = fn.clip_array(s * 3.0, 0., 1.)
color[:, 1] = fn.clip_array(s * 1.0, 0., 1.)
color[:, 2] = fn.clip_array(s ** 3, 0., 1.)
sp2 = gl.GLScatterPlotItem(pos=pos, color=(1, 1, 1, 1), size=size)
w.addItem(sp2)
## Start Qt event loop unless running in interactive mode.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtWidgets.QApplication.instance().exec_()
Unfortunatly, I do not see an orbit in your data. Nevertheless, here's my approach:
Set all colors to fully transparent. Then create a "transparency ramp" from 0 to 1 and let this ramp "roll" over your positions for each update. This way, it looks like a moving fading object:
from itertools import cycle
import pyqtgraph.opengl as gl
import numpy as np
import pandas as pd
import pyqtgraph as pg
from PySide6.QtTest import QTest
app = pg.mkQApp()
w = gl.GLViewWidget()
w.opts["distance"] = 100
w.show()
ax = gl.GLAxisItem()
ax.setSize(900, 900, 900)
w.addItem(ax)
df = pd.read_csv("Orbit.csv")
pos = [(z, x, y) for z, x, y in zip(df["Z"], df["X"], df["Y"])]
sp2 = gl.GLScatterPlotItem(pos=pos, color=(1, 1, 1, 1), size=5)
w.addItem(sp2)
delta_times = np.diff(df["TimeDiff"])
# repeat the last time step for loop-around
delta_times = np.append(delta_times, delta_times[-1])
# create transparency ramp
n_display = 6
color = np.ones((sp2.pos.shape[0], 4), dtype=np.float32)
color[:, 3] = 0
color[: n_display + 1, 3] = np.linspace(0, 1, n_display + 1)
# endless cycle over delta times
for dt in cycle(delta_times):
# move the ramp over the array by one
color = np.roll(color, 1, axis=0)
sp2.setData(color=color)
# delay application
QTest.qWait(int(dt * 1000))