implemented wiggle plots (feature request #68)

This commit is contained in:
jkriege2 2022-05-11 22:55:23 +02:00
parent d45083ee9b
commit ee2477a1f6
16 changed files with 518 additions and 14 deletions

View File

@ -35,9 +35,12 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
<tr><td> \image html JKQTPBarHorizontalGraphStacked_small.png
<td> \subpage JKQTPlotterStackedBarChart
<td> `JKQTPBarVerticalStackableGraph`, `JKQTPBarHorizontalStackableGraph` <br> C++-style vectors of data
<tr><td> \image html filledgraphs_small.png
<td> \subpage JKQTPlotterFilledGraphs
<td> `JKQTPBarVerticalGraph` <br> setting/altering data in `JKQTPDatstore` directly <br> transparent plots <br> calculating histograms
<tr><td> \image html filledgraphs_small.png
<td> \subpage JKQTPlotterFilledGraphs
<td> `JKQTPFilledCurveXGraph`/`JKQTPFilledCurveYGraph` <br> setting/altering data in `JKQTPDatstore` directly <br> transparent plots <br> calculating histograms
<tr><td> \image html wiggleplots_small.png
<td> \subpage JKQTPlotterWigglePlots
<td> `JKQTPFilledCurveXGraph`/`JKQTPFilledCurveYGraph` <br> setting/altering data in `JKQTPDatstore` directly <br> data-depentend coloring <br> random-walks <br> seismographic data
<tr><td> \image html impulsesplot_small.png
<td> \subpage JKQTPlotterImpulsePlots
<td> `JKQTPImpulsesVerticalGraph` and `JKQTPImpulsesHorizontalGraph` <br> C++-style QVector as plot data

View File

@ -14,7 +14,7 @@ This page lists release notes for the diferent version of JKQTPlotter
\subsection page_whatsnew_TRUNK_OVERVIEW trunk: Overview
Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
<ul>
<li></li>
<li>JKQTPFilledCurveXGraph and JKQTPFilledCurveYGraph can now plot wiggle plots with different fill styles above and below the baseline (feature request <a href="https://github.com/jkriege2/JKQtPlotter/issues/68">#68 Wiggle Plots</a> from <a href="https://github.com/xichaoqiang">user:xichaoqiang</a> </li>
</ul>
\subsection page_whatsnew_TRUNK_DOWNLOAD trunk: Download

View File

@ -60,5 +60,5 @@ add_subdirectory(symbols_and_styles)
add_subdirectory(ui)
add_subdirectory(user_interaction)
add_subdirectory(violinplot)
add_subdirectory(wiggleplots)

View File

@ -15,7 +15,8 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/errorbarstyles_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/errorbarstyles) | [Different Types of Error Indicators](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/errorbarstyles) | `JKQTPXYLineErrorGraph` <br> different styles of error indicators for x- and y-errors <br> C++-style QVector for data <br> styling error indicators <br> moving key and formatting plotter grid |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/barchart_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/barchart) | [Simple Bar Charts](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/barchart) | `JKQTPBarVerticalGraph` <br> C-style arrays of data |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/JKQTPbarHorizontalGraphStacked_small.png) <br> ![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/JKQTPbarVerticalGraphStacked_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/stackedbars) | [Stacked Bar Charts](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/stackedbars) | `JKQTPBarVerticalStackableGraph`, `JKQTPBarHorizontalStackableGraph` <br> C++-style vectors of data |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/filledgraphs_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/filledgraphs) | [Filled Curve Plots](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/filledgraphs) | `JKQTPBarVerticalGraph` <br> setting/altering data in `JKQTPDatstore` directly <br> transparent plots <br> calculating histograms |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/filledgraphs_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/filledgraphs) | [Filled Curve Plots](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/filledgraphs) | `JKQTPFilledCurveXGraph`/`JKQTPFilledCurveYGraph` <br> setting/altering data in `JKQTPDatstore` directly <br> transparent plots <br> calculating histograms |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/wiggleplots_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/wiggleplots) | [Wiggle Plots](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/wiggleplots) | `JKQTPFilledCurveXGraph`/`JKQTPFilledCurveYGraph` <br> setting/altering data in `JKQTPDatstore` directly <br> data-dependent coloring <br> random-walks <br> seismographic data |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/impulsesplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/impulsesplot) | [Impulse Plots](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/impulsesplot) | `JKQTPImpulsesVerticalGraph` and `JKQTPImpulsesHorizontalGraph` <br> C++-style QVector as plot data |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/paramscatterplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/paramscatterplot) | [Scatter Graph with Parametrized Symbols/Colors](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/paramscatterplot) | `JKQTPXYParametrizedScatterGraph` <br> C++-style QVector as plot data <br> modify scatter/points/line-graph properties by data |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/paramscatterplot_image_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/paramscatterplot_image) | [Draw an Artistic Image with a Parametrized Scatter Graph](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/paramscatterplot_image) | `JKQTPXYParametrizedScatterGraph` <br> C++-style QVector as plot data <br> rectangular arrangement of scatters <br> generative computer graphics |

