How to plot the Earth orbit with pyqtgraph?

65 views Asked by At

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   |

enter image description here

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_()
1

There are 1 answers

4
Christian Karcher On BEST ANSWER

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:

enter image description here

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))