Light Markers and Points Selection Example#
The Light Markers and Points Selection example shows how to use light markers and point selections in a series.
Creating the chart and its elements#
We start by creating a series, filling it with the data, and enabling the light marker and point selection features.
It is important not to set points visibility to True
, because light markers functionality is an independent feature and setting both would result in undesired behavior.
20
21 marker_size = 20.
22 series = QSplineSeries()
23 series.append([QPointF(0, 0),
24 QPointF(0.5, 2.27),
25 QPointF(1.5, 2.2),
26 QPointF(3.3, 1.7),
27 QPointF(4.23, 3.1),
28 QPointF(5.3, 2.3),
29 QPointF(6.47, 4.1)])
30 series.setMarkerSize(marker_size)
31 series.setLightMarker(Utilities.default_light_marker(marker_size))
32 series.setSelectedLightMarker(Utilities.default_selected_light_marker(marker_size))
33
34 @Slot(QPointF)
35 def toggle_selection(point):
36 try:
37 index = series.points().index(point)
38 if index != -1:
39 series.toggleSelection([index])
40 except ValueError:
41 pass
42
Then we create the QChart
, the QChartview
and the control widget with its layout to arrange customization elements.
44
45 chart = QChart()
46 chart.addSeries(series)
47 chart.createDefaultAxes()
48 chart.legend().setVisible(False)
49
50 chart_view = QChartView(chart)
51 chart_view.setRenderHint(QPainter.Antialiasing)
52
53 control_widget = QWidget(window)
Creating UI for configuring the chart#
The next step is where we create user interface elements that allow customizing the chart, including setting light marker and selection marker images.
54 control_layout = QGridLayout(control_widget)
55 char_point_combobox = QComboBox()
56 char_point_selected_combobox = QComboBox()
57 line_color_combobox = QComboBox()
We create the label for the marker selection combobox and fill the combobox with the items. We then provide functionality to the combobox, allowing the user’s selection to set the desired light marker image. As light markers are enabled and disabled by setting a valid QImage or setting an empty QImage()
, we need to make sure that if the user does not wish unselected points to be displayed, we do not actually set the light marker image.
If checking isn’t performed, a new QImage
will be set as the light marker and unselected points will be visible even though it has been switched off.
59
60 @Slot(int)
61 def set_light_marker(index):
62 if show_unselected_points_checkbox.isChecked():
63 series.setLightMarker(Utilities.get_point_representation(
64 Utilities.point_type(index), marker_size))
65
66 char_point = QLabel("Char point: ")
67 char_point_combobox.addItems(["Red rectangle", "Green triangle", "Orange circle"])
Almost the same procedure applies to the selected point light marker and line color. The only difference is that there is no need to check the visibility of unselected points as it doesn’t affect the functionality.
70 @Slot(int)
71 def set_selected_light_marker(index):
72 series.setSelectedLightMarker(
73 Utilities.get_selected_point_representation(
74 Utilities.selected_point_type(index), marker_size))
75
76 char_point_selected = QLabel("Char point selected: ")
77 char_point_selected_combobox.addItems(["Blue triangle", "Yellow rectangle", "Lavender circle"])
78 char_point_selected_combobox.currentIndexChanged.connect(set_selected_light_marker)
79
80 @Slot(int)
81 def set_line_color(index):
82 series.setColor(Utilities.make_line_color(Utilities.line_color(index)))
83
84 line_color_label = QLabel("Line color: ")
85 line_color_combobox.addItems(["Blue", "Black", "Mint"])
A small difference comes with changing visibility of unselected points. As it was mentioned before, making light markers invisible is achieved by setting the light marker to an empty QImage()
. That is why, depending on checkbox state, selected point light marker is set to an empty QImage
or to the light marker extracted from the current index of the corresponding combobox.
88 @Slot(int)
89 def display_unselected_points(checkbox_state):
90 if checkbox_state:
91 series.setLightMarker(
92 Utilities.get_point_representation(
93 Utilities.point_type(char_point_combobox.currentIndex()), marker_size))
94 else:
95 series.setLightMarker(QImage())
96
97 show_unselected_points_label = QLabel("Display unselected points: ")
The final part is to lay out the widgets within the main widget and set the main window size.
Usage#
To use this example, change any of the comboboxes and checkboxes controlling the markers, line color, and unselected point visibility on the right. Then try clicking on points in the chart to select or deselect them.
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
"""PySide6 port of the Light Markers Points Selection example from Qt v6.2"""
import sys
from PySide6.QtCore import Slot, QPointF, Qt
from PySide6.QtCharts import QChart, QChartView, QSplineSeries
from PySide6.QtGui import QPainter, QImage
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QGridLayout,
QComboBox, QCheckBox, QLabel, QHBoxLayout)
import utilities as Utilities
if __name__ == "__main__":
a = QApplication(sys.argv)
window = QMainWindow()
window.setWindowTitle("Light Markers and Points Selection")
marker_size = 20.
series = QSplineSeries()
series.append([QPointF(0, 0),
QPointF(0.5, 2.27),
QPointF(1.5, 2.2),
QPointF(3.3, 1.7),
QPointF(4.23, 3.1),
QPointF(5.3, 2.3),
QPointF(6.47, 4.1)])
series.setMarkerSize(marker_size)
series.setLightMarker(Utilities.default_light_marker(marker_size))
series.setSelectedLightMarker(Utilities.default_selected_light_marker(marker_size))
@Slot(QPointF)
def toggle_selection(point):
try:
index = series.points().index(point)
if index != -1:
series.toggleSelection([index])
except ValueError:
pass
series.clicked.connect(toggle_selection)
chart = QChart()
chart.addSeries(series)
chart.createDefaultAxes()
chart.legend().setVisible(False)
chart_view = QChartView(chart)
chart_view.setRenderHint(QPainter.Antialiasing)
control_widget = QWidget(window)
control_layout = QGridLayout(control_widget)
char_point_combobox = QComboBox()
char_point_selected_combobox = QComboBox()
line_color_combobox = QComboBox()
show_unselected_points_checkbox = QCheckBox()
@Slot(int)
def set_light_marker(index):
if show_unselected_points_checkbox.isChecked():
series.setLightMarker(Utilities.get_point_representation(
Utilities.point_type(index), marker_size))
char_point = QLabel("Char point: ")
char_point_combobox.addItems(["Red rectangle", "Green triangle", "Orange circle"])
char_point_combobox.currentIndexChanged.connect(set_light_marker)
@Slot(int)
def set_selected_light_marker(index):
series.setSelectedLightMarker(
Utilities.get_selected_point_representation(
Utilities.selected_point_type(index), marker_size))
char_point_selected = QLabel("Char point selected: ")
char_point_selected_combobox.addItems(["Blue triangle", "Yellow rectangle", "Lavender circle"])
char_point_selected_combobox.currentIndexChanged.connect(set_selected_light_marker)
@Slot(int)
def set_line_color(index):
series.setColor(Utilities.make_line_color(Utilities.line_color(index)))
line_color_label = QLabel("Line color: ")
line_color_combobox.addItems(["Blue", "Black", "Mint"])
line_color_combobox.currentIndexChanged.connect(set_line_color)
@Slot(int)
def display_unselected_points(checkbox_state):
if checkbox_state:
series.setLightMarker(
Utilities.get_point_representation(
Utilities.point_type(char_point_combobox.currentIndex()), marker_size))
else:
series.setLightMarker(QImage())
show_unselected_points_label = QLabel("Display unselected points: ")
show_unselected_points_checkbox.setChecked(True)
show_unselected_points_checkbox.stateChanged.connect(display_unselected_points)
control_label = QLabel("Marker and Selection Controls")
control_label.setAlignment(Qt.AlignHCenter)
control_label_font = control_label.font()
control_label_font.setBold(True)
control_label.setFont(control_label_font)
control_layout.addWidget(control_label, 0, 0, 1, 2)
control_layout.addWidget(char_point, 1, 0)
control_layout.addWidget(char_point_combobox, 1, 1)
control_layout.addWidget(char_point_selected, 2, 0)
control_layout.addWidget(char_point_selected_combobox, 2, 1)
control_layout.addWidget(line_color_label, 3, 0)
control_layout.addWidget(line_color_combobox, 3, 1)
control_layout.addWidget(show_unselected_points_label, 4, 0)
control_layout.addWidget(show_unselected_points_checkbox, 4, 1, 1, 2)
control_layout.setRowStretch(5, 1)
main_widget = QWidget(window)
main_layout = QHBoxLayout(main_widget)
main_layout.addWidget(chart_view)
main_layout.addWidget(control_widget)
window.setCentralWidget(main_widget)
window.resize(1080, 720)
window.show()
sys.exit(a.exec())
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
from PySide6.QtGui import QImage, QPainter, QColor
from PySide6.QtCore import Qt
import rc_markers # noqa: F401
def rectangle(point_type, image_size):
image = QImage(image_size, image_size, QImage.Format_RGB32)
painter = QPainter()
painter.begin(image)
painter.setRenderHint(QPainter.Antialiasing)
painter.fillRect(0, 0, image_size, image_size, point_type[2])
painter.end()
return image
def triangle(point_type, image_size):
return QImage(point_type[3]).scaled(image_size, image_size)
def circle(point_type, image_size):
image = QImage(image_size, image_size, QImage.Format_ARGB32)
image.fill(QColor(0, 0, 0, 0))
painter = QPainter()
painter.begin(image)
painter.setRenderHint(QPainter.Antialiasing)
painter.setBrush(point_type[2])
pen = painter.pen()
pen.setWidth(0)
painter.setPen(pen)
painter.drawEllipse(0, 0, image_size * 0.9, image_size * 0.9)
painter.end()
return image
_point_types = [("RedRectangle", rectangle, Qt.red),
("GreenTriangle", triangle, Qt.green, ":/images/green_triangle.png"),
("OrangeCircle", circle, QColor(255, 127, 80))]
_selected_point_types = [("BlueTriangle", triangle, Qt.blue, ":/images/blue_triangle.png"),
("YellowRectangle", rectangle, Qt.yellow),
("LavenderCircle", circle, QColor(147, 112, 219))]
_line_colors = [("Blue", QColor(65, 105, 225)), ("Black", Qt.black), ("Mint", QColor(70, 203, 155))]
def point_type(index):
return _point_types[index]
def selected_point_type(index):
return _selected_point_types[index]
def line_color(index):
return _line_colors[index]
def default_light_marker(image_size):
return rectangle(_point_types[0], image_size)
def default_selected_light_marker(image_size):
return triangle(_selected_point_types[0], image_size)
def get_point_representation(point_type, image_size):
return point_type[1](point_type, image_size)
def get_selected_point_representation(point_type, image_size):
return point_type[1](point_type, image_size)
def make_line_color(line_color):
return line_color[1]
<RCC>
<qresource prefix="/">
<file>images/blue_triangle.png</file>
<file>images/green_triangle.png</file>
</qresource>
</RCC>