View File

@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 3.16)
set(EXAMPLE_NAME wiggleplots)
set(EXENAME jkqtptest_${EXAMPLE_NAME})
message( STATUS ".. Building Example ${EXAMPLE_NAME}" )
# Set up source files
set(SOURCES ${EXAMPLE_NAME}.cpp)
set(HEADERS )
set(RESOURCES )
set(UIS )
add_executable(${EXENAME} WIN32 ${SOURCES} ${HEADERS} ${RESOURCES} ${UIS})
target_include_directories(${EXENAME} PRIVATE ../../lib)
if(JKQtPlotter_BUILD_STATIC_LIBS)
target_link_libraries(${EXENAME} JKQTPlotterLib)
elseif(JKQtPlotter_BUILD_SHARED_LIBS)
target_link_libraries(${EXENAME} JKQTPlotterSharedLib)
endif()
# Installation
install(TARGETS ${EXENAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
#Installation of Qt DLLs on Windows
jkqtplotter_deployqt(${EXENAME})

View File

@ -0,0 +1,149 @@
# Example (JKQTPlotter): Wiggle Plots {#JKQTPlotterWigglePlots}
This project (see `./examples/wiggleplots/`) demonstrates how to draw "wiggle plots" with JKQtPlotter, using `JKQTPFilledCurveXGraph` or `JKQTPFilledCurveYGraph`. Wiggle plots are plots, where the fill color is different above and below the baseline of the plot. They are e.g. used in seismology.
The source code of the main application can be found in [`wiggleplots.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/wiggleplots/wiggleplots.cpp). If creates two different plots that demonstrate two styles of plots and also uses the horizontal and vertical variant of the graph class.
## Plot red/blue wiggle plot using `JKQTPFilledCurveXGraph`
For the first example we simulate a 1D random walk and plot the result as a filles wiggle plot:
In a first step, we obtain a pointer to the JKQTPDatastore and add two columns to it.
```.cpp
// 1. get a pointer to the internal datastore (for convenience)
JKQTPDatastore* ds=plot.getDatastore();
// 2. now we create 2 datacolumns with length 1000 (NSteps) entries in the datastore
// these will later hold the time-step and position of a random walker
const size_t NSteps=400;
const size_t columnT=ds->addLinearColumn(NSteps, 0, NSteps-1, "time");
const size_t columnX=ds->addColumn(NSteps, "position");
```
Now we fill the column with the random walk data:
```.cpp
// 3. now we simulate a simple rendom walk and store the calculated positions
// in columnX
double pos=5;
const double stepsize=1;
std::random_device rd; // random number generators:
std::mt19937 gen{rd()};
std::uniform_int_distribution<int> dist(0,1);
for (size_t t=0; t<NSteps; t++) {
ds->set(columnX, t, pos);
pos=pos+stepsize*(static_cast<double>(dist(gen))*2.0-1.0);
}
```
Now we can generate the actual graph and set its basic properties and data columns:
```.cpp
// 4. now we add three semi-transparent, filled curve plots, one for each histogram
JKQTPFilledCurveXGraph* graph=new JKQTPFilledCurveXGraph(&plot);
// 5. set graph titles
graph->setTitle("Random Walk");
// 6. set data
graph->setXColumn(columnT); graph->setYColumn(columnX);
```
Now we can acrivate the wiggle plot style filling mode and set the fill colors and line color and width.
```.cpp
// 7.1 enable wiggle-plot filling
graph->setFillMode(JKQTPFilledCurveXGraph::TwoColorFilling);
// 7.2 draw the data also as a black, thin line
graph->setLineColor(QColor("black"));
graph->setLineWidth(1);
// 7.3 fill areas below the baseline with red
graph->setFillColor(QColor("red"));
// 7.4 fill areas above the baseline with blue
graph->fillStyleBelow().setFillColor(QColor("blue"));
```
The baseline is set to the starting point (5) of the random walk. By default it would be at y=0.
```.cpp
// 7.5 set the baseline to be at 5 (not the default 0
graph->setBaseline(5);
```
Now we only have to add the graph to the plotter and set some final properties for styling:
```.cpp
// 8. add the graphs to the plot, so they are actually displayed
plot.addGraph(graph);
// 9. set axis labels
plot.getXAxis()->setAxisLabel("time $t$");
plot.getYAxis()->setAxisLabel("walker position $x(t)$");
// 10. scale plot automatically
plot.zoomToFit();
// 11. show plotter and make it a decent size
plot.show();
plot.resize(600,400);
```
This is the resulting plot:
![wiggleplot of random walk](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/wiggleplot_x.png)
## Plot black/transparent wiggle plot using `JKQTPFilledCurveYGraph` in a "seismographic style"
The second example follows mor or less the same steps as above, but here we add several graphs that each show a wavepacket that is shoft slightly:
```.cpp
// 3. now we calculate several wavepackets and add a graph for each.
const size_t NWavepackets=7;
for (size_t nw=0; nw<NWavepackets; nw++) {
const size_t columnPacket=ds->addColumn(NSteps, "wavepacket1");
const double packwidth=0.4/static_cast<double>(NWavepackets);
const double pos=pow(static_cast<double>(nw), 0.6)*packwidth*3.5+5.0*packwidth;
const double wavelength=packwidth/1.5;
const double offset=(static_cast<double>(nw)*1.5+1.5);
for (size_t ti=0; ti<NSteps; ti++) {
const double t=ds->get(columnT, ti);
ds->set(columnPacket, ti, offset+sin(2.0*M_PI*t/wavelength)*exp(-0.5*jkqtp_sqr(t-pos)/jkqtp_sqr(packwidth)));
}
// 4. now we add three semi-transparent, filled curve plots, one for each histogram
JKQTPFilledCurveYGraph* graph=new JKQTPFilledCurveYGraph(&plot);
// set graph titles
graph->setTitle("wave "+QString::number(nw+1));
// set data
graph->setYColumn(columnT); graph->setXColumn(columnPacket);
// enable wiggle-plot filling
graph->setFillMode(JKQTPFilledCurveXGraph::TwoColorFilling);
// draw the data also as a black, thin line
graph->setLineColor(QColor("black"));
graph->setLineWidth(1);
// fill areas below the baseline with red
graph->setFillColor(Qt::transparent);
// fill areas above the baseline with blue
graph->fillStyleBelow().setFillColor(QColor("black"));
// set the baseline to be at 5 (not the default 0
graph->setBaseline(offset);
// add the graphs to the plot, so they are actually displayed
plot.addGraph(graph);
}
```
Also the colors are different: We use black below the baseline and transparent above. The line through the data points is black as well.
This is the resulting plot:
![wiggleplot of random walk](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/wiggleplot_y.png)

View File

@ -0,0 +1,155 @@
/** \example wiggleplots.cpp
* Shows how to use filled graphs with JKQTPlotter
*
* \ref JKQTPlotterwiggleplots
*/
#include <QApplication>
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/graphs/jkqtpfilledcurve.h"
#include <random>
void drawRandomWalkX(JKQTPlotter& plot) {
// 1. get a pointer to the internal datastore (for convenience)
JKQTPDatastore* ds=plot.getDatastore();
// 2. now we create 2 datacolumns with length 1000 (NSteps) entries in the datastore
// these will later hold the time-step and position of a random walker
const size_t NSteps=400;
const size_t columnT=ds->addLinearColumn(NSteps, 0, NSteps-1, "time");
const size_t columnX=ds->addColumn(NSteps, "position");
// 3. now we simulate a simple rendom walk and store the calculated positions
// in columnX
double pos=5;
const double stepsize=1;
std::random_device rd; // random number generators:
std::mt19937 gen{rd()};
std::uniform_int_distribution<int> dist(0,1);
for (size_t t=0; t<NSteps; t++) {
ds->set(columnX, t, pos);
pos=pos+stepsize*(static_cast<double>(dist(gen))*2.0-1.0);
}
// 4. now we add three semi-transparent, filled curve plots, one for each histogram
JKQTPFilledCurveXGraph* graph=new JKQTPFilledCurveXGraph(&plot);
// 5. set graph titles
graph->setTitle("Random Walk");
// 6. set data
graph->setXColumn(columnT); graph->setYColumn(columnX);
// 7.1 enable wiggle-plot filling
graph->setFillMode(JKQTPFilledCurveXGraph::TwoColorFilling);
// 7.2 draw the data also as a black, thin line
graph->setLineColor(QColor("black"));
graph->setLineWidth(1);
// 7.3 fill areas below the baseline with red
graph->setFillColor(QColor("red"));
// 7.4 fill areas above the baseline with blue
graph->fillStyleBelow().setFillColor(QColor("blue"));
// 7.5 set the baseline to be at 5 (not the default 0
graph->setBaseline(5);
// 8. add the graphs to the plot, so they are actually displayed
plot.addGraph(graph);
// 9. set axis labels
plot.getXAxis()->setAxisLabel("time $t$");
plot.getYAxis()->setAxisLabel("walker position $x(t)$");
// 10. scale plot automatically
plot.zoomToFit();
// 11. show plotter and make it a decent size
plot.show();
plot.resize(600,400);
}
void drawWavepacketsY(JKQTPlotter& plot) {
// 1. create a plotter window and get a pointer to the internal datastore (for convenience)
JKQTPDatastore* ds=plot.getDatastore();
// 2. now we create a datacolumns with length 1200 (NSteps) entries in the datastore
// these will later hold the time-value for each wavepacket
const size_t NSteps=1200;
const size_t columnT=ds->addLinearColumn(NSteps, 0, 1, "time");
// 3. now we calculate several wavepackets and add a graph for each.
const size_t NWavepackets=7;
for (size_t nw=0; nw<NWavepackets; nw++) {
const size_t columnPacket=ds->addColumn(NSteps, "wavepacket1");
const double packwidth=0.4/static_cast<double>(NWavepackets);
const double pos=pow(static_cast<double>(nw), 0.6)*packwidth*3.5+5.0*packwidth;
const double wavelength=packwidth/1.5;
const double offset=(static_cast<double>(nw)*1.5+1.5);
for (size_t ti=0; ti<NSteps; ti++) {
const double t=ds->get(columnT, ti);
ds->set(columnPacket, ti, offset+sin(2.0*M_PI*t/wavelength)*exp(-0.5*jkqtp_sqr(t-pos)/jkqtp_sqr(packwidth)));
}
// 4. now we add three semi-transparent, filled curve plots, one for each histogram
JKQTPFilledCurveYGraph* graph=new JKQTPFilledCurveYGraph(&plot);
// set graph titles
graph->setTitle("wave "+QString::number(nw+1));
// set data
graph->setYColumn(columnT); graph->setXColumn(columnPacket);
// enable wiggle-plot filling
graph->setFillMode(JKQTPFilledCurveXGraph::TwoColorFilling);
// draw the data also as a black, thin line
graph->setLineColor(QColor("black"));
graph->setLineWidth(1);
// fill areas below the baseline with red
graph->setFillColor(Qt::transparent);
// fill areas above the baseline with blue
graph->fillStyleBelow().setFillColor(QColor("black"));
// set the baseline to be at 5 (not the default 0
graph->setBaseline(offset);
// add the graphs to the plot, so they are actually displayed
plot.addGraph(graph);
}
// 5. set axis labels
plot.getXAxis()->setAxisLabel("wavepacket amplitude $f(t)$");
plot.getYAxis()->setAxisLabel("time $t$");
// 4. scale plot automatically
plot.zoomToFit();
// 5. show plotter and make it a decent size
plot.show();
plot.resize(600,600);
}
int main(int argc, char* argv[])
{
#if QT_VERSION >= QT_VERSION_CHECK(5,6,0) && QT_VERSION < QT_VERSION_CHECK(6,0,0)
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // DPI support
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); //HiDPI pixmaps
#endif
QApplication app(argc, argv);
JKQTPlotter plotWalk, plotWavepackets;
drawRandomWalkX(plotWalk);
drawWavepacketsY(plotWavepackets);
return app.exec();
}

View File

@ -0,0 +1,30 @@
# source code for this simple demo
SOURCES = wiggleplots.cpp
RESOURCES +=
# configure Qt
CONFIG += link_prl qt
QT += core gui xml svg
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
# output executable name
TARGET = wiggleplots
# include JKQTPlotter source code
DEPENDPATH += ../../lib ../../qmake/staticlib/jkqtplotterlib
INCLUDEPATH += ../../lib
CONFIG (debug, debug|release) {
LIBS += -L../../qmake/staticlib/jkqtplotterlib/debug -ljkqtplotterlib_debug
} else {
LIBS += -L../../qmake/staticlib/jkqtplotterlib/release -ljkqtplotterlib
}
message("LIBS = $$LIBS")
win32-msvc*: DEFINES += _USE_MATH_DEFINES
win32-msvc*: DEFINES += NOMINMAX

View File

@ -0,0 +1,8 @@
TEMPLATE = subdirs
SUBDIRS += jkqtplotterlib wiggleplots
jkqtplotterlib.file = ../../qmake/staticlib/jkqtplotterlib/jkqtplotterlib.pro
wiggleplots.file=$$PWD/wiggleplots.pro
wiggleplots.depends = jkqtplotterlib

View File

@ -33,11 +33,12 @@
JKQTPFilledCurveGraphBase::JKQTPFilledCurveGraphBase(JKQTBasePlotter *parent):
JKQTPXYBaselineGraph(parent)
JKQTPXYBaselineGraph(parent), m_fillMode(FillMode::SingleFilling)
{
parentPlotStyle=-1;
initLineStyle(parent, parentPlotStyle, JKQTPPlotStyleType::Filled);
initFillStyle(parent, parentPlotStyle, JKQTPPlotStyleType::Filled);
m_fillStyleBelow.initFillStyleInvertedColor(this);
setFillCurve(true);
setDrawLine(true);
}
@ -57,16 +58,50 @@ void JKQTPFilledCurveGraphBase::drawKeyMarker(JKQTPEnhancedPainter &painter, QRe
painter.setPen(np);
if (getDrawLine()) painter.setPen(p);
painter.setBrush(b);
if (getFillCurve()) painter.drawRect(rect);
if (getFillCurve()) {
if (getFillMode()==FillMode::SingleFilling) {
painter.drawRect(rect);
} else {
QBrush belowB=fillStyleBelow().getFillBrush(painter, parent);
QPolygonF p,pb;
p<<rect.topLeft()<<rect.topRight()<<rect.bottomRight();
pb<<rect.topLeft()<<rect.bottomRight()<<rect.bottomLeft();
painter.drawPolygon(p);
painter.setBrush(belowB);
painter.drawPolygon(pb);
painter.setBrush(b);
}
}
if (!getFillCurve() && getDrawLine()) painter.drawLine(QLineF(rect.left(), y, rect.right(), y));
}
JKQTPGraphFillStyleMixin &JKQTPFilledCurveGraphBase::fillStyleBelow()
{
return m_fillStyleBelow;
}
const JKQTPGraphFillStyleMixin &JKQTPFilledCurveGraphBase::fillStyleBelow() const
{
return m_fillStyleBelow;
}
JKQTPFilledCurveGraphBase::FillMode JKQTPFilledCurveGraphBase::getFillMode() const
{
return m_fillMode;
}
void JKQTPFilledCurveGraphBase::setColor(QColor c)
{
setLineColor(c);
setFillColor(JKQTPGetDerivedColor(parent->getCurrentPlotterStyle().graphsStyle.filledStyle.fillColorDerivationMode, c));
c.setAlphaF(0.5);
setHighlightingLineColor(c);
m_fillStyleBelow.initFillStyleInvertedColor(this);
}
void JKQTPFilledCurveGraphBase::setFillMode(FillMode mode)
{
m_fillMode=mode;
}
@ -98,6 +133,7 @@ void JKQTPFilledCurveXGraph::draw(JKQTPEnhancedPainter& painter) {
QPen ph=getHighlightingLinePen(painter, parent);
QPen np(Qt::NoPen);
QBrush b=getFillBrush(painter, parent);
QBrush b_below=fillStyleBelow().getFillBrush(painter, parent);
int imax=0;
int imin=0;
@ -150,7 +186,22 @@ void JKQTPFilledCurveXGraph::draw(JKQTPEnhancedPainter& painter) {
auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
if (getFillCurve()) {
painter.fillPath(pf, b);
if (getFillMode()==FillMode::SingleFilling) {
painter.fillPath(pf, b);
} else if (getFillMode()==FillMode::TwoColorFilling) {
QRectF rAbove=pf.boundingRect();
rAbove.setBottom(y0);
QPainterPath pAbove;
pAbove.addRect(rAbove);
QRectF rBelow=pf.boundingRect();
rBelow.setTop(y0);
QPainterPath pBelow;
pBelow.addRect(rBelow);
QPainterPath pfa=pf.intersected(pAbove);
QPainterPath pfb=pf.intersected(pBelow);
painter.fillPath(pfa, b);
painter.fillPath(pfb, b_below);
}
}
if (isHighlighted()) {
@ -196,6 +247,7 @@ void JKQTPFilledCurveYGraph::draw(JKQTPEnhancedPainter &painter)
QPen ph=getHighlightingLinePen(painter, parent);
QPen np(Qt::NoPen);
QBrush b=getFillBrush(painter, parent);
QBrush b_below=fillStyleBelow().getFillBrush(painter, parent);
int imax=0;
int imin=0;
@ -245,7 +297,22 @@ void JKQTPFilledCurveYGraph::draw(JKQTPEnhancedPainter &painter)
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
if (getFillCurve()) {
painter.fillPath(pf, b);
if (getFillMode()==FillMode::SingleFilling) {
painter.fillPath(pf, b);
} else if (getFillMode()==FillMode::TwoColorFilling) {
QRectF rAbove=pf.boundingRect();
rAbove.setLeft(x0);
QPainterPath pAbove;
pAbove.addRect(rAbove);
QRectF rBelow=pf.boundingRect();
rBelow.setRight(x0);
QPainterPath pBelow;
pBelow.addRect(rBelow);
QPainterPath pfa=pf.intersected(pAbove);
QPainterPath pfb=pf.intersected(pBelow);
painter.fillPath(pfa, b);
painter.fillPath(pfb, b_below);
}
}
if (isHighlighted()) {

View File

@ -40,6 +40,16 @@
class JKQTPLOTTER_LIB_EXPORT JKQTPFilledCurveGraphBase: public JKQTPXYBaselineGraph, public JKQTPGraphLineAndFillStyleMixin {
Q_OBJECT
public:
/** \brief specifies how the area below the graph is filled
*
* \see setFillMode(), getFillMode(), fillStyleBelow(), \ref JKQTPlotterWigglePlots
*/
enum FillMode {
SingleFilling=0, /*!< \brief the whole area is filled with the same color/pattern, generates "simple filled plots", such as \image html filledgraphs_small.png */
TwoColorFilling=1 /*!< \brief the area above and below baseline with the two different colors/patterns, generates "wiggle plots", such as \image html wiggleplots_small.png */
};
Q_ENUM(FillMode)
/** \brief class constructor */
explicit JKQTPFilledCurveGraphBase(JKQTBasePlotter* parent=nullptr);
@ -47,12 +57,23 @@ public:
virtual QColor getKeyLabelColor() const override;
/** \brief plots a key marker inside the specified rectangle \a rect */
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) override;
/** \copydoc m_fillStyleBelow */
JKQTPGraphFillStyleMixin& fillStyleBelow();
/** \copydoc m_fillStyleBelow */
const JKQTPGraphFillStyleMixin& fillStyleBelow() const;
/** \copydoc m_fillMode */
FillMode getFillMode() const;
public slots:
/** \brief set line-color, fill color and symbol color */
void setColor(QColor c);
/** \copydoc m_fillMode */
void setFillMode(FillMode mode);
protected:
/** \brief specifies how the area of the graph is filles */
FillMode m_fillMode;
/** \brief if m_fillMode \c ==FillAboveAndBelowDifferently then this fill style is used below the baseline and
* the default fill style is used above */
JKQTPGraphFillStyleMixin m_fillStyleBelow;
};
@ -63,6 +84,19 @@ protected:
\image html filledgraphs.png
\see \ref JKQTPlotterFilledGraphs
This class also provides the possibility to file above and below the baseline with different style.
Such plots are sometimes called "Wiggle Plots" and are often used (in their black/white-variety for seismographic
data plotting.
\image html wiggleplot_x.png
To generate such a plot, used \c JKQTPFilledCurveXGraph::setFillMode(JKQTPFilledCurveXGraph::FillMode::TwoColorFilling)
and then use \c JKQTPFilledCurveXGraph::fillStyleBelow() to access the fill style for the area below the baseline
and the default fill style to define the fill style above the baseline.
\see \ref JKQTPlotterWigglePlots
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPFilledCurveXGraph: public JKQTPFilledCurveGraphBase {
Q_OBJECT
@ -113,6 +147,18 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPFilledCurveXErrorGraph: public JKQTPFilledCurv
\see \ref JKQTPlotterFilledGraphs
This class also provides the possibility to file above and below the baseline with different style.
Such plots are sometimes called "Wiggle Plots" and are often used (in their black/white-variety for seismographic
data plotting.
\image html wiggleplot_x.png
To generate such a plot, used \c JKQTPFilledCurveXGraph::setFillMode(JKQTPFilledCurveXGraph::FillMode::TwoColorFilling)
and then use \c JKQTPFilledCurveXGraph::fillStyleBelow() to access the fill style for the area below the baseline
and the default fill style to define the fill style above the baseline.
\see \ref JKQTPlotterWigglePlots
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPFilledCurveYGraph: public JKQTPFilledCurveGraphBase {
Q_OBJECT

View File

@ -288,6 +288,19 @@ JKQTPGraphFillStyleMixin::JKQTPGraphFillStyleMixin()
}
void JKQTPGraphFillStyleMixin::initFillStyleInvertedColor(JKQTPGraphFillStyleMixin *other)
{
if (other) { // get style settings from parent object
m_fillColor=other->getFillColor();
qreal h=0,s=0,v=0,a=0;
m_fillColor.getHsvF(&h, &s, &v, &a);
h=std::fmod(h+120.0/360.0, 1.0);
m_fillColor.setHsvF(h,s,v,a);
m_fillBrush.setColor(m_fillColor);
m_fillBrush.setStyle(other->getFillStyle());
}
}
void JKQTPGraphFillStyleMixin::initFillStyle(JKQTBasePlotter *parent, int &parentPlotStyle, JKQTPPlotStyleType styletype)
{
if (parent) { // get style settings from parent object

View File

@ -400,6 +400,8 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPGraphFillStyleMixin {
/** \brief initiaize the fill style (from the parent plotter) */
void initFillStyle(JKQTBasePlotter* parent, int &parentPlotStyle, JKQTPPlotStyleType styletype=JKQTPPlotStyleType::Default);
/** \brief initiaize the fill style from another JKQTPGraphFillStyleMixin \a other by inverting its fill color */
void initFillStyleInvertedColor(JKQTPGraphFillStyleMixin *other);
virtual ~JKQTPGraphFillStyleMixin();
@ -434,14 +436,15 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPGraphFillStyleMixin {
Q_PROPERTY(Qt::BrushStyle fillStyle MEMBER m_fillStyle READ getFillStyle WRITE setFillStyle)
Q_PROPERTY(QColor fillColor MEMBER m_fillColor READ getFillColor WRITE setFillColor)
/** \brief constructs a QBrush from the graph fill styling properties */
QBrush getFillBrush(JKQTPEnhancedPainter &painter, JKQTBasePlotter* parent) const;
private:
/** \brief fill style of the graph */
QBrush m_fillBrush;
/** \brief last fill color of the graph */
QColor m_fillColor;
protected:
/** \brief constructs a QBrush from the graph fill styling properties */
QBrush getFillBrush(JKQTPEnhancedPainter &painter, JKQTBasePlotter* parent) const;
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB