3D图表例子

This commit is contained in:
Irony 2019-10-04 23:39:16 +08:00
parent 686fe5a4d0
commit 61560e9d12
8 changed files with 2912 additions and 1 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,413 @@
# Blender v2.69 (sub 0) OBJ File: ''
# www.blender.org
v 0.000000 0.986570 0.000000
v 0.000000 0.500000 -0.218399
v -0.042608 0.500000 -0.214202
v -0.083578 0.500000 -0.201774
v -0.121336 0.500000 -0.181592
v -0.154431 0.500000 -0.154431
v -0.181592 0.500000 -0.121336
v -0.201774 0.500000 -0.083578
v -0.214202 0.500000 -0.042608
v -0.218399 0.500000 -0.000000
v -0.214202 0.500000 0.042607
v -0.201774 0.500000 0.083578
v -0.181592 0.500000 0.121336
v -0.154431 0.500000 0.154431
v -0.121336 0.500000 0.181592
v -0.083578 0.500000 0.201774
v -0.042607 0.500000 0.214202
v 0.000000 0.500000 0.218399
v 0.042608 0.500000 0.214202
v 0.083578 0.500000 0.201774
v 0.121336 0.500000 0.181592
v 0.154431 0.500000 0.154431
v 0.181592 0.500000 0.121336
v 0.201774 0.500000 0.083577
v 0.214202 0.500000 0.042607
v 0.218399 0.500000 -0.000000
v 0.214202 0.500000 -0.042608
v 0.201774 0.500000 -0.083578
v 0.181592 0.500000 -0.121336
v 0.154431 0.500000 -0.154432
v 0.121336 0.500000 -0.181592
v 0.083577 0.500000 -0.201774
v 0.042607 0.500000 -0.214202
v 0.000000 0.000000 0.000000
v 0.000000 0.000000 0.000000
v -0.000000 0.500000 -0.126422
v -0.024664 0.500000 -0.123993
v -0.048380 0.500000 -0.116799
v -0.070236 0.500000 -0.105116
v -0.089394 0.500000 -0.089394
v -0.105116 0.500000 -0.070236
v -0.116799 0.500000 -0.048380
v -0.123993 0.500000 -0.024664
v -0.126422 0.500000 -0.000000
v -0.123993 0.500000 0.024664
v -0.116799 0.500000 0.048380
v -0.105116 0.500000 0.070236
v -0.089394 0.500000 0.089394
v -0.070236 0.500000 0.105116
v -0.048380 0.500000 0.116799
v -0.024664 0.500000 0.123993
v 0.000000 0.500000 0.126422
v 0.024664 0.500000 0.123993
v 0.048380 0.500000 0.116799
v 0.070236 0.500000 0.105116
v 0.089394 0.500000 0.089394
v 0.105116 0.500000 0.070236
v 0.116799 0.500000 0.048380
v 0.123993 0.500000 0.024664
v 0.126422 0.500000 -0.000000
v 0.123993 0.500000 -0.024664
v 0.116799 0.500000 -0.048380
v 0.105116 0.500000 -0.070237
v 0.089394 0.500000 -0.089394
v 0.070236 0.500000 -0.105116
v 0.048380 0.500000 -0.116799
v 0.024664 0.500000 -0.123993
v 0.126422 -0.983070 -0.000000
v 0.123993 -0.983070 0.024664
v -0.048380 -0.983070 -0.116799
v -0.024664 -0.983070 -0.123993
v -0.070236 -0.983070 0.105116
v -0.089394 -0.983070 0.089394
v 0.116799 -0.983070 0.048380
v 0.105116 -0.983070 0.070236
v -0.105116 -0.983070 0.070236
v -0.116799 -0.983070 0.048380
v 0.024664 -0.983070 -0.123993
v 0.048380 -0.983070 -0.116799
v 0.089394 -0.983070 0.089394
v 0.070236 -0.983070 0.105116
v -0.123993 -0.983070 0.024664
v -0.126422 -0.983070 -0.000000
v 0.070236 -0.983070 -0.105116
v 0.089394 -0.983070 -0.089394
v 0.048380 -0.983070 0.116799
v 0.024664 -0.983070 0.123993
v -0.123993 -0.983070 -0.024664
v -0.116799 -0.983070 -0.048380
v 0.105116 -0.983070 -0.070237
v 0.116799 -0.983070 -0.048380
v -0.105116 -0.983070 -0.070236
v -0.089394 -0.983070 -0.089394
v 0.000000 -0.983070 0.126422
v -0.024664 -0.983070 0.123993
v 0.123993 -0.983070 -0.024664
v -0.070236 -0.983070 -0.105116
v -0.048380 -0.983070 0.116799
v -0.000000 -0.983070 -0.126422
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 1.000000 1.000000
vt 0.000000 1.000000
vt 0.500000 1.000000
vt 0.597545 0.990393
vt 0.402456 0.990393
vt 0.691342 0.961940
vt 0.777785 0.915735
vt 0.853553 0.853553
vt 0.915735 0.777785
vt 0.961940 0.691342
vt 0.990393 0.597545
vt 1.000000 0.500000
vt 0.990393 0.402455
vt 0.961940 0.308658
vt 0.915735 0.222215
vt 0.853553 0.146447
vt 0.777785 0.084265
vt 0.691342 0.038060
vt 0.597545 0.009607
vt 0.308659 0.961940
vt 0.222215 0.915735
vt 0.146447 0.853554
vt 0.308658 0.038060
vt 0.500000 0.000000
vt 0.402455 0.009607
vt 0.222215 0.084265
vt 0.146446 0.146447
vt 0.084265 0.222215
vt 0.009607 0.402455
vt 0.038060 0.308659
vt 0.009607 0.597546
vt 0.000000 0.500000
vt 0.038060 0.691342
vt 0.084266 0.777786
vn -0.089495 0.407852 -0.908651
vn -0.265044 0.407852 -0.873733
vn -0.430408 0.407852 -0.805236
vn -0.579231 0.407852 -0.705796
vn -0.705796 0.407852 -0.579232
vn -0.805237 0.407852 -0.430408
vn -0.873733 0.407852 -0.265043
vn -0.908651 0.407852 -0.089495
vn -0.908652 0.407852 0.089494
vn -0.873732 0.407852 0.265044
vn -0.805237 0.407852 0.430407
vn -0.705796 0.407852 0.579232
vn -0.579231 0.407852 0.705796
vn -0.430408 0.407852 0.805237
vn -0.265044 0.407852 0.873733
vn -0.089494 0.407852 0.908652
vn 0.089495 0.407852 0.908651
vn 0.265044 0.407852 0.873732
vn 0.430408 0.407852 0.805237
vn 0.579232 0.407852 0.705796
vn 0.705796 0.407852 0.579231
vn 0.805237 0.407852 0.430406
vn 0.873733 0.407852 0.265044
vn 0.908652 0.407852 0.089493
vn 0.908651 0.407852 -0.089496
vn 0.873732 0.407852 -0.265045
vn 0.805236 0.407852 -0.430409
vn 0.705795 0.407852 -0.579232
vn 0.579231 0.407852 -0.705796
vn 0.430407 0.407852 -0.805237
vn 0.265042 0.407852 -0.873733
vn 0.089494 0.407852 -0.908652
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000062
vn -0.290284 0.000000 0.956940
vn -0.098017 0.000000 0.995185
vn -0.634393 0.000000 -0.773010
vn -0.773010 0.000000 -0.634393
vn 0.956940 0.000000 -0.290286
vn 0.881921 0.000000 -0.471398
vn -0.881922 0.000000 -0.471396
vn -0.956940 0.000000 -0.290285
vn 0.098017 0.000000 0.995185
vn 0.290285 0.000000 0.956940
vn 0.773010 0.000000 -0.634394
vn 0.634392 0.000000 -0.773011
vn -0.995185 0.000000 -0.098017
vn -0.995185 0.000000 0.098017
vn 0.471397 0.000000 0.881921
vn 0.634394 0.000000 0.773010
vn 0.471395 0.000000 -0.881922
vn 0.290283 0.000000 -0.956941
vn 0.098016 0.000000 -0.995185
vn -0.956940 0.000000 0.290285
vn -0.881922 0.000000 0.471396
vn 0.773011 0.000000 0.634393
vn 0.881922 0.000000 0.471396
vn -0.773010 0.000000 0.634393
vn -0.634394 0.000000 0.773010
vn -0.471397 0.000000 0.881921
vn -0.098016 0.000000 -0.995185
vn -0.290284 0.000000 -0.956940
vn -0.471397 0.000000 -0.881921
vn 0.956941 0.000000 0.290284
vn 0.995185 0.000000 0.098016
vn 0.995185 0.000000 -0.098018
vn 0.000000 -1.000000 0.000001
vn 0.000000 -1.000000 0.000018
vn 0.000000 -1.000000 -0.000013
vn 0.000000 -1.000000 0.000011
vn 0.000000 -1.000000 0.000002
vn 0.000000 -1.000000 -0.000031
vn 0.000000 -1.000000 0.000031
vn 0.000000 -1.000000 -0.000021
vn 0.000000 -1.000000 -0.000016
vn 0.000000 -1.000000 -0.000005
vn 0.000000 -1.000000 0.000003
vn -0.098015 0.000000 0.995185
vn -0.773011 0.000000 -0.634393
vn -0.881921 0.000000 -0.471396
vn 0.773009 0.000000 -0.634394
vn 0.098017 0.000000 -0.995185
vn -0.634393 0.000000 0.773011
vn -0.098018 0.000000 -0.995185
vn -0.290285 0.000000 -0.956940
s off
f 1/1/1 2/2/1 3/3/1
f 1/1/2 3/2/2 4/3/2
f 1/1/3 4/2/3 5/3/3
f 1/1/4 5/2/4 6/3/4
f 1/1/5 6/2/5 7/3/5
f 1/1/6 7/2/6 8/3/6
f 1/1/7 8/2/7 9/3/7
f 1/1/8 9/2/8 10/3/8
f 1/1/9 10/2/9 11/3/9
f 1/1/10 11/2/10 12/3/10
f 1/1/11 12/2/11 13/3/11
f 1/1/12 13/2/12 14/3/12
f 1/1/13 14/2/13 15/3/13
f 1/1/14 15/2/14 16/3/14
f 1/1/15 16/2/15 17/3/15
f 1/1/16 17/2/16 18/3/16
f 1/1/17 18/2/17 19/3/17
f 1/1/18 19/2/18 20/3/18
f 1/1/19 20/2/19 21/3/19
f 1/1/20 21/2/20 22/3/20
f 1/1/21 22/2/21 23/3/21
f 1/1/22 23/2/22 24/3/22
f 1/1/23 24/2/23 25/3/23
f 1/1/24 25/2/24 26/3/24
f 1/1/25 26/2/25 27/3/25
f 1/1/26 27/2/26 28/3/26
f 1/1/27 28/2/27 29/3/27
f 1/1/28 29/2/28 30/3/28
f 1/1/29 30/2/29 31/3/29
f 1/1/30 31/2/30 32/3/30
f 1/1/31 32/2/31 33/3/31
f 1/1/32 33/2/32 2/3/32
f 24/1/33 23/2/33 58/4/33
f 13/1/33 12/2/33 47/4/33
f 2/1/33 33/2/33 36/4/33
f 23/1/33 22/2/33 57/4/33
f 12/1/33 11/2/33 46/4/33
f 33/1/33 32/2/33 67/4/33
f 22/1/33 21/2/33 56/4/33
f 11/1/33 10/2/33 45/4/33
f 32/1/33 31/2/33 66/4/33
f 21/1/33 20/2/33 55/4/33
f 10/1/33 9/2/33 44/4/33
f 31/1/33 30/2/33 65/4/33
f 20/1/33 19/2/33 54/4/33
f 9/1/33 8/2/33 43/4/33
f 30/1/33 29/2/33 64/4/33
f 19/1/33 18/2/33 53/4/33
f 3/1/33 2/2/33 37/4/33
f 8/1/33 7/2/33 42/4/33
f 29/1/33 28/2/33 63/4/33
f 7/1/33 6/2/33 41/4/33
f 18/1/33 17/2/33 52/4/33
f 28/1/33 27/2/33 62/4/33
f 6/1/33 5/2/33 40/4/33
f 17/1/33 16/2/33 51/4/33
f 27/1/33 26/2/33 61/4/33
f 5/1/33 4/2/33 39/4/33
f 16/1/33 15/2/33 50/4/33
f 26/1/33 25/2/33 60/4/33
f 4/1/33 3/2/33 38/4/33
f 15/1/33 14/2/33 49/4/33
f 25/1/33 24/2/33 59/4/33
f 14/1/33 13/2/33 48/4/33
f 81/5/34 86/6/34 80/7/34
f 51/1/35 50/2/35 95/4/35
f 52/1/36 51/2/36 94/4/36
f 40/1/37 39/2/37 93/4/37
f 41/1/38 40/2/38 92/4/38
f 62/1/39 61/2/39 91/4/39
f 63/1/40 62/2/40 90/4/40
f 42/1/41 41/2/41 89/4/41
f 43/1/42 42/2/42 88/4/42
f 53/1/43 52/2/43 87/4/43
f 54/1/44 53/2/44 86/4/44
f 64/1/45 63/2/45 85/4/45
f 65/1/46 64/2/46 84/4/46
f 44/1/47 43/2/47 83/4/47
f 45/1/48 44/2/48 82/4/48
f 55/1/49 54/2/49 81/4/49
f 56/1/50 55/2/50 80/4/50
f 66/1/51 65/2/51 79/4/51
f 67/1/52 66/2/52 78/4/52
f 36/1/53 67/2/53 99/4/53
f 46/1/54 45/2/54 77/4/54
f 47/1/55 46/2/55 76/4/55
f 57/1/56 56/2/56 75/4/56
f 58/1/57 57/2/57 74/4/57
f 48/1/58 47/2/58 73/4/58
f 49/1/59 48/2/59 72/4/59
f 50/1/60 49/2/60 98/4/60
f 37/1/61 36/2/61 71/4/61
f 38/1/62 37/2/62 70/4/62
f 39/1/63 38/2/63 97/4/63
f 59/1/64 58/2/64 69/4/64
f 60/1/65 59/2/65 68/4/65
f 61/1/66 60/2/66 96/4/66
f 23/2/33 57/3/33 58/4/33
f 12/2/33 46/3/33 47/4/33
f 33/2/33 67/3/33 36/4/33
f 22/2/33 56/3/33 57/4/33
f 11/2/33 45/3/33 46/4/33
f 32/2/67 66/3/67 67/4/67
f 21/2/33 55/3/33 56/4/33
f 10/2/33 44/3/33 45/4/33
f 31/2/33 65/3/33 66/4/33
f 20/2/33 54/3/33 55/4/33
f 9/2/33 43/3/33 44/4/33
f 30/2/33 64/3/33 65/4/33
f 19/2/33 53/3/33 54/4/33
f 8/2/33 42/3/33 43/4/33
f 29/2/33 63/3/33 64/4/33
f 18/2/33 52/3/33 53/4/33
f 2/2/33 36/3/33 37/4/33
f 7/2/33 41/3/33 42/4/33
f 28/2/33 62/3/33 63/4/33
f 6/2/33 40/3/33 41/4/33
f 17/2/33 51/3/33 52/4/33
f 27/2/33 61/3/33 62/4/33
f 5/2/33 39/3/33 40/4/33
f 16/2/67 50/3/67 51/4/67
f 26/2/33 60/3/33 61/4/33
f 4/2/33 38/3/33 39/4/33
f 15/2/33 49/3/33 50/4/33
f 25/2/33 59/3/33 60/4/33
f 3/2/33 37/3/33 38/4/33
f 14/2/33 48/3/33 49/4/33
f 24/2/33 58/3/33 59/4/33
f 13/2/33 47/3/33 48/4/33
f 86/6/33 87/8/33 80/7/33
f 87/8/33 94/9/33 80/7/33
f 94/9/33 95/10/33 80/7/33
f 95/10/68 98/11/68 80/7/68
f 98/11/69 72/12/69 80/7/69
f 72/12/70 73/13/70 80/7/70
f 73/13/33 76/14/33 80/7/33
f 76/14/33 77/15/33 80/7/33
f 77/15/33 82/16/33 80/7/33
f 82/16/33 83/17/33 80/7/33
f 83/17/33 88/18/33 80/7/33
f 88/18/33 89/19/33 80/7/33
f 89/19/33 92/20/33 93/21/33
f 80/7/71 89/19/71 93/21/71
f 75/22/33 80/7/33 93/21/33
f 74/23/33 75/22/33 93/21/33
f 69/24/33 74/23/33 93/21/33
f 71/25/72 97/26/72 70/27/72
f 71/25/73 93/21/73 97/26/73
f 99/28/74 93/21/74 71/25/74
f 78/29/33 93/21/33 99/28/33
f 79/30/33 93/21/33 78/29/33
f 85/31/73 79/30/73 84/32/73
f 85/31/33 93/21/33 79/30/33
f 91/33/75 85/31/75 90/34/75
f 91/33/33 93/21/33 85/31/33
f 96/35/33 68/36/33 91/33/33
f 68/36/76 69/24/76 93/21/76
f 91/33/77 68/36/77 93/21/77
f 50/2/35 98/3/35 95/4/35
f 51/2/78 95/3/78 94/4/78
f 39/2/37 97/3/37 93/4/37
f 40/2/79 93/3/79 92/4/79
f 61/2/39 96/3/39 91/4/39
f 62/2/40 91/3/40 90/4/40
f 41/2/80 92/3/80 89/4/80
f 42/2/42 89/3/42 88/4/42
f 52/2/43 94/3/43 87/4/43
f 53/2/44 87/3/44 86/4/44
f 63/2/81 90/3/81 85/4/81
f 64/2/46 85/3/46 84/4/46
f 43/2/47 88/3/47 83/4/47
f 44/2/48 83/3/48 82/4/48
f 54/2/49 86/3/49 81/4/49
f 55/2/50 81/3/50 80/4/50
f 65/2/51 84/3/51 79/4/51
f 66/2/52 79/3/52 78/4/52
f 67/2/82 78/3/82 99/4/82
f 45/2/54 82/3/54 77/4/54
f 46/2/55 77/3/55 76/4/55
f 56/2/56 80/3/56 75/4/56
f 57/2/57 75/3/57 74/4/57
f 47/2/58 76/3/58 73/4/58
f 48/2/83 73/3/83 72/4/83
f 49/2/60 72/3/60 98/4/60
f 36/2/84 99/3/84 71/4/84
f 37/2/85 71/3/85 70/4/85
f 38/2/63 70/3/63 97/4/63
f 58/2/64 74/3/64 69/4/64
f 59/2/65 69/3/65 68/4/65
f 60/2/66 68/3/66 96/4/66

