2024-02-06 21:49:14 +08:00
|
|
|
/*
|
|
|
|
Copyright (c) 2008-2024 Jan W. Krieger (<jan@jkrieger.de>)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This software is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU Lesser General Public License (LGPL) as published by
|
|
|
|
the Free Software Foundation, either version 2.1 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU Lesser General Public License (LGPL) for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License (LGPL)
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef jkqtpgraphlabels_H
|
|
|
|
#define jkqtpgraphlabels_H
|
|
|
|
|
|
|
|
|
|
|
|
#include <QString>
|
|
|
|
#include <QPainter>
|
|
|
|
#include <QPair>
|
|
|
|
#include <functional>
|
|
|
|
#include "jkqtplotter/jkqtptools.h"
|
|
|
|
#include "jkqtplotter/jkqtplotter_imexport.h"
|
|
|
|
#include "jkqtplotter/jkqtpgraphsbase.h"
|
|
|
|
#include "jkqtplotter/graphs/jkqtpgraphlabelstylemixin.h"
|
|
|
|
|
|
|
|
// forward declarations
|
|
|
|
class JKQTBasePlotter;
|
|
|
|
class JKQTPlotter;
|
|
|
|
class JKQTPCoordinateAxis;
|
|
|
|
class JKQTPDatastore;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*! \brief This graph plots a series of data labels. This can be used to add number-labels to e.g. a barchart.
|
|
|
|
\ingroup jkqtplotter_graphlabels
|
|
|
|
|
|
|
|
Sometimes it is necessary to display the numeric value of a datapoint right in the plot.
|
|
|
|
To achieve this, JKQTPXYGraphLabels is provided, which draws a text-label next to each datapoint in a
|
|
|
|
series of x- and y-values (thus it is derived from JKQTPXYGraph). Each label is drawn with a little offset
|
|
|
|
from the actual datapoint. Under each label, a small (stylable) box is drawn, which is by default simply
|
|
|
|
the same color as the background color of complete plot, but with transparency, thus providing a certain
|
|
|
|
level of contrast to the text, even if drawn above other plot elements. Use the properties of the parent
|
|
|
|
mix-in class JKQTPGraphValueLabelStyleMixin to style the text and the box.
|
|
|
|
|
|
|
|
Here is an example of labels together with a bars and lines chart:
|
|
|
|
|
|
|
|
\image html JKQTPGLabelAwayFromXAxis.png
|
|
|
|
|
2024-02-06 22:19:20 +08:00
|
|
|
Also other styles of boxes are available:
|
|
|
|
|
|
|
|
\image html JKQTPGLSimpleBoxAndLine.png
|
|
|
|
|
2024-02-06 21:49:14 +08:00
|
|
|
To achieve this, use code like this:
|
|
|
|
\code
|
|
|
|
// create barchart and line-chart to display the data:
|
|
|
|
JKQTPBarVerticalGraph* graph1=new JKQTPBarVerticalGraph(&plot);
|
|
|
|
graph1->setBarPositionColumn(columnX);
|
|
|
|
graph1->setBarHeightColumn(columnY);
|
|
|
|
|
|
|
|
JKQTPXYLineGraph* graph2=new JKQTPXYLineGraph(&plot);
|
|
|
|
graph2->setXColumn(columnX);
|
|
|
|
graph2->setYColumn(columnY);
|
|
|
|
|
|
|
|
// create the data labels:
|
|
|
|
JKQTPXYGraphLabels* graphLabels=new JKQTPXYGraphLabels(JKQTPXYGraphLabels::YValueLabel, &plot);
|
|
|
|
graphLabels->setXColumn(graph1->getXColumn());
|
|
|
|
graphLabels->setYColumn(graph1->getYColumn());
|
|
|
|
graphLabels->setLabelPosition(JKQTPGLabelAwayFromXAxis),
|
|
|
|
|
|
|
|
// add the graphs to the plot, so it is actually displayed
|
|
|
|
plot.addGraph(graph1);
|
|
|
|
plot.addGraph(graph2);
|
|
|
|
plot.addGraph(graphLabels);
|
|
|
|
\endcode
|
|
|
|
|
|
|
|
The text shown in the label is determined by a functor of type JKQTPXYGraphLabels::LabelGenerator that calculates
|
|
|
|
it from the labels position and data-index.
|
|
|
|
This functor can be custimized (set setCustomLabelGenerator() or the matching constructor), or it may be one of
|
|
|
|
three default immplementations, that display:
|
|
|
|
- the current x-value (JKQTPXYGraphLabels::XValueLabel constructor arguent or setDefaultXLabelGenerator() )
|
|
|
|
- the current y-value (JKQTPXYGraphLabels::YValueLabel constructor arguent or setDefaultYLabelGenerator() )
|
|
|
|
- the current x- and y-value (JKQTPXYGraphLabels::XYValueLabel constructor arguent or setDefaultXYLabelGenerator() )
|
|
|
|
.
|
|
|
|
|
|
|
|
The default generators can be further customized with a series of properties on how to format their output:
|
|
|
|
- setXValueLabelFormat(), setYValueLabelFormat(), setXYValueLabelFormat() ... these set the basic label and are
|
|
|
|
typically only \c "$%1$" or \c "$%1/%2$" , but you can set them to any string (\c %1 / \c %2 is replaced by
|
|
|
|
the string-converted x-/y-values) and e.g. add a prefix, like \c setXValueLabelFormat("$x=%1$").
|
|
|
|
You can use any LaTeX-markup that is allowed by JKQTMathText here!
|
|
|
|
- setXDefaultConverter(), setXDefaultPrecision(), setXBelowIsZero(), ... (all these exist in X and Y variants!)
|
|
|
|
.
|
|
|
|
|
2024-02-06 23:20:48 +08:00
|
|
|
\see \ref JKQTPlotterGraphLabelsExample
|
2024-02-06 21:49:14 +08:00
|
|
|
|
|
|
|
*/
|
|
|
|
class JKQTPLOTTER_LIB_EXPORT JKQTPXYGraphLabels: public JKQTPXYGraph, public JKQTPGraphValueLabelStyleMixin, public JKQTPXYLabelsGeneratorMixin {
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
enum LabelContentsDefaultType {
|
|
|
|
XValueLabel, //!< \brief generates a label with the x-coordinate only, calls setDefaultXLabelGenerator()
|
|
|
|
YValueLabel, //!< \brief generates a label with the y-coordinate only, calls setDefaultYLabelGenerator()
|
|
|
|
XYValueLabel //!< \brief generates a label with the x- and y-coordinate, calls setDefaultXYLabelGenerator()
|
|
|
|
};
|
|
|
|
Q_ENUM(LabelContentsDefaultType)
|
|
|
|
/** \brief type of a functor that generates a label */
|
|
|
|
typedef std::function<QString(double,double,int)> LabelGenerator;
|
|
|
|
|
|
|
|
/** \brief class constructor, generates a JKQTPXYGraphLabels with one of the default label generator functors (x-value, y-value or x+y-values) */
|
|
|
|
explicit JKQTPXYGraphLabels(LabelContentsDefaultType lt, JKQTBasePlotter* parent=nullptr);
|
|
|
|
/** \brief class constructor, generates a JKQTPXYGraphLabels with one of the default label generator functors (x-value, y-value or x+y-values) */
|
|
|
|
JKQTPXYGraphLabels(LabelContentsDefaultType lt, JKQTPlotter* parent);
|
|
|
|
/** \brief class constructor, generates a JKQTPXYGraphLabels with a custom LabelGenerator functor */
|
|
|
|
JKQTPXYGraphLabels(const LabelGenerator& lgen, JKQTBasePlotter* parent=nullptr);
|
|
|
|
/** \brief class constructor, generates a JKQTPXYGraphLabels with a custom LabelGenerator functor */
|
|
|
|
JKQTPXYGraphLabels(const LabelGenerator& lgen, JKQTPlotter* parent);
|
|
|
|
|
|
|
|
/** \brief plots the graph to the plotter object specified as parent */
|
|
|
|
virtual void draw(JKQTPEnhancedPainter& painter) override;
|
|
|
|
/** \brief plots a key marker inside the specified rectangle \a rect */
|
|
|
|
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, const QRectF& rect) override;
|
|
|
|
/** \brief returns the color to be used for the key label */
|
|
|
|
virtual QColor getKeyLabelColor() const override;
|
|
|
|
/** \copydoc JKQTPPlotElement::getXMinMax() */
|
|
|
|
virtual bool getXMinMax(double& minx, double& maxx, double& smallestGreaterZero) override;
|
|
|
|
/** \copydoc JKQTPPlotElement::getYMinMax() */
|
|
|
|
virtual bool getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) override;
|
|
|
|
|
|
|
|
|
|
|
|
/** \brief set color of line and symbol */
|
|
|
|
void setColor(QColor c, bool setTextColor_=true, bool setFrameColor_=true);
|
|
|
|
/** \brief sets a custom label geneator function of type LabelGenerator to use
|
|
|
|
*
|
|
|
|
* \see m_labelGenerator, setDefaultXLabelGenerator(), setDefaultYLabelGenerator(), setDefaultXYLabelGenerator()
|
|
|
|
*/
|
|
|
|
void setCustomLabelGenerator(const LabelGenerator& labgen);
|
|
|
|
/** \brief sets the label geneator function to a default implementation, that prints the x-value only
|
|
|
|
*
|
|
|
|
* The generator uses m_xValueLabelFormat, m_xDefaultConverter, ...
|
|
|
|
* \see m_labelGenerator, setCustomLabelGenerator(), setDefaultXLabelGenerator(), setDefaultYLabelGenerator(), setDefaultXYLabelGenerator()
|
|
|
|
*/
|
|
|
|
void setDefaultXLabelGenerator();
|
|
|
|
/** \brief sets the label geneator function to a default implementation, that prints the y-value only
|
|
|
|
*
|
|
|
|
* The generator uses m_yValueLabelFormat, m_yDefaultConverter, ...
|
|
|
|
* \see m_labelGenerator, setCustomLabelGenerator(), setDefaultXLabelGenerator(), setDefaultYLabelGenerator(), setDefaultXYLabelGenerator()
|
|
|
|
*/
|
|
|
|
void setDefaultYLabelGenerator();
|
|
|
|
/** \brief sets the label geneator function to a default implementation, that prints the x- and y-value
|
|
|
|
*
|
|
|
|
* The generator uses m_xyValueLabelFormat, m_xDefaultConverter, m_yDefaultConverter, ...
|
|
|
|
* \see m_labelGenerator, setCustomLabelGenerator(), setDefaultXLabelGenerator(), setDefaultYLabelGenerator(), setDefaultXYLabelGenerator()
|
|
|
|
*/
|
|
|
|
void setDefaultXYLabelGenerator();
|
|
|
|
protected:
|
|
|
|
/** \brief generates the label at position (\a x , \a y ) and at the given data \a index */
|
|
|
|
QString generateLabel(double x, double y, int index) const;
|
|
|
|
private:
|
|
|
|
/** \brief generate the label for the datapoint at location (\a x , \a y ) and being the \a index -th value in the columns */
|
|
|
|
LabelGenerator m_labelGenerator;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif // jkqtpgraphlabels_H
|