/**************************************************************************** ** ** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Charts module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 or (at your option) any later version ** approved by the KDE Free Qt Foundation. The licenses are as published by ** the Free Software Foundation and appearing in the file LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE /*! \class QXYSeries \inmodule QtCharts \brief The QXYSeries class is a base class for line, spline, and scatter series. QXYSeries supports displaying best fit line on a chart. Best fit line is a line through a chart that expresses the relationship between points. */ /*! \qmltype XYSeries \instantiates QXYSeries \inqmlmodule QtCharts \inherits AbstractSeries \brief A base type for line, spline, and scatter series. XYSeries supports displaying best fit line on a chart. Best fit line is a line through a chart that expresses the relationship between points. */ /*! \enum QXYSeries::PointConfiguration This enum value describes the particular configuration of a point. \value Color This enum value can be used to change a point's color. If used together with QXYSeries::setPointConfiguration, the configuration's value should be a valid QColor. \value Size This enum value can be used to change a point's size. If used together with QXYSeries::setPointConfiguration, the configuration's value should be a number, such as \c qreal or \c int. \value Visibility This enum value can be used to hide or show the point. If used together with QXYSeries::setPointConfiguration, the configuration's value should be boolean. \value LabelVisibility This enum value can be used to hide or show the label of the point. If used together with QXYSeries::setPointConfiguration, the configuration's value should be boolean. \sa setPointConfiguration() */ /*! \qmlproperty AbstractAxis XYSeries::axisX The x-axis used for the series. If you leave both axisX and axisXTop undefined, a value axis is created for the series. \sa axisXTop, ValueAxis */ /*! \qmlproperty AbstractAxis XYSeries::axisY The y-axis used for the series. If you leave both axisY and axisYRight undefined, a value axis is created for the series. \sa axisYRight, ValueAxis */ /*! \qmlproperty AbstractAxis XYSeries::axisXTop The x-axis used for the series, drawn on top of the chart view. \note You can only provide either axisX or axisXTop, not both. \sa axisX */ /*! \qmlproperty AbstractAxis XYSeries::axisYRight The y-axis used for the series, drawn to the right on the chart view. \note You can only provide either axisY or axisYRight, not both. \sa axisY */ /*! \qmlproperty AbstractAxis XYSeries::axisAngular The angular axis used for the series, drawn around the polar chart view. \sa axisX */ /*! \qmlproperty AbstractAxis XYSeries::axisRadial The radial axis used for the series, drawn inside the polar chart view. \sa axisY */ /*! \property QXYSeries::pointsVisible \brief Whether the data points are visible and should be drawn. */ /*! \qmlproperty bool XYSeries::pointsVisible Whether the data points are visible and should be drawn. */ /*! \fn QPen QXYSeries::pen() const Returns the pen used to draw the outline of the data points for the series. \sa setPen() */ /*! \fn QBrush QXYSeries::brush() const Returns the brush used to fill the data points for the series. \sa setBrush() */ /*! \property QXYSeries::color \brief The color of the series. This is the line (pen) color in case of QLineSeries or QSplineSeries and the fill (brush) color in case of QScatterSeries or QAreaSeries. \sa pen(), brush() */ /*! \qmlproperty color XYSeries::color The color of the series. This is the line (pen) color in case of LineSeries or SplineSeries and the fill (brush) color in case of ScatterSeries or AreaSeries. */ /*! \property QXYSeries::pointLabelsFormat \brief The format used for showing labels with data points. QXYSeries supports the following format tags: \table \row \li @xPoint \li The x-coordinate of the data point. \row \li @yPoint \li The y-coordinate of the data point. \endtable For example, the following usage of the format tags would produce labels that display the data point shown inside brackets separated by a comma (x, y): \code series->setPointLabelsFormat("(@xPoint, @yPoint)"); \endcode By default, the labels' format is set to \c {@xPoint, @yPoint}. The labels are shown on the plot area, and the labels on the edge of the plot area are cut. If the points are close to each other, the labels may overlap. \sa pointLabelsVisible, pointLabelsFont, pointLabelsColor */ /*! \qmlproperty string XYSeries::pointLabelsFormat The format used for showing labels with data points. \sa pointLabelsVisible, pointLabelsFont, pointLabelsColor */ /*! \fn void QXYSeries::pointLabelsFormatChanged(const QString &format) This signal is emitted when the format of data point labels changes to \a format. */ /*! \property QXYSeries::pointLabelsVisible \brief The visibility of data point labels. This property is \c false by default. \sa pointLabelsFormat, pointLabelsClipping */ /*! \qmlproperty bool XYSeries::pointLabelsVisible The visibility of data point labels. This property is \c false by default. \sa pointLabelsFormat, pointLabelsClipping */ /*! \fn void QXYSeries::pointLabelsVisibilityChanged(bool visible) This signal is emitted when the visibility of the data point labels changes to \a visible. */ /*! \property QXYSeries::pointLabelsFont \brief The font used for data point labels. \sa pointLabelsFormat */ /*! \qmlproperty font XYSeries::pointLabelsFont The font used for data point labels. \sa pointLabelsFormat */ /*! \fn void QXYSeries::pointLabelsFontChanged(const QFont &font); This signal is emitted when the font used for data point labels changes to \a font. */ /*! \property QXYSeries::pointLabelsColor \brief The color used for data point labels. By default, the color is the color of the brush defined in theme for labels. \sa pointLabelsFormat */ /*! \qmlproperty font XYSeries::pointLabelsColor The color used for data point labels. By default, the color is the color of the brush defined in theme for labels. \sa pointLabelsFormat */ /*! \fn void QXYSeries::pointLabelsColorChanged(const QColor &color); This signal is emitted when the color used for data point labels changes to \a color. */ /*! \property QXYSeries::pointLabelsClipping \brief The clipping for data point labels. This property is \c true by default. The labels on the edge of the plot area are cut when clipping is enabled. \sa pointLabelsVisible */ /*! \qmlproperty bool XYSeries::pointLabelsClipping The clipping for data point labels. This property is \c true by default. The labels on the edge of the plot area are cut when clipping is enabled. \sa pointLabelsVisible */ /*! \property QXYSeries::selectedColor \brief The color of the selected points. This is the fill (brush) color of points marked as selected. If not specified, value of QXYSeries::color is used as default. \sa color \since 6.2 */ /*! \qmlproperty color XYSeries::selectedColor The color of the selected points. This is the fill (brush) color of points marked as selected. If not specified, value of QXYSeries::color is used as default. \sa color */ /*! \fn void QXYSeries::markerSizeChanged(qreal size) This signal is emitted when the marker size changes to \a size. */ /*! \fn void QXYSeries::pointLabelsClippingChanged(bool clipping) This signal is emitted when the clipping of the data point labels changes to \a clipping. */ /*! \property QXYSeries::bestFitLineVisible \brief The visibility of the best fit line. This property is \c false by default. \sa bestFitLineEquation \since 6.2 */ /*! \qmlproperty bool XYSeries::bestFitLineVisible The visibility of the best fit line. This property is \c false by default. */ /*! \fn void QXYSeries::bestFitLineVisibilityChanged(bool visible) This signal is emitted when the visibility of the best fit line changes to \a visible. */ /*! \property QXYSeries::bestFitLineColor \brief The color of best fit line. \sa bestFitLineEquation, bestFitLineVisible \since 6.2 */ /*! \qmlproperty bool XYSeries::bestFitLineColor The color of best fit line. \sa bestFitLineVisible */ /*! \fn void QXYSeries::bestFitLineColorChanged(const QColor &color) This signal is emitted when the color used for the best fit line changes to \a color. */ /*! \fn void QXYSeries::clicked(const QPointF& point) This signal is emitted when the user triggers a mouse event by clicking the point \a point in the chart. \sa pressed(), released(), doubleClicked() */ /*! \qmlsignal XYSeries::clicked(point point) This signal is emitted when the user triggers a mouse event by clicking the point \a point in the chart. For example: \code LineSeries { XYPoint { x: 0; y: 0 } XYPoint { x: 1.1; y: 2.1 } onClicked: console.log("onClicked: " + point.x + ", " + point.y); } \endcode The corresponding signal handler is \c onClicked(). \sa pressed(), released(), doubleClicked() */ /*! \fn void QXYSeries::hovered(const QPointF &point, bool state) This signal is emitted when a mouse is hovered over the point \a point in the chart. When the mouse moves over the point, \a state turns \c true, and when the mouse moves away again, it turns \c false. */ /*! \qmlsignal XYSeries::hovered(point point, bool state) This signal is emitted when a mouse is hovered over the point \a point in the chart. When the mouse moves over the point, \a state turns \c true, and when the mouse moves away again, it turns \c false. The corresponding signal handler is \c onHovered(). */ /*! \fn void QXYSeries::pressed(const QPointF& point) This signal is emitted when the user presses the data point \a point in the chart and holds down the mouse button. \sa clicked(), released(), doubleClicked() */ /*! \qmlsignal XYSeries::pressed(point point) This signal is emitted when the user presses the data point \a point in the chart and holds down the mouse button. For example: \code LineSeries { XYPoint { x: 0; y: 0 } XYPoint { x: 1.1; y: 2.1 } onPressed: console.log("onPressed: " + point.x + ", " + point.y); } \endcode The corresponding signal handler is \c onPressed(). \sa clicked(), released(), doubleClicked() */ /*! \fn void QXYSeries::released(const QPointF& point) This signal is emitted when the user releases the mouse press on the data point specified by \a point. \sa pressed(), clicked(), doubleClicked() */ /*! \qmlsignal XYSeries::released(point point) This signal is emitted when the user releases the mouse press on the data point specified by \a point. For example: \code LineSeries { XYPoint { x: 0; y: 0 } XYPoint { x: 1.1; y: 2.1 } onReleased: console.log("onReleased: " + point.x + ", " + point.y); } \endcode The corresponding signal handler is \c onReleased(). \sa pressed(), clicked(), doubleClicked() */ /*! \fn void QXYSeries::doubleClicked(const QPointF& point) This signal is emitted when the user double-clicks the data point \a point in the chart. The \a point is the point where the first press was triggered. \sa pressed(), released(), clicked() */ /*! \qmlsignal XYSeries::doubleClicked(point point) This signal is emitted when the user double-clicks the data point \a point in the chart. The \a point is the point where the first press was triggered. For example: \code LineSeries { XYPoint { x: 0; y: 0 } XYPoint { x: 1.1; y: 2.1 } onDoubleClicked: console.log("onDoubleClicked: " + point.x + ", " + point.y); } \endcode The corresponding signal handler is \c onDoubleClicked(). \sa pressed(), released(), clicked() */ /*! \fn void QXYSeries::pointReplaced(int index) This signal is emitted when a point is replaced at the position specified by \a index. \sa replace() */ /*! \qmlsignal XYSeries::pointReplaced(int index) This signal is emitted when a point is replaced at the position specified by \a index. The corresponding signal handler is \c onPointReplaced(). */ /*! \fn void QXYSeries::pointsReplaced() This signal is emitted when all points are replaced with other points. \sa replace() */ /*! \qmlsignal XYSeries::pointsReplaced() This signal is emitted when all points are replaced with other points. The corresponding signal handler is \c onPointsReplaced(). */ /*! \fn void QXYSeries::pointAdded(int index) This signal is emitted when a point is added at the position specified by \a index. \sa append(), insert() */ /*! \qmlsignal XYSeries::pointAdded(int index) This signal is emitted when a point is added at the position specified by \a index. The corresponding signal handler is \c onPointAdded(). */ /*! \fn void QXYSeries::pointRemoved(int index) This signal is emitted when a point is removed from the position specified by \a index. \sa remove() */ /*! \qmlsignal XYSeries::pointRemoved(int index) This signal is emitted when a point is removed from the position specified by \a index. The corresponding signal handler is \c onPointRemoved(). */ /*! \fn void QXYSeries::pointsRemoved(int index, int count) This signal is emitted when the number of points specified by \a count is removed starting at the position specified by \a index. \sa removePoints(), clear() */ /*! \qmlsignal XYSeries::pointsRemoved(int index, int count) This signal is emitted when the number of points specified by \a count is removed starting at the position specified by \a index. The corresponding signal handler is \c onPointRemoved(). */ /*! \fn void QXYSeries::colorChanged(QColor color) This signal is emitted when the line (pen) color changes to \a color. */ /*! \fn void QXYSeries::penChanged(const QPen &pen) This signal is emitted when the pen changes to \a pen. */ /*! \fn void QXYSeries::lightMarkerChanged(const QImage &lightMarker) This signal is emitted when the light marker image changes to \a lightMarker. \sa QXYSeries::setLightMarker(); \since 6.2 */ /*! \fn void QXYSeriesPrivate::seriesUpdated() \internal */ /*! \qmlmethod XYSeries::append(real x, real y) Appends a point with the coordinates \a x and \a y to the series. */ /*! \qmlmethod XYSeries::replace(real oldX, real oldY, real newX, real newY) Replaces the point with the coordinates \a oldX and \a oldY with the point with the coordinates \a newX and \a newY. Does nothing if the old point does not exist. */ /*! \qmlmethod XYSeries::remove(real x, real y) Removes the point with the coordinates \a x and \a y from the series. Does nothing if the point does not exist. */ /*! \qmlmethod XYSeries::remove(int index) Removes the point at the position specified by \a index from the series. */ /*! \qmlmethod XYSeries::removePoints(int index, int count) Removes the number of points specified by \a count from the series starting at the position specified by \a index. */ /*! \qmlmethod XYSeries::insert(int index, real x, real y) Inserts a point with the coordinates \a x and \a y to the position specified by \a index in the series. If the index is 0 or less than 0, the point is prepended to the list of points. If the index is equal to or greater than than the number of points in the series, the point is appended to the list of points. */ /*! \qmlmethod QPointF XYSeries::at(int index) Returns the point at the position specified by \a index. Returns (0, 0) if the index is not valid. */ /*! \internal Constructs an empty series object that is a child of \a parent. When the series object is added to QChart, instance ownerships is transferred. */ QXYSeries::QXYSeries(QXYSeriesPrivate &d, QObject *parent) : QAbstractSeries(d, parent) { } /*! Deletes the series. Series added to QChart instances are owned by them, and are deleted when the QChart instances are deleted. */ QXYSeries::~QXYSeries() { } /*! Adds the data point with the coordinates \a x and \a y to the series. */ void QXYSeries::append(qreal x, qreal y) { append(QPointF(x, y)); } /*! \overload Adds the data point \a point to the series. */ void QXYSeries::append(const QPointF &point) { Q_D(QXYSeries); if (isValidValue(point)) { d->m_points << point; emit pointAdded(d->m_points.count() - 1); } } /*! \overload Adds the list of data points specified by \a points to the series. */ void QXYSeries::append(const QList &points) { foreach (const QPointF &point , points) append(point); } /*! Replaces the point with the coordinates \a oldX and \a oldY with the point with the coordinates \a newX and \a newY. Does nothing if the old point does not exist. \sa pointReplaced() */ void QXYSeries::replace(qreal oldX, qreal oldY, qreal newX, qreal newY) { replace(QPointF(oldX, oldY), QPointF(newX, newY)); } /*! Replaces the point specified by \a oldPoint with the one specified by \a newPoint. \sa pointReplaced() */ void QXYSeries::replace(const QPointF &oldPoint, const QPointF &newPoint) { Q_D(QXYSeries); int index = d->m_points.indexOf(oldPoint); if (index == -1) return; replace(index, newPoint); } /*! Replaces the point at the position specified by \a index with the point that has the coordinates \a newX and \a newY. \sa pointReplaced() */ void QXYSeries::replace(int index, qreal newX, qreal newY) { replace(index, QPointF(newX, newY)); } /*! Replaces the point at the position specified by \a index with the point specified by \a newPoint. \sa pointReplaced() */ void QXYSeries::replace(int index, const QPointF &newPoint) { Q_D(QXYSeries); if (isValidValue(newPoint)) { d->m_points[index] = newPoint; emit pointReplaced(index); } } /*! Replaces the current points with the points specified by \a points. \note This is much faster than replacing data points one by one, or first clearing all data, and then appending the new data. Emits QXYSeries::pointsReplaced() when the points have been replaced. \sa pointsReplaced() */ void QXYSeries::replace(const QList &points) { Q_D(QXYSeries); d->m_points = points; emit pointsReplaced(); } /*! Removes the configuration of a point located at \a index and restores the default look derived from the series' settings. \note It doesn't affect the configuration of other points. \sa clearPointsConfiguration(), setPointConfiguration() \since 6.2 */ void QXYSeries::clearPointConfiguration(const int index) { Q_D(QXYSeries); if (d->m_pointsConfiguration.contains(index)) { d->m_pointsConfiguration.remove(index); emit pointsConfigurationChanged(d->m_pointsConfiguration); } } /*! Removes the configuration property identified by \a key from the point at \a index and restores the default look derived from the series' settings. Removes the configuration type, such as color or size, specified by \a key from the point at \a index with configuration customizations, allowing that configuration property to be rendered as the default specified in the series' properties. \note It doesn't affect the configuration of other points. \sa clearPointsConfiguration(), setPointConfiguration() \since 6.2 */ void QXYSeries::clearPointConfiguration(const int index, const QXYSeries::PointConfiguration key) { Q_D(QXYSeries); if (d->m_pointsConfiguration.contains(index)) { auto &conf = d->m_pointsConfiguration[index]; if (conf.contains(key)) { conf.remove(key); d->m_pointsConfiguration[index] = conf; emit pointsConfigurationChanged(d->m_pointsConfiguration); } } } /*! Removes the configuration of all points in the series and restores the default look derived from the series' settings. \sa setPointConfiguration() \since 6.2 */ void QXYSeries::clearPointsConfiguration() { Q_D(QXYSeries); d->m_pointsConfiguration.clear(); emit pointsConfigurationChanged(d->m_pointsConfiguration); } /*! Removes the configuration property identified by \a key from all points and restores the default look derived from the series' settings. Removes the configuration type, such as color or size, specified by \a key from all points with configuration customizations, allowing that configuration property to be rendered as the default specified in the series properties. \sa clearPointsConfiguration(), setPointConfiguration() \since 6.2 */ void QXYSeries::clearPointsConfiguration(const QXYSeries::PointConfiguration key) { Q_D(QXYSeries); bool needsUpdate = false; for (const int &index : d->m_pointsConfiguration.keys()) { auto &conf = d->m_pointsConfiguration[index]; if (conf.contains(key)) { conf.remove(key); d->m_pointsConfiguration[index] = conf; needsUpdate = true; } } if (needsUpdate) emit pointsConfigurationChanged(d->m_pointsConfiguration); } /*! Enables customizing the appearance of a point located at \a index with desired \a configuration. With points configuration you can change various aspects of every point's appearance. A point's configuration is represented as a hash map with QXYSeries::pointConfiguration keys and QVariant values. For example: \code QLineSeries *series = new QLineSeries(); series->setName("Customized serie"); series->setPointsVisible(true); *series << QPointF(0, 6) << QPointF(2, 4) << QPointF(3, 6) << QPointF(7, 4) << QPointF(10, 5) << QPointF(11, 1) << QPointF(13, 3) << QPointF(17, 6) << QPointF(18, 3) << QPointF(20, 2); QChart *chart = new QChart(); chart->addSeries(series); chart->createDefaultAxes(); QHash conf; conf[QXYSeries::PointConfiguration::Color] = QColor(Qt::red); conf[QXYSeries::PointConfiguration::Size] = 8; conf[QXYSeries::PointConfiguration::LabelVisibility] = true; series->setPointConfiguration(4, conf); conf.remove(QXYSeries::PointConfiguration::LabelVisibility); series->setPointConfiguration(6, conf); \endcode In this example, you can see a default QLineSeries with 10 points and with changed configuration of two points. Both changed points are red and visibly bigger than the others with a look derived from series. By default, points don't have labels, but the point at index 4 has the label thanks to the QXYSeries::PointConfiguration::LabelVisibility configuration value. Below is an example of a chart created in this way: \image xyseries_point_configuration.png \sa pointsConfiguration(), clearPointsConfiguration() \since 6.2 */ void QXYSeries::setPointConfiguration( const int index, const QHash &configuration) { Q_D(QXYSeries); if (d->m_pointsConfiguration[index] != configuration) { d->m_pointsConfiguration[index] = configuration; emit pointsConfigurationChanged(d->m_pointsConfiguration); } } /*! Enables customizing a particular aspect of a point's configuration. \note Points configuration concept provides a flexible way to configure various aspects of a point's appearance. Thus, values need to have an elastic type such as QVariant. See QXYSeries::PointConfiguration to see what \a value should be passed for certain \a key. \sa pointsConfiguration() \since 6.2 */ void QXYSeries::setPointConfiguration(const int index, const QXYSeries::PointConfiguration key, const QVariant &value) { Q_D(QXYSeries); QHash conf; if (d->m_pointsConfiguration.contains(index)) conf = d->m_pointsConfiguration[index]; bool callSignal = false; if (conf.contains(key)) { if (conf[key] != value) callSignal = true; } else { callSignal = true; } conf[key] = value; d->m_pointsConfiguration[index] = conf; if (callSignal) { emit pointsConfigurationChanged(d->m_pointsConfiguration); } } /*! Enables customizing the configuration of multiple points as specified by \a pointsConfiguration. \sa pointsConfiguration() \since 6.2 */ void QXYSeries::setPointsConfiguration( const QHash> &pointsConfiguration) { Q_D(QXYSeries); if (d->m_pointsConfiguration != pointsConfiguration) { d->m_pointsConfiguration = pointsConfiguration; emit pointsConfigurationChanged(d->m_pointsConfiguration); } } /*! Returns a map representing the configuration of a point at \a index. With points configuration you can change various aspects of each point's look. \sa setPointConfiguration() \since 6.2 */ QHash QXYSeries::pointConfiguration(const int index) const { Q_D(const QXYSeries); return d->m_pointsConfiguration[index]; } /*! Returns a map with points' indexes as keys and points' configuration as values. \sa setPointConfiguration(), pointConfiguration() \since 6.2 */ QHash> QXYSeries::pointsConfiguration() const { Q_D(const QXYSeries); return d->m_pointsConfiguration; } /*! Sets the points' sizes according to a passed list of values. Values from \a sourceData are sorted and mapped to a point size which is between \a minSize and \a maxSize. \note If \a sourceData length is smaller than number of points in the series, then size of the points at the end of the series will stay the same. \sa setPointConfiguration(), pointConfiguration() \since 6.2 */ void QXYSeries::sizeBy(const QList &sourceData, const qreal minSize, const qreal maxSize) { Q_D(QXYSeries); Q_ASSERT(minSize <= maxSize); Q_ASSERT(minSize >= 0); qreal min = std::numeric_limits::max(); qreal max = -std::numeric_limits::max(); for (const auto &p : sourceData) { min = qMin(min, p); max = qMax(max, p); } const qreal range = max - min; for (int i = 0; i < sourceData.size() && i < d->m_points.size(); ++i) { qreal pointSize = minSize; if (range != 0) { const qreal startValue = sourceData.at(i) - min; const qreal percentage = startValue / range; pointSize = qMax(minSize, percentage * maxSize); } setPointConfiguration(i, QXYSeries::PointConfiguration::Size, pointSize); } } /*! Sets the points' color according to a passed list of values. Values from \a sourceData are sorted and mapped to the \a gradient. If the series has a QColorAxis attached, then a gradient from the axis is going to be used. \sa setPointConfiguration(), pointConfiguration(), QColorAxis \since 6.2 */ void QXYSeries::colorBy(const QList &sourceData, const QLinearGradient &gradient) { Q_D(QXYSeries); d->m_colorByData = sourceData; if (d->m_colorByData.isEmpty()) return; const qreal imgSize = 100.0; qreal min = std::numeric_limits::max(); qreal max = std::numeric_limits::min(); for (const auto &p : sourceData) { min = qMin(min, p); max = qMax(max, p); } qreal range = max - min; QLinearGradient usedGradient = gradient; // Gradient will be taked from the first attached color axis. // If there are more color axis, they will have just changed range. bool axisFound = false; const auto axes = attachedAxes(); for (const auto &axis : axes) { if (axis->type() == QAbstractAxis::AxisTypeColor) { QColorAxis *colorAxis = static_cast(axis); if (!axisFound) { usedGradient = QLinearGradient(QPointF(0,0), QPointF(0, imgSize)); const auto stops = colorAxis->gradient().stops(); for (const auto &stop : stops) usedGradient.setColorAt(stop.first, stop.second); if (!colorAxis->autoRange()) { min = colorAxis->min(); max = colorAxis->max(); range = max - min; } axisFound = true; } if (colorAxis->autoRange()) colorAxis->setRange(min, max); } } QImage image(imgSize, imgSize, QImage::Format_ARGB32); QPainter painter(&image); painter.fillRect(image.rect(), usedGradient); // To ensure that negative values will be well handled, distance from min to 0 // will be added to min and every single value. This will move entire values // list to positive only values. const qreal diff = min < 0 ? qAbs(min) : 0; min += diff; for (int i = 0; i < sourceData.size() && i < d->m_points.size(); ++i) { const qreal startValue = qMax(0.0, sourceData.at(i) + diff - min); const qreal percentage = startValue / range; QColor color = image.pixelColor(0, qMin(percentage * imgSize, imgSize - 1)); setPointConfiguration(i, QXYSeries::PointConfiguration::Color, color); } } /*! Returns true if point at given \a index is among selected points and false otherwise. \note Selected points are drawn using the selected color if it was specified. \sa selectedPoints(), setPointSelected(), setSelectedColor() \since 6.2 */ bool QXYSeries::isPointSelected(int index) { Q_D(QXYSeries); return d->isPointSelected(index); } /*! Marks point at \a index as selected. \note Emits QXYSeries::selectedPointsChanged \sa setPointSelected() \since 6.2 */ void QXYSeries::selectPoint(int index) { setPointSelected(index, true); } /*! Deselects point at given \a index. \note Emits QXYSeries::selectedPointsChanged \sa setPointSelected() \since 6.2 */ void QXYSeries::deselectPoint(int index) { setPointSelected(index, false); } /*! Marks point at given \a index as either selected or deselected as specified by \a selected. \note Selected points are drawn using the selected color if it was specified. Emits QXYSeries::selectedPointsChanged \sa setPointSelected(), setSelectedColor() \since 6.2 */ void QXYSeries::setPointSelected(int index, bool selected) { Q_D(QXYSeries); bool callSignal = false; d->setPointSelected(index, selected, callSignal); if (callSignal) emit selectedPointsChanged(); } /*! Marks all points in the series as selected, \note Emits QXYSeries::selectedPointsChanged \sa setPointSelected() \since 6.2 */ void QXYSeries::selectAllPoints() { Q_D(QXYSeries); bool callSignal = false; for (int i = 0; i < d->m_points.count(); ++i) d->setPointSelected(i, true, callSignal); if (callSignal) emit selectedPointsChanged(); } /*! Deselects all points in the series. \note Emits QXYSeries::selectedPointsChanged \sa setPointSelected() \since 6.2 */ void QXYSeries::deselectAllPoints() { Q_D(QXYSeries); bool callSignal = false; for (int i = 0; i < d->m_points.count(); ++i) d->setPointSelected(i, false, callSignal); if (callSignal) emit selectedPointsChanged(); } /*! Marks multiple points passed in a \a indexes list as selected. \note Emits QXYSeries::selectedPointsChanged \sa setPointSelected() \since 6.2 */ void QXYSeries::selectPoints(const QList &indexes) { Q_D(QXYSeries); bool callSignal = false; for (const int &index : indexes) d->setPointSelected(index, true, callSignal); if (callSignal) emit selectedPointsChanged(); } /*! Marks multiple points passed in a \a indexes list as deselected. \note Emits QXYSeries::selectedPointsChanged \sa setPointSelected() \since 6.2 */ void QXYSeries::deselectPoints(const QList &indexes) { Q_D(QXYSeries); bool callSignal = false; for (const int &index : indexes) d->setPointSelected(index, false, callSignal); if (callSignal) emit selectedPointsChanged(); } /*! Changes selection state of points at given \a indexes to the opposite one. Makes \note Emits QXYSeries::selectedPointsChanged \sa setPointSelected() \since 6.2 */ void QXYSeries::toggleSelection(const QList &indexes) { Q_D(QXYSeries); bool callSignal = false; for (const int &index : indexes) d->setPointSelected(index, !isPointSelected(index), callSignal); if (callSignal) emit selectedPointsChanged(); } /*! Returns a list of points indexes marked as selected. Selected points are visible regardless of points visibility. \sa setPointSelected(), pointsVisible() \since 6.2 */ QList QXYSeries::selectedPoints() const { Q_D(const QXYSeries); return QList(d->m_selectedPoints.begin(), d->m_selectedPoints.end()); } /*! Removes the point that has the coordinates \a x and \a y from the series. \sa pointRemoved() */ void QXYSeries::remove(qreal x, qreal y) { remove(QPointF(x, y)); } /*! Removes the data point \a point from the series. \sa pointRemoved() */ void QXYSeries::remove(const QPointF &point) { Q_D(QXYSeries); int index = d->m_points.indexOf(point); if (index == -1) return; remove(index); } /*! Removes the point at the position specified by \a index from the series. \sa pointRemoved() */ void QXYSeries::remove(int index) { Q_D(QXYSeries); d->m_points.remove(index); bool callSignal = false; d->setPointSelected(index, false, callSignal); emit pointRemoved(index); if (callSignal) emit selectedPointsChanged(); } /*! Removes the number of points specified by \a count from the series starting at the position specified by \a index. \sa pointsRemoved() */ void QXYSeries::removePoints(int index, int count) { // This function doesn't overload remove as there is chance for it to get mixed up with // remove(qreal, qreal) overload in some implicit casting cases. Q_D(QXYSeries); if (count > 0) { d->m_points.remove(index, count); bool callSignal = false; if (!d->m_selectedPoints.empty()) { QSet selectedAfterRemoving; for (const int &selectedPointIndex : qAsConst(d->m_selectedPoints)) { if (selectedPointIndex < index) { selectedAfterRemoving << selectedPointIndex; } else if (selectedPointIndex >= index + count) { selectedAfterRemoving << selectedPointIndex - count; callSignal = true; } else { callSignal = true; } } d->m_selectedPoints = selectedAfterRemoving; } emit pointsRemoved(index, count); if (callSignal) emit selectedPointsChanged(); } } /*! Inserts the data point \a point in the series at the position specified by \a index. \sa pointAdded() */ void QXYSeries::insert(int index, const QPointF &point) { Q_D(QXYSeries); if (isValidValue(point)) { index = qMax(0, qMin(index, d->m_points.size())); d->m_points.insert(index, point); bool callSignal = false; if (!d->m_selectedPoints.isEmpty()) { // if point was inserted we need to move already selected points by 1 QSet selectedAfterInsert; for (const auto &value : qAsConst(d->m_selectedPoints)) { if (value >= index) { selectedAfterInsert << value + 1; callSignal = true; } else { selectedAfterInsert << value; } } d->m_selectedPoints = selectedAfterInsert; } emit pointAdded(index); if (callSignal) emit selectedPointsChanged(); } } /*! Removes all points from the series. \sa pointsRemoved() */ void QXYSeries::clear() { Q_D(QXYSeries); removePoints(0, d->m_points.size()); } /*! Returns the points in the series. */ QList QXYSeries::points() const { Q_D(const QXYSeries); return d->m_points; } #if QT_DEPRECATED_SINCE(6, 0) /*! \deprecated Use points() instead. Returns the points in the series. */ QList QXYSeries::pointsVector() const { Q_D(const QXYSeries); return d->m_points; } #endif /*! Returns the data point at the position specified by \a index in the internal series of points. */ const QPointF &QXYSeries::at(int index) const { Q_D(const QXYSeries); return d->m_points.at(index); } /*! Returns the number of data points in a series. */ int QXYSeries::count() const { Q_D(const QXYSeries); return d->m_points.count(); } /*! Sets the pen used for drawing points on the chart to \a pen. If the pen is not defined, the pen from the chart theme is used. \sa QChart::setTheme() */ void QXYSeries::setPen(const QPen &pen) { Q_D(QXYSeries); if (d->m_pen != pen) { bool emitColorChanged = d->m_pen.color() != pen.color(); d->m_pen = pen; emit d->seriesUpdated(); if (emitColorChanged) emit colorChanged(pen.color()); emit penChanged(pen); } } QPen QXYSeries::pen() const { Q_D(const QXYSeries); if (d->m_pen == QChartPrivate::defaultPen()) return QPen(); else return d->m_pen; } /*! Sets the brush used for drawing points on the chart to \a brush. If the brush is not defined, the brush from the chart theme setting is used. \sa QChart::setTheme() */ void QXYSeries::setBrush(const QBrush &brush) { Q_D(QXYSeries); if (d->m_brush != brush) { d->m_brush = brush; emit d->seriesUpdated(); } } QBrush QXYSeries::brush() const { Q_D(const QXYSeries); if (d->m_brush == QChartPrivate::defaultBrush()) return QBrush(); else return d->m_brush; } void QXYSeries::setColor(const QColor &color) { QPen p = pen(); if (p.color() != color) { p.setColor(color); setPen(p); } } QColor QXYSeries::color() const { return pen().color(); } void QXYSeries::setSelectedColor(const QColor &color) { Q_D(QXYSeries); if (selectedColor() != color) { d->m_selectedColor = color; emit selectedColorChanged(color); } } QColor QXYSeries::selectedColor() const { Q_D(const QXYSeries); return d->m_selectedColor; } void QXYSeries::setPointsVisible(bool visible) { Q_D(QXYSeries); if (d->m_pointsVisible != visible) { d->m_pointsVisible = visible; emit d->seriesUpdated(); } } bool QXYSeries::pointsVisible() const { Q_D(const QXYSeries); return d->m_pointsVisible; } void QXYSeries::setPointLabelsFormat(const QString &format) { Q_D(QXYSeries); if (d->m_pointLabelsFormat != format) { d->m_pointLabelsFormat = format; emit pointLabelsFormatChanged(format); } } QString QXYSeries::pointLabelsFormat() const { Q_D(const QXYSeries); return d->m_pointLabelsFormat; } void QXYSeries::setPointLabelsVisible(bool visible) { Q_D(QXYSeries); if (d->m_pointLabelsVisible != visible) { d->m_pointLabelsVisible = visible; emit pointLabelsVisibilityChanged(visible); } } bool QXYSeries::pointLabelsVisible() const { Q_D(const QXYSeries); return d->m_pointLabelsVisible; } void QXYSeries::setPointLabelsFont(const QFont &font) { Q_D(QXYSeries); if (d->m_pointLabelsFont != font) { d->m_pointLabelsFont = font; emit pointLabelsFontChanged(font); } } QFont QXYSeries::pointLabelsFont() const { Q_D(const QXYSeries); return d->m_pointLabelsFont; } void QXYSeries::setPointLabelsColor(const QColor &color) { Q_D(QXYSeries); if (d->m_pointLabelsColor != color) { d->m_pointLabelsColor = color; emit pointLabelsColorChanged(color); } } QColor QXYSeries::pointLabelsColor() const { Q_D(const QXYSeries); if (d->m_pointLabelsColor == QChartPrivate::defaultPen().color()) return QPen().color(); else return d->m_pointLabelsColor; } void QXYSeries::setPointLabelsClipping(bool enabled) { Q_D(QXYSeries); if (d->m_pointLabelsClipping != enabled) { d->m_pointLabelsClipping = enabled; emit pointLabelsClippingChanged(enabled); } } bool QXYSeries::pointLabelsClipping() const { Q_D(const QXYSeries); return d->m_pointLabelsClipping; } /*! Sets the image used for drawing markers on each point of the series as the value of \a lightMarker. The default value is a default-QImage() (QImage::isNull() == true), meaning no light marker will be painted. You can reset back to default (disabled) by calling this function with a null QImage (QImage()). The light markers visualize the data points of this series and as such are an alternative to \c setPointsVisible(true). If a light marker is set with this method, visible points as set with \c setPointsVisible(true) are not displayed. Unlike the elements of \l {QScatterSeries}{QScatterSeries} the light markers are not represented by QGraphicsItem, but are just painted (no objects created). However, the mouse-event-signals of QXYSeries behave the same way, meaning that you'll get the exact domain value of the point if you click/press/hover the light marker. You'll still get the in between domain value if you click on the line. The light markers are above the line in terms of painting as well as events. \sa QXYSeries::lightMarker() \since 6.2 */ void QXYSeries::setLightMarker(const QImage &lightMarker) { Q_D(QXYSeries); if (d->m_lightMarker == lightMarker) return; d->m_lightMarker = lightMarker; emit d->seriesUpdated(); emit lightMarkerChanged(d->m_lightMarker); } /*! Gets the image used for drawing markers on each point of the series. The default value is QImage(), meaning no light marker will be painted. The light markers visualize the data points of this series and as such are an alternative to setPointsVisible(true). Both features can be enabled independently from each other. Unlike the elements of \l {QScatterSeries}{QScatterSeries} the light markers are not represented by QGraphicsItem, but are just painted (no objects created). However, the mouse-event-signals of QXYSeries behave the same way, meaning that you'll get the exact domain value of the point if you click/press/hover the light marker. You'll still get the in between domain value if you click on the line. The light markers are above the line in terms of painting as well as events. \sa QXYSeries::setLightMarker() \since 6.2 */ const QImage &QXYSeries::lightMarker() const { Q_D(const QXYSeries); return d->m_lightMarker; } /*! Sets the image used for drawing markers on selected series's points to \a selectedLightMarker. The default value is QImage(), meaning usual QXYSeries::lightMarker() will be painted. This is an equivalent for QXYSeries::setSelectedColor() if you prefer light markers over normal points, but you still want to distinguish selected points. \sa QXYSeries::lightMarker(), QXYSeries::selectedColor(), QXYSeries::setPointSelected() \since 6.2 */ void QXYSeries::setSelectedLightMarker(const QImage &selectedLightMarker) { Q_D(QXYSeries); if (d->m_selectedLightMarker == selectedLightMarker) return; d->m_selectedLightMarker = selectedLightMarker; emit d->seriesUpdated(); emit selectedLightMarkerChanged(d->m_selectedLightMarker); } /*! Returns the image used for drawing markers on selected series's points. The default value is QImage(), meaning usual QXYSeries::lightMarker() will be painted. This is an equivalent for QXYSeries::selectedColor() if you prefer light markers over normal points, but you still want to distinguish selected points. \sa QXYSeries::lightMarker(), QXYSeries::selectedColor(), QXYSeries::setPointSelected() \since 6.2 */ const QImage &QXYSeries::selectedLightMarker() const { Q_D(const QXYSeries); return d->m_selectedLightMarker; } /*! Sets the size of the marker used to render points in the series. The default size is 15.0. \sa QScatterSeries::markerSize \since 6.2 */ void QXYSeries::setMarkerSize(qreal size) { Q_D(QXYSeries); if (!qFuzzyCompare(d->m_markerSize, size)) { d->m_markerSizeDefault = false; d->setMarkerSize(size); emit d->seriesUpdated(); emit markerSizeChanged(size); } } /*! Gets the size of the marker used to render points in the series. The default size depends on the specific QXYSeries type. QScatterSeries has a default of 15.0 QLineSeries has a default of the series pen size * 1.5 \sa QScatterSeries::markerSize \since 6.2 */ qreal QXYSeries::markerSize() const { Q_D(const QXYSeries); return d->m_markerSize; } void QXYSeries::setBestFitLineVisible(bool visible) { Q_D(QXYSeries); if (d->m_bestFitLineVisible != visible) { d->m_bestFitLineVisible = visible; emit bestFitLineVisibilityChanged(visible); emit d->seriesUpdated(); } } bool QXYSeries::bestFitLineVisible() const { Q_D(const QXYSeries); return d->m_bestFitLineVisible; } /*! Returns a pair of numbers where the first number is a slope factor and the second number is intercept of a linear function for a best fit line. Those factors are calculated using Least Squares Method based on points passed to the series. Parameter \a ok is used to report a failure by setting its value to \c false and to report a success by setting its value to \c true. \sa QXYSeries::bestFitLineVisible() \since 6.2 */ QPair QXYSeries::bestFitLineEquation(bool &ok) const { Q_D(const QXYSeries); return d->bestFitLineEquation(ok); } void QXYSeries::setBestFitLinePen(const QPen &pen) { Q_D(QXYSeries); if (d->m_bestFitLinePen != pen) { bool emitColorChanged = d->m_bestFitLinePen.color() != pen.color(); d->m_bestFitLinePen = pen; emit d->seriesUpdated(); if (emitColorChanged) bestFitLineColorChanged(pen.color()); emit bestFitLinePenChanged(pen); } } QPen QXYSeries::bestFitLinePen() const { Q_D(const QXYSeries); if (d->m_bestFitLinePen == QChartPrivate::defaultPen()) return QPen(); else return d->m_bestFitLinePen; } /*! Stream operator for adding the data point \a point to the series. \sa append() */ QXYSeries &QXYSeries::operator<< (const QPointF &point) { append(point); return *this; } /*! Stream operator for adding the list of data points specified by \a points to the series. \sa append() */ QXYSeries &QXYSeries::operator<< (const QList& points) { append(points); return *this; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// QXYSeriesPrivate::QXYSeriesPrivate(QXYSeries *q) : QAbstractSeriesPrivate(q), m_pen(QChartPrivate::defaultPen()), m_brush(QChartPrivate::defaultBrush()), m_pointsVisible(false), m_pointLabelsFormat(QLatin1String("@xPoint, @yPoint")), m_pointLabelsVisible(false), m_pointLabelsFont(QChartPrivate::defaultFont()), m_pointLabelsColor(QChartPrivate::defaultPen().color()), m_pointLabelsClipping(true), m_bestFitLinePen(QChartPrivate::defaultPen()), m_bestFitLineVisible(false), m_markerSize(15.0) { } void QXYSeriesPrivate::initializeDomain() { qreal minX(0); qreal minY(0); qreal maxX(1); qreal maxY(1); Q_Q(QXYSeries); const QList &points = q->points(); if (!points.isEmpty()) { minX = points[0].x(); minY = points[0].y(); maxX = minX; maxY = minY; for (int i = 0; i < points.count(); i++) { qreal x = points[i].x(); qreal y = points[i].y(); minX = qMin(minX, x); minY = qMin(minY, y); maxX = qMax(maxX, x); maxY = qMax(maxY, y); } } domain()->setRange(minX, maxX, minY, maxY); } QList QXYSeriesPrivate::createLegendMarkers(QLegend* legend) { Q_Q(QXYSeries); QList list; return list << new QXYLegendMarker(q,legend); } void QXYSeriesPrivate::initializeAxes() { } QAbstractAxis::AxisType QXYSeriesPrivate::defaultAxisType(Qt::Orientation orientation) const { Q_UNUSED(orientation); return QAbstractAxis::AxisTypeValue; } QAbstractAxis* QXYSeriesPrivate::createDefaultAxis(Qt::Orientation orientation) const { Q_UNUSED(orientation); return new QValueAxis; } void QXYSeriesPrivate::initializeAnimations(QChart::AnimationOptions options, int duration, QEasingCurve &curve) { XYChart *item = static_cast(m_item.data()); Q_ASSERT(item); if (item->animation()) item->animation()->stopAndDestroyLater(); if (options.testFlag(QChart::SeriesAnimations)) item->setAnimation(new XYAnimation(item, duration, curve)); else item->setAnimation(0); QAbstractSeriesPrivate::initializeAnimations(options, duration, curve); } void QXYSeriesPrivate::drawPointLabels(QPainter *painter, const QList &allPoints, const int offset) { if (m_pointLabelsVisible || !m_pointsConfiguration.isEmpty()) { if (m_pointLabelsClipping) painter->setClipping(true); else painter->setClipping(false); QList pointsToSkip; QHash offsets; if (!m_pointsConfiguration.isEmpty()) { for (int i = 0; i < allPoints.size(); ++i) { bool drawLabel = m_pointLabelsVisible; if (m_pointsConfiguration.contains(i)) { const auto &conf = m_pointsConfiguration[i]; if (conf.contains(QXYSeries::PointConfiguration::LabelVisibility)) { drawLabel = m_pointsConfiguration [i][QXYSeries::PointConfiguration::LabelVisibility] .toBool(); if (drawLabel && conf.contains(QXYSeries::PointConfiguration::Size)) offsets[i] = conf[QXYSeries::PointConfiguration::Size].toReal(); } } if (!drawLabel) pointsToSkip << i; } } drawSeriesPointLabels(painter, allPoints, offset, offsets, pointsToSkip); } } void QXYSeriesPrivate::drawSeriesPointLabels(QPainter *painter, const QList &points, const int offset, const QHash &offsets, const QList &indexesToSkip) { if (points.size() == 0) return; static const QString xPointTag(QLatin1String("@xPoint")); static const QString yPointTag(QLatin1String("@yPoint")); QFont f(m_pointLabelsFont); f.setPixelSize(QFontInfo(m_pointLabelsFont).pixelSize()); painter->setFont(f); painter->setPen(QPen(m_pointLabelsColor)); QFontMetrics fm(painter->font()); // m_points is used for the label here as it has the series point information // points variable passed is used for positioning because it has the coordinates const int pointCount = qMin(points.size(), m_points.size()); for (int i(0); i < pointCount; i++) { if (indexesToSkip.contains(i)) continue; QString pointLabel = m_pointLabelsFormat; pointLabel.replace(xPointTag, presenter()->numberToString(m_points.at(i).x())); pointLabel.replace(yPointTag, presenter()->numberToString(m_points.at(i).y())); int currOffset = offset; if (offsets.contains(i)) currOffset = offsets[i]; const int labelOffset = currOffset + 2; // Position text in relation to the point int pointLabelWidth = fm.horizontalAdvance(pointLabel); QPointF position(points.at(i)); position.setX(position.x() - pointLabelWidth / 2); position.setY(position.y() - labelOffset); painter->drawText(position, pointLabel); } } void QXYSeriesPrivate::drawBestFitLine(QPainter *painter, const QRectF &clipRect) { bool ok = false; const auto &bestFitLineParams = bestFitLineEquation(ok); if (!ok) return; const qreal x1 = clipRect.x(); const qreal y1 = bestFitLineParams.first * x1 + bestFitLineParams.second; QPointF p1 = domain()->calculateGeometryPoint(QPointF(x1, y1), ok); const qreal x2 = clipRect.x() + 1; const qreal y2 = bestFitLineParams.first * x2 + bestFitLineParams.second; QPointF p2 = domain()->calculateGeometryPoint(QPointF(x2, y2), ok); if (ok) { QLineF bestFitLine { p1, p2 }; // maxLength is length of the diagonal, no line can be longer const qreal maxLength = qSqrt(qPow(clipRect.width(), 2) * qPow(clipRect.height(), 2)); bestFitLine.setLength(maxLength); painter->save(); painter->setPen(m_bestFitLinePen); painter->drawLine(bestFitLine); painter->restore(); } } void QXYSeries::setBestFitLineColor(const QColor &color) { QPen p = bestFitLinePen(); if (p.color() != color) { p.setColor(color); setBestFitLinePen(p); } } QColor QXYSeries::bestFitLineColor() const { return bestFitLinePen().color(); } QPair QXYSeriesPrivate::bestFitLineEquation(bool &ok) const { if (m_points.count() <= 1) { ok = false; return { 0, 0 }; } ok = true; qreal xSum = 0.0, x2Sum = 0.0, ySum = 0.0, xySum = 0.0; for (const auto &point : m_points) { xSum += point.x(); ySum += point.y(); x2Sum += qPow(point.x(), 2); xySum += point.x() * point.y(); } const qreal divisor = m_points.count() * x2Sum - xSum * xSum; // To prevent crashes in unusual cases if (divisor == 0.0) { ok = false; return { 0, 0 }; } qreal a = (m_points.count() * xySum - xSum * ySum) / divisor; qreal b = (x2Sum * ySum - xSum * xySum) / divisor; return { a, b }; } void QXYSeriesPrivate::setPointSelected(int index, bool selected, bool &callSignal) { if (index < 0 || index > m_points.count() - 1) return; if (selected) { if (!isPointSelected(index)) { m_selectedPoints << index; callSignal = true; } } else { if (isPointSelected(index)) { m_selectedPoints.remove(index); callSignal = true; } } } bool QXYSeriesPrivate::isPointSelected(int index) { return m_selectedPoints.contains(index); } bool QXYSeriesPrivate::isMarkerSizeDefault() { return m_markerSizeDefault; } void QXYSeriesPrivate::setMarkerSize(qreal markerSize) { m_markerSize = markerSize; } QList QXYSeriesPrivate::colorByData() const { return m_colorByData; } QT_END_NAMESPACE #include "moc_qxyseries.cpp" #include "moc_qxyseries_p.cpp"