View file

@ -0,0 +1,251 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on 2019/10/4
@author: Irony
@site: https://pyqt5.com , https://github.com/892768447
@email: 892768447@qq.com
@file: MagneticOfSun
@description:
"""
#############################################################################
##
## Copyright (C) 2014 Riverbank Computing Limited.
## Copyright (C) 2014 Digia Plc
## All rights reserved.
## For any questions to Digia, please use contact form at http://qt.digia.com
##
## This file is part of the QtDataVisualization module.
##
## Licensees holding valid Qt Enterprise licenses may use this file in
## accordance with the Qt Enterprise License Agreement provided with the
## Software or, alternatively, in accordance with the terms contained in
## a written agreement between you and Digia.
##
## If you have questions regarding the use of this file, please use
## contact form at http://qt.digia.com
##
#############################################################################
import math
from PyQt5.QtCore import QFileInfo, QObject, QSize, Qt, QTimer, QLocale
from PyQt5.QtDataVisualization import (Q3DCamera, Q3DScatter, Q3DTheme,
QAbstract3DGraph, QAbstract3DSeries, QScatter3DSeries,
QScatterDataItem)
from PyQt5.QtGui import QColor, QLinearGradient, QQuaternion, QVector3D
from PyQt5.QtWidgets import (QApplication, QHBoxLayout, QLabel, QPushButton,
QSlider, QSizePolicy, QVBoxLayout, QWidget)
country = QLocale.system().country()
if country in (QLocale.China, QLocale.HongKong, QLocale.Taiwan):
Tr = {
'Item rotations example - Magnetic field of the sun': '项目旋转示例-太阳磁场',
'Toggle animation': '开启/关闭 动画',
'Toggle Sun': '显示/隐藏 太阳',
'Field Lines (1 - 128):': '磁场线条数(1 - 128)',
'Arrows per line (8 - 32):': '箭头数(8 - 32)'
}
else:
Tr = {}
class ScatterDataModifier(QObject):
verticalRange = 8.0
horizontalRange = verticalRange
ellipse_a = horizontalRange / 3.0
ellipse_b = verticalRange
doublePi = math.pi * 2.0
radiansToDegrees = 360.0 / doublePi
animationFrames = 30.0 # 动画帧数
def __init__(self, scatter):
super(ScatterDataModifier, self).__init__()
mesh_dir = QFileInfo(__file__).absolutePath() + '/Data/mesh'
self.m_graph = scatter # Q3DScatter 对象实例
self.m_rotationTimer = QTimer()
self.m_fieldLines = 12 # 初始磁场线数量
self.m_arrowsPerLine = 16 # 初始箭头数
self.m_magneticField = QScatter3DSeries() # 磁场线三维散点图
self.m_sun = QScatter3DSeries() # 太阳三维散点图
self.m_angleOffset = 0.0 # 角度偏移
self.m_angleStep = self.doublePi / self.m_arrowsPerLine / self.animationFrames
# 设置阴影质量
self.m_graph.setShadowQuality(QAbstract3DGraph.ShadowQualityNone)
# 设置当前场景中的激活的相机预设值
self.m_graph.scene().activeCamera().setCameraPreset(
Q3DCamera.CameraPresetFront)
# Magnetic field lines use custom narrow arrow.
# 磁力线使用自定义窄箭头。
self.m_magneticField.setItemSize(0.2)
self.m_magneticField.setMesh(QAbstract3DSeries.MeshUserDefined)
self.m_magneticField.setUserDefinedMesh(mesh_dir + '/narrowarrow.obj')
# 设置渐变颜色
fieldGradient = QLinearGradient(0, 0, 16, 1024)
fieldGradient.setColorAt(0.0, Qt.black)
fieldGradient.setColorAt(1.0, Qt.white)
self.m_magneticField.setBaseGradient(fieldGradient)
self.m_magneticField.setColorStyle(Q3DTheme.ColorStyleRangeGradient)
# For 'sun' we use a custom large sphere.
# 使用一个自定义的球体代表太阳
self.m_sun.setItemSize(0.2)
self.m_sun.setName("Sun")
self.m_sun.setItemLabelFormat("@seriesName")
self.m_sun.setMesh(QAbstract3DSeries.MeshUserDefined)
self.m_sun.setUserDefinedMesh(mesh_dir + '/largesphere.obj')
self.m_sun.setBaseColor(QColor(0xff, 0xbb, 0x00))
self.m_sun.dataProxy().addItem(QScatterDataItem(QVector3D()))
self.m_graph.addSeries(self.m_magneticField)
self.m_graph.addSeries(self.m_sun)
# Configure the axes according to the data.
# 设置x轴的范围值
self.m_graph.axisX().setRange(-self.horizontalRange,
self.horizontalRange)
# 设置y轴的范围值
self.m_graph.axisY().setRange(-self.verticalRange, self.verticalRange)
# 设置z轴的范围值
self.m_graph.axisZ().setRange(-self.horizontalRange,
self.horizontalRange)
# x和z轴上的段数
# 这表明绘制了多少标签。要绘制的网格线的数量使用公式计算segments * subsegments + 1。预设默认值为5。该值不能低于1。
self.m_graph.axisX().setSegmentCount(self.horizontalRange)
self.m_graph.axisZ().setSegmentCount(self.horizontalRange)
self.m_rotationTimer.timeout.connect(self.triggerRotation)
self.toggleRotation()
self.generateData()
def generateData(self):
# 生成模拟数据
magneticFieldArray = []
for i in range(self.m_fieldLines):
horizontalAngle = (self.doublePi * i) / self.m_fieldLines
xCenter = self.ellipse_a * math.cos(horizontalAngle)
zCenter = self.ellipse_a * math.sin(horizontalAngle)
# Rotate - arrow is always tangential to the origin.
# 旋转-箭头始终与原点相切。
yRotation = QQuaternion.fromAxisAndAngle(0.0, 1.0, 0.0,
horizontalAngle * self.radiansToDegrees)
for j in range(self.m_arrowsPerLine):
# Calculate the point on the ellipse centered on the origin and
# 计算椭圆上以原点为中心的点
# parallel to the x-axis.
# 平行于X轴。
verticalAngle = ((self.doublePi * j) / self.m_arrowsPerLine) + self.m_angleOffset
xUnrotated = self.ellipse_a * math.cos(verticalAngle)
y = self.ellipse_b * math.sin(verticalAngle)
# Rotate the ellipse around the y-axis.
# 围绕Y轴旋转椭圆。
xRotated = xUnrotated * math.cos(horizontalAngle)
zRotated = xUnrotated * math.sin(horizontalAngle)
# Add the offset.
# 添加偏移量。
x = xCenter + xRotated
z = zCenter + zRotated
zRotation = QQuaternion.fromAxisAndAngle(0.0, 0.0, 1.0,
verticalAngle * self.radiansToDegrees)
totalRotation = yRotation * zRotation
itm = QScatterDataItem(QVector3D(x, y, z), totalRotation)
magneticFieldArray.append(itm)
if self.m_graph.selectedSeries() is self.m_magneticField:
self.m_graph.clearSelection()
self.m_magneticField.dataProxy().resetArray(magneticFieldArray)
def setFieldLines(self, lines):
self.m_fieldLines = lines
self.generateData()
def setArrowsPerLine(self, arrows):
self.m_arrowsPerLine = arrows
self.m_angleOffset = 0.0
self.m_angleStep = self.doublePi / self.m_arrowsPerLine / self.animationFrames
self.generateData()
def triggerRotation(self):
self.m_angleOffset += self.m_angleStep
self.generateData()
def toggleSun(self):
self.m_sun.setVisible(not self.m_graph.seriesList()[1].isVisible())
def toggleRotation(self):
if self.m_rotationTimer.isActive():
self.m_rotationTimer.stop()
else:
self.m_rotationTimer.start(15)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
graph = Q3DScatter()
container = QWidget.createWindowContainer(graph)
screenSize = graph.screen().size()
container.setMinimumSize(
QSize(screenSize.width() / 2, screenSize.height() / 1.5))
container.setMaximumSize(screenSize)
container.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
container.setFocusPolicy(Qt.StrongFocus)
widget = QWidget()
hLayout = QHBoxLayout(widget)
vLayout = QVBoxLayout()
hLayout.addWidget(container, 1)
hLayout.addLayout(vLayout)
widget.setWindowTitle(Tr.get("Item rotations example - Magnetic field of the sun",
"Item rotations example - Magnetic field of the sun"))
toggleRotationButton = QPushButton(Tr.get("Toggle animation", "Toggle animation"))
toggleSunButton = QPushButton(Tr.get("Toggle Sun", "Toggle Sun"))
fieldLinesSlider = QSlider(Qt.Horizontal)
fieldLinesSlider.setTickInterval(1)
fieldLinesSlider.setMinimum(1)
fieldLinesSlider.setValue(12)
fieldLinesSlider.setMaximum(128)
arrowsSlider = QSlider(Qt.Horizontal)
arrowsSlider.setTickInterval(1)
arrowsSlider.setMinimum(8)
arrowsSlider.setValue(16)
arrowsSlider.setMaximum(32)
vLayout.addWidget(toggleRotationButton)
vLayout.addWidget(toggleSunButton)
vLayout.addWidget(QLabel(Tr.get("Field Lines (1 - 128):", "Field Lines (1 - 128):")))
vLayout.addWidget(fieldLinesSlider)
vLayout.addWidget(QLabel(Tr.get("Arrows per line (8 - 32):", "Arrows per line (8 - 32):")))
vLayout.addWidget(arrowsSlider, 1, Qt.AlignTop)
modifier = ScatterDataModifier(graph)
toggleRotationButton.clicked.connect(modifier.toggleRotation)
toggleSunButton.clicked.connect(modifier.toggleSun)
fieldLinesSlider.valueChanged.connect(modifier.setFieldLines)
arrowsSlider.valueChanged.connect(modifier.setArrowsPerLine)
widget.show()
sys.exit(app.exec_())

View file

@ -2,8 +2,20 @@
- 目录 - 目录
- [柱状图3D](#1柱状图3D) - [柱状图3D](#1柱状图3D)
- [太阳磁场线](#2太阳磁场线)
- [余弦波3D](#3余弦波3D)
## 1、柱状图3D ## 1、柱状图3D
[运行 BarsVisualization.py](BarsVisualization.py) [运行 BarsVisualization.py](BarsVisualization.py)
![BarsVisualization](ScreenShot/BarsVisualization.gif) ![BarsVisualization](ScreenShot/BarsVisualization.gif)
## 2、太阳磁场线
[运行 MagneticOfSun.py](MagneticOfSun.py)
![MagneticOfSun](ScreenShot/MagneticOfSun.gif)
## 3、余弦波3D
[运行 ScatterVisualization.py](ScatterVisualization.py)
![ScatterVisualization](ScreenShot/ScatterVisualization.gif)

View file

@ -0,0 +1,295 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on 2019/10/4
@author: Irony
@site: https://pyqt5.com , https://github.com/892768447
@email: 892768447@qq.com
@file: ScatterVisualization
@description:
"""
#############################################################################
##
## Copyright (C) 2014 Riverbank Computing Limited.
## Copyright (C) 2014 Digia Plc
## All rights reserved.
## For any questions to Digia, please use contact form at http://qt.digia.com
##
## This file is part of the QtDataVisualization module.
##
## Licensees holding valid Qt Enterprise licenses may use this file in
## accordance with the Qt Enterprise License Agreement provided with the
## Software or, alternatively, in accordance with the terms contained in
## a written agreement between you and Digia.
##
## If you have questions regarding the use of this file, please use
## contact form at http://qt.digia.com
##
#############################################################################
import math
from PyQt5.QtCore import pyqtSignal, QObject, QSize, Qt, QLocale
from PyQt5.QtDataVisualization import (Q3DCamera, Q3DTheme, Q3DScatter,
QAbstract3DGraph, QAbstract3DSeries, QScatter3DSeries,
QScatterDataItem, QScatterDataProxy)
from PyQt5.QtGui import QFont, QVector3D
from PyQt5.QtWidgets import (QApplication, QCheckBox, QComboBox, QFontComboBox,
QHBoxLayout, QLabel, QPushButton, QSizePolicy, QVBoxLayout, QWidget)
country = QLocale.system().country()
if country in (QLocale.China, QLocale.HongKong, QLocale.Taiwan):
Tr = {
'A Cosine Wave': '余弦波',
'Change label style': '更改label样式',
'Smooth dots': '平滑圆点',
'Change camera preset': '更改相机预设',
'Show background': '显示背景',
'Show grid': '显示网格',
'Change dot style': '更改点样式',
'Change theme': '更改主题',
'Adjust shadow quality': '调整阴影质量',
'Change font': '更改字体'
}
else:
Tr = {}
class ScatterDataModifier(QObject):
numberOfItems = 3600
curveDivider = 3.0
lowerNumberOfItems = 900
lowerCurveDivider = 0.75
backgroundEnabledChanged = pyqtSignal(bool)
gridEnabledChanged = pyqtSignal(bool)
shadowQualityChanged = pyqtSignal(int)
fontChanged = pyqtSignal(QFont)
def __init__(self, scatter):
super(ScatterDataModifier, self).__init__()
self.m_graph = scatter # Q3DScatter实例
self.m_fontSize = 40.0
self.m_style = QAbstract3DSeries.MeshSphere
self.m_smooth = True
self.m_itemCount = self.lowerNumberOfItems
self.m_curveDivider = self.lowerCurveDivider
# 设置当前主题类型
self.m_graph.activeTheme().setType(Q3DTheme.ThemeEbony)
# 设置当前主题的字体
font = self.m_graph.activeTheme().font()
font.setPointSize(self.m_fontSize)
self.m_graph.activeTheme().setFont(font)
# 设置阴影质量
self.m_graph.setShadowQuality(QAbstract3DGraph.ShadowQualitySoftLow)
self.m_graph.scene().activeCamera().setCameraPreset(
Q3DCamera.CameraPresetFront)
proxy = QScatterDataProxy()
series = QScatter3DSeries(proxy)
series.setItemLabelFormat(
"@xTitle: @xLabel @yTitle: @yLabel @zTitle: @zLabel")
series.setMeshSmooth(self.m_smooth)
self.m_graph.addSeries(series)
self.addData()
def addData(self):
# 添加数据
self.m_graph.axisX().setTitle("X")
self.m_graph.axisY().setTitle("Y")
self.m_graph.axisZ().setTitle("Z")
dataArray = []
limit = math.sqrt(self.m_itemCount) / 2.0
i = -limit
while i < limit:
j = -limit
while j < limit:
itm = QScatterDataItem(
QVector3D(i + 0.5,
math.cos(
math.radians((i * j) / self.m_curveDivider)),
j + 0.5))
dataArray.append(itm)
j += 1.0
i += 1.0
self.m_graph.seriesList()[0].dataProxy().resetArray(dataArray)
def changeStyle(self, style):
comboBox = self.sender()
if isinstance(comboBox, QComboBox):
self.m_style = QAbstract3DSeries.Mesh(comboBox.itemData(style))
self.m_graph.seriesList()[0].setMesh(self.m_style)
def setSmoothDots(self, smooth):
self.m_smooth = bool(smooth)
self.m_graph.seriesList()[0].setMeshSmooth(self.m_smooth)
def changeTheme(self, theme):
currentTheme = self.m_graph.activeTheme()
currentTheme.setType(Q3DTheme.Theme(theme))
self.backgroundEnabledChanged.emit(currentTheme.isBackgroundEnabled())
self.gridEnabledChanged.emit(currentTheme.isGridEnabled())
self.fontChanged.emit(currentTheme.font())
preset = int(Q3DCamera.CameraPresetFrontLow)
def changePresetCamera(self):
self.m_graph.scene().activeCamera().setCameraPreset(
Q3DCamera.CameraPreset(self.preset))
self.preset += 1
if self.preset > Q3DCamera.CameraPresetDirectlyBelow:
self.preset = int(Q3DCamera.CameraPresetFrontLow)
def changeLabelStyle(self):
self.m_graph.activeTheme().setLabelBackgroundEnabled(
not self.m_graph.activeTheme().isLabelBackgroundEnabled())
def changeFont(self, font):
newFont = QFont(font)
newFont.setPointSizeF(self.m_fontSize)
self.m_graph.activeTheme().setFont(newFont)
def shadowQualityUpdatedByVisual(self, sq):
self.shadowQualityChanged.emit(int(sq))
def changeShadowQuality(self, quality):
sq = QAbstract3DGraph.ShadowQuality(quality)
self.m_graph.setShadowQuality(sq)
def setBackgroundEnabled(self, enabled):
self.m_graph.activeTheme().setBackgroundEnabled(enabled)
def setGridEnabled(self, enabled):
self.m_graph.activeTheme().setGridEnabled(enabled)
def toggleItemCount(self):
if self.m_itemCount == self.numberOfItems:
self.m_itemCount = self.lowerNumberOfItems
self.m_curveDivider = self.lowerCurveDivider
else:
self.m_itemCount = self.numberOfItems
self.m_curveDivider = self.curveDivider
self.m_graph.seriesList()[0].dataProxy().resetArray(None)
self.addData()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
graph = Q3DScatter()
container = QWidget.createWindowContainer(graph)
screenSize = graph.screen().size()
container.setMinimumSize(
QSize(screenSize.width() / 2, screenSize.height() / 1.5))
container.setMaximumSize(screenSize)
container.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
container.setFocusPolicy(Qt.StrongFocus)
widget = QWidget()
hLayout = QHBoxLayout(widget)
vLayout = QVBoxLayout()
hLayout.addWidget(container, 1)
hLayout.addLayout(vLayout)
widget.setWindowTitle(Tr.get("A Cosine Wave", "A Cosine Wave"))
themeList = QComboBox()
themeList.addItem("Qt")
themeList.addItem("Primary Colors")
themeList.addItem("Digia")
themeList.addItem("Stone Moss")
themeList.addItem("Army Blue")
themeList.addItem("Retro")
themeList.addItem("Ebony")
themeList.addItem("Isabelle")
themeList.setCurrentIndex(6)
labelButton = QPushButton(Tr.get("Change label style", "Change label style"))
smoothCheckBox = QCheckBox(Tr.get("Smooth dots", "Smooth dots"), checked=True)
itemStyleList = QComboBox()
itemStyleList.addItem("Sphere", QAbstract3DSeries.MeshSphere)
itemStyleList.addItem("Cube", QAbstract3DSeries.MeshCube)
itemStyleList.addItem("Minimal", QAbstract3DSeries.MeshMinimal)
itemStyleList.addItem("Point", QAbstract3DSeries.MeshPoint)
itemStyleList.setCurrentIndex(0)
cameraButton = QPushButton(Tr.get("Change camera preset", "Change camera preset"))
itemCountButton = QPushButton(Tr.get("Toggle item count", "Toggle item count"))
backgroundCheckBox = QCheckBox(Tr.get("Show background", "Show background"), checked=True)
gridCheckBox = QCheckBox(Tr.get("Show grid", "Show grid"), checked=True)
shadowQuality = QComboBox()
shadowQuality.addItem("None")
shadowQuality.addItem("Low")
shadowQuality.addItem("Medium")
shadowQuality.addItem("High")
shadowQuality.addItem("Low Soft")
shadowQuality.addItem("Medium Soft")
shadowQuality.addItem("High Soft")
shadowQuality.setCurrentIndex(4)
fontList = QFontComboBox()
fontList.setCurrentFont(QFont('Arial'))
vLayout.addWidget(labelButton, 0, Qt.AlignTop)
vLayout.addWidget(cameraButton, 0, Qt.AlignTop)
vLayout.addWidget(itemCountButton, 0, Qt.AlignTop)
vLayout.addWidget(backgroundCheckBox)
vLayout.addWidget(gridCheckBox)
vLayout.addWidget(smoothCheckBox, 0, Qt.AlignTop)
vLayout.addWidget(QLabel(Tr.get("Change dot style", "Change dot style")))
vLayout.addWidget(itemStyleList)
vLayout.addWidget(QLabel(Tr.get("Change theme", "Change theme")))
vLayout.addWidget(themeList)
vLayout.addWidget(QLabel(Tr.get("Adjust shadow quality", "Adjust shadow quality")))
vLayout.addWidget(shadowQuality)
vLayout.addWidget(QLabel(Tr.get("Change font", "Change font")))
vLayout.addWidget(fontList, 1, Qt.AlignTop)
modifier = ScatterDataModifier(graph)
cameraButton.clicked.connect(modifier.changePresetCamera)
labelButton.clicked.connect(modifier.changeLabelStyle)
itemCountButton.clicked.connect(modifier.toggleItemCount)
backgroundCheckBox.stateChanged.connect(modifier.setBackgroundEnabled)
gridCheckBox.stateChanged.connect(modifier.setGridEnabled)
smoothCheckBox.stateChanged.connect(modifier.setSmoothDots)
modifier.backgroundEnabledChanged.connect(backgroundCheckBox.setChecked)
modifier.gridEnabledChanged.connect(gridCheckBox.setChecked)
itemStyleList.currentIndexChanged.connect(modifier.changeStyle)
themeList.currentIndexChanged.connect(modifier.changeTheme)
shadowQuality.currentIndexChanged.connect(modifier.changeShadowQuality)
modifier.shadowQualityChanged.connect(shadowQuality.setCurrentIndex)
graph.shadowQualityChanged.connect(modifier.shadowQualityUpdatedByVisual)
fontList.currentFontChanged.connect(modifier.changeFont)
modifier.fontChanged.connect(fontList.setCurrentFont)
widget.show()
sys.exit(app.exec_())

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

View file

@ -170,6 +170,8 @@ https://pyqt5.com 社区是专门针对PyQt5学习和提升开设的博客网站
- [QtDataVisualization](QtDataVisualization) - [QtDataVisualization](QtDataVisualization)
- [柱状图3D](QtDataVisualization/BarsVisualization.py) - [柱状图3D](QtDataVisualization/BarsVisualization.py)
- [太阳磁场线](QtDataVisualization/MagneticOfSun.py)
- [余弦波3D](QtDataVisualization/ScatterVisualization.py)
- [PyQtGraph](PyQtGraph) - [PyQtGraph](PyQtGraph)
- [鼠标获取X轴坐标](PyQtGraph/mouseFlow.py) - [鼠标获取X轴坐标](PyQtGraph/mouseFlow.py)