PySide6Plot 0.0.1__tar.gz → 0.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PKG-INFO +1 -1
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/libs/data_handler.py +3 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/libs/plot_item.py +84 -9
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/libs/style.py +36 -2
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/widgets/q_plot_widget.py +1 -1
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot.egg-info/PKG-INFO +1 -1
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot.egg-info/SOURCES.txt +1 -0
- pyside6plot-0.0.2/examples/qplotwidget_line_plot.py +43 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/.gitignore +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/__init__.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/compoents/__init__.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/compoents/average_line.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/compoents/draw_line.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/compoents/frame_recorder.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/compoents/zoom_move.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/libs/__init__.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/libs/constant.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/libs/helpers.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/resources/icons/ChevronLeft_black.svg +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/resources/icons/ChevronLeft_white.svg +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/resources/qss/dark/navigation_view_interface.qss +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/resources/qss/light/navigation_view_interface.qss +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/widgets/__init__.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/widgets/colorful_toggle_button.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/widgets/fluent_scroller.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/widgets/line_card.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/widgets/navigation_widget.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/widgets/removable_table.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/widgets/transparent_Line_edit.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/widgets/transparent_selector.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/widgets/value_select_box.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/widgets/zoom_bar.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot.egg-info/dependency_links.txt +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot.egg-info/requires.txt +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot.egg-info/top_level.txt +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/README.md +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/examples/price_volume_plotter.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/examples/sample_stock_data.h5 +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/examples/single_plotter.py +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/pyproject.toml +0 -0
- {pyside6plot-0.0.1 → pyside6plot-0.0.2}/setup.cfg +0 -0
|
@@ -38,6 +38,9 @@ class ChildDataFrame:
|
|
|
38
38
|
min_y_key (str, optional): The key to access the minimum y-value data. Defaults to None.
|
|
39
39
|
x_label_key (str, optional): The key to access the x-label data. Defaults to None.
|
|
40
40
|
"""
|
|
41
|
+
if "date" not in data_frame.columns:
|
|
42
|
+
if isinstance(data_frame.index, pd.DatetimeIndex):
|
|
43
|
+
data_frame.reset_index(inplace=True, drop=False)
|
|
41
44
|
data_keys = data_keys if isinstance(data_keys, list) else [data_keys]
|
|
42
45
|
self.data_keys = deepcopy(data_keys)
|
|
43
46
|
if max_y_key is not None:
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from pyqtgraph import QtGui, QtCore
|
|
2
2
|
import pyqtgraph as pg
|
|
3
|
-
from abc import
|
|
3
|
+
from abc import abstractmethod
|
|
4
4
|
import numpy as np
|
|
5
|
-
from .style import DEFAULT_STYLE
|
|
5
|
+
from .style import DEFAULT_STYLE, LINE_DEFAULT_STYLE
|
|
6
6
|
from .data_handler import ChildDataFrame, PricesDataFrame, VolumeDataFrame
|
|
7
7
|
|
|
8
8
|
|
|
@@ -37,8 +37,8 @@ class AdaptiveGraphObject(pg.GraphicsObject):
|
|
|
37
37
|
super().__init__()
|
|
38
38
|
self.style = None
|
|
39
39
|
|
|
40
|
-
@
|
|
41
|
-
def get_local_plot_range(x_start, x_end):
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def get_local_plot_range(self, x_start, x_end):
|
|
42
42
|
"""
|
|
43
43
|
Abstract method to get the local plot range for the graph object.
|
|
44
44
|
|
|
@@ -51,8 +51,8 @@ class AdaptiveGraphObject(pg.GraphicsObject):
|
|
|
51
51
|
"""
|
|
52
52
|
raise NotImplementedError
|
|
53
53
|
|
|
54
|
-
@
|
|
55
|
-
def get_x_ticks():
|
|
54
|
+
@abstractmethod
|
|
55
|
+
def get_x_ticks(self):
|
|
56
56
|
"""
|
|
57
57
|
Abstract method to get the x-axis ticks for the graph object.
|
|
58
58
|
|
|
@@ -61,8 +61,8 @@ class AdaptiveGraphObject(pg.GraphicsObject):
|
|
|
61
61
|
"""
|
|
62
62
|
raise NotImplementedError
|
|
63
63
|
|
|
64
|
-
@
|
|
65
|
-
def get_feature_value(key):
|
|
64
|
+
@abstractmethod
|
|
65
|
+
def get_feature_value(self, key):
|
|
66
66
|
"""
|
|
67
67
|
Abstract method to get the value of a specific feature for the graph object.
|
|
68
68
|
|
|
@@ -223,7 +223,7 @@ class CandlestickVolumeItem(AdaptiveGraphObject):
|
|
|
223
223
|
"""
|
|
224
224
|
return self.data.get_x_ticks()
|
|
225
225
|
|
|
226
|
-
def get_feature_value(self):
|
|
226
|
+
def get_feature_value(self, key=None):
|
|
227
227
|
"""
|
|
228
228
|
Get the feature values for the volume item.
|
|
229
229
|
|
|
@@ -231,3 +231,78 @@ class CandlestickVolumeItem(AdaptiveGraphObject):
|
|
|
231
231
|
numpy.ndarray: An array of feature values.
|
|
232
232
|
"""
|
|
233
233
|
return np.asarray([data[1] / 1e8 for data in self.data])
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def draw_circle_marker(p, canvas_pt, marker_size):
|
|
237
|
+
"""
|
|
238
|
+
Draws a circle marker at the specified canvas point.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
p (QPainter): The painter object used for drawing.
|
|
242
|
+
canvas_pt (QPointF): The point where the marker should be drawn.
|
|
243
|
+
marker_size (float): The size of the marker.
|
|
244
|
+
"""
|
|
245
|
+
p.drawEllipse(canvas_pt, marker_size, marker_size)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class LinePlotItem(AdaptiveGraphObject):
|
|
249
|
+
"""
|
|
250
|
+
A class representing a line plot item for displaying data.
|
|
251
|
+
|
|
252
|
+
Attributes:
|
|
253
|
+
data (ChildDataFrame): The data containing the values to be plotted.
|
|
254
|
+
style (Style, optional): The style of the line plot item. Defaults to DEFAULT_STYLE.
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
MARKER_DRAWER = {"circle": draw_circle_marker, "o": draw_circle_marker}
|
|
258
|
+
|
|
259
|
+
def __init__(self, data: ChildDataFrame, style=LINE_DEFAULT_STYLE, marker=None):
|
|
260
|
+
super().__init__()
|
|
261
|
+
self.data = data
|
|
262
|
+
self.style = style
|
|
263
|
+
self.marker_drawer = self.MARKER_DRAWER.get(marker, None)
|
|
264
|
+
self.picture = QtGui.QPicture()
|
|
265
|
+
p = QtGui.QPainter(self.picture)
|
|
266
|
+
p.setPen(pg.mkPen(self.style.line_color, width=self.style.line_width))
|
|
267
|
+
x = data.data_frame.index.to_numpy()
|
|
268
|
+
for data_key in data.data_keys:
|
|
269
|
+
if data_key not in data.data_frame.columns:
|
|
270
|
+
raise ValueError(f"Data key '{data_key}' not found in data frame.")
|
|
271
|
+
y = data.data_frame[data_key].to_numpy()
|
|
272
|
+
p.drawPolyline(QtGui.QPolygonF([QtCore.QPointF(x[i], y[i]) for i in range(len(x))]))
|
|
273
|
+
p.end()
|
|
274
|
+
|
|
275
|
+
def paint(self, p, *args):
|
|
276
|
+
p.drawPicture(0, 0, self.picture)
|
|
277
|
+
if self.marker_drawer is not None:
|
|
278
|
+
transform = p.transform()
|
|
279
|
+
# Set marker color
|
|
280
|
+
p.setPen(pg.mkPen(self.style.marker_color, width=self.style.line_width))
|
|
281
|
+
p.setBrush(pg.mkBrush(self.style.marker_color))
|
|
282
|
+
marker_size = self.style.marker_size / 2
|
|
283
|
+
x = self.data.data_frame.index.to_numpy()
|
|
284
|
+
# Reset transformation to canvas transform, so marker is unaffected by data scaling.
|
|
285
|
+
p.resetTransform()
|
|
286
|
+
for data_key in self.data.data_keys:
|
|
287
|
+
if data_key not in self.data.data_frame.columns:
|
|
288
|
+
continue
|
|
289
|
+
y = self.data.data_frame[data_key].to_numpy()
|
|
290
|
+
for i in range(len(x)):
|
|
291
|
+
# Map data point to canvas coordinate.
|
|
292
|
+
data_pt = QtCore.QPointF(x[i], y[i])
|
|
293
|
+
canvas_pt = transform.map(data_pt)
|
|
294
|
+
self.marker_drawer(p, canvas_pt, marker_size)
|
|
295
|
+
# Restore the original transformation
|
|
296
|
+
p.setTransform(transform)
|
|
297
|
+
|
|
298
|
+
def boundingRect(self):
|
|
299
|
+
return QtCore.QRectF(self.picture.boundingRect())
|
|
300
|
+
|
|
301
|
+
def get_local_plot_range(self, x_start, x_end):
|
|
302
|
+
return self.data.get_local_range(x_start, x_end)
|
|
303
|
+
|
|
304
|
+
def get_x_ticks(self):
|
|
305
|
+
return self.data.get_x_ticks()
|
|
306
|
+
|
|
307
|
+
def get_feature_value(self, key=None):
|
|
308
|
+
return self.data.get_feature_value(key)
|
|
@@ -72,8 +72,41 @@ def default_style_configs() -> ConfigurationsHandler:
|
|
|
72
72
|
return configs_handler
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
def
|
|
76
|
-
configs_handler =
|
|
75
|
+
def line_style_configs() -> ConfigurationsHandler:
|
|
76
|
+
configs_handler = ConfigurationsHandler()
|
|
77
|
+
configs_handler.add_config_item(
|
|
78
|
+
"line_color",
|
|
79
|
+
default_value=(255, 0, 0),
|
|
80
|
+
value_type=tuple,
|
|
81
|
+
in_func=lambda x, other_config: tuple_to_color(x),
|
|
82
|
+
out_func=lambda x, other_config: color_to_rbg_tuple(x),
|
|
83
|
+
description="color of the line",
|
|
84
|
+
)
|
|
85
|
+
configs_handler.add_config_item(
|
|
86
|
+
"line_width",
|
|
87
|
+
default_value=2.0,
|
|
88
|
+
value_type=float,
|
|
89
|
+
description="width of the line, the unit is pixel",
|
|
90
|
+
)
|
|
91
|
+
configs_handler.add_config_item(
|
|
92
|
+
"marker_color",
|
|
93
|
+
default_value=(255, 0, 0),
|
|
94
|
+
value_type=tuple,
|
|
95
|
+
in_func=lambda x, other_config: tuple_to_color(x),
|
|
96
|
+
out_func=lambda x, other_config: color_to_rbg_tuple(x),
|
|
97
|
+
description="color of the marker",
|
|
98
|
+
)
|
|
99
|
+
configs_handler.add_config_item(
|
|
100
|
+
"marker_size",
|
|
101
|
+
default_value=5.0,
|
|
102
|
+
value_type=float,
|
|
103
|
+
description="size of the marker",
|
|
104
|
+
)
|
|
105
|
+
return configs_handler
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def make_style(configs_handler=None, style_yaml_file="", **kwargs):
|
|
109
|
+
configs_handler = configs_handler or default_style_configs()
|
|
77
110
|
if style_yaml_file != "":
|
|
78
111
|
configs_handler.set_config_items_from_yaml(style_yaml_file)
|
|
79
112
|
configs_handler.set_config_items(**kwargs)
|
|
@@ -117,3 +150,4 @@ def set_background_with_theme(widget: QWidget, theme=None):
|
|
|
117
150
|
|
|
118
151
|
|
|
119
152
|
DEFAULT_STYLE = make_style()
|
|
153
|
+
LINE_DEFAULT_STYLE = make_style(configs_handler=line_style_configs(), line_color=(255, 0, 0))
|
|
@@ -98,7 +98,7 @@ class CustomizedAxis(AxisItem):
|
|
|
98
98
|
if self.plot_strs is None:
|
|
99
99
|
return f"{value:.1f}"
|
|
100
100
|
else:
|
|
101
|
-
if
|
|
101
|
+
if self.min_index <= value <= self.max_index:
|
|
102
102
|
return self.plot_strs[round(value)]
|
|
103
103
|
else:
|
|
104
104
|
return " "
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# @Time : 2025/7/16 21:43
|
|
2
|
+
# @Author : YQ Tsui
|
|
3
|
+
# @File : qplotwidget_line_plot.py
|
|
4
|
+
# @Purpose :
|
|
5
|
+
from PySide6Plot import QStockPlotter
|
|
6
|
+
from PySide6Plot.libs.data_handler import ChildDataFrame
|
|
7
|
+
from PySide6Plot.libs.plot_item import LinePlotItem
|
|
8
|
+
import numpy as np
|
|
9
|
+
import pandas as pd
|
|
10
|
+
|
|
11
|
+
if __name__ == "__main__":
|
|
12
|
+
from PySide6.QtWidgets import QApplication, QVBoxLayout, QWidget
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
app = QApplication(sys.argv)
|
|
16
|
+
|
|
17
|
+
# Create a main window
|
|
18
|
+
main_window = QWidget()
|
|
19
|
+
main_window.setWindowTitle("Line Plot Example")
|
|
20
|
+
main_window.setGeometry(100, 100, 800, 600)
|
|
21
|
+
|
|
22
|
+
# Create a QPlotWidget instance
|
|
23
|
+
plot_widget = QStockPlotter()
|
|
24
|
+
|
|
25
|
+
# Add some sample data to the plot
|
|
26
|
+
test_df = pd.DataFrame(
|
|
27
|
+
np.random.rand(100), index=pd.date_range(end="2025-07-15", periods=100).rename("date"), columns=["data"]
|
|
28
|
+
)
|
|
29
|
+
# plot_widget.plot(x=list(range(len(test_df["data"]))), y=test_df["data"], pen="b", name="Sample Data")
|
|
30
|
+
line_data = ChildDataFrame(test_df, "data", x_label_key="date")
|
|
31
|
+
line_data_item = LinePlotItem(line_data, marker="circle")
|
|
32
|
+
|
|
33
|
+
plot_widget.add_main_item(line_data_item, x_ticks=line_data_item.get_x_ticks())
|
|
34
|
+
|
|
35
|
+
# Set up the layout
|
|
36
|
+
layout = QVBoxLayout(main_window)
|
|
37
|
+
layout.addWidget(plot_widget)
|
|
38
|
+
|
|
39
|
+
main_window.setLayout(layout)
|
|
40
|
+
|
|
41
|
+
main_window.show()
|
|
42
|
+
|
|
43
|
+
sys.exit(app.exec())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pyside6plot-0.0.1 → pyside6plot-0.0.2}/PySide6Plot/resources/qss/dark/navigation_view_interface.qss
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|