improvements to iterator interface (full random access iterators, erase-remove-idion)

added specific example for the iterator interface
This commit is contained in:
jkriege2 2019-05-31 14:01:49 +02:00
parent c56b02998f
commit 6fe42748ed
20 changed files with 831 additions and 75 deletions

View File

@ -80,6 +80,8 @@ addSimpleTest(boxplot)
addSimpleTest(advancedlineandfillstyling)
addSimpleTest(imageplot_nodatastore)
addSimpleTest(datastore)
addSimpleTest(datastore_iterators)
addSimpleTest(datastore_statistics)
addSimpleTest(contourplot)
#addSimpleTest(rgbimageplot_opencv)
#addSimpleTest(imageplot_opencv)

View File

@ -153,9 +153,12 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
<tr><td> \image html simpletest_datastore_small.png
<td> \subpage JKQTPlotterBasicJKQTPDatastore
<td> Basic Data Management with JKQTPDatastore <br/> Copying data into a JKQTPDatastore <br/> Editing data inside a JKQTPDatastore <br/> Editing Image Data in a JKQTPDatastore
<tr><td> \image html simpletest_datastore_iterators_small.png
<td> \subpage JKQTPlotterBasicJKQTPDatastoreIterators
<td> Iterator-based Data Management with JKQTPDatastore
<tr><td> \image html jkqtplotter_simpletest_datastore_statistics_small.png
<td> \subpage JKQTPlotterBasicJKQTPDatastoreStatistics
<td> Advanced 1-Dimensional Statistical Computation with JKQTPODatastore (and the internal statistics library, see \ref jkqtptools_math_statistics )
<td> Advanced 1-Dimensional Statistical Computation with JKQTPDatastore<br>using the internal statistics library (see \ref jkqtptools_math_statistics )<br>basic statistics (mean, standard deviation, ...)<br>boxplots<br>histograms<br>kernel density estimates (KDE)
</table>

View File

@ -12,6 +12,8 @@
- \ref JKQTMathTextSimpleExample
.
\defgroup jkqtmathtext_items JKQTMathText Render-Tree Items
\ingroup jkqtmathtext
*/

View File

@ -58,13 +58,13 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_test_user_interaction_small.gif)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/test_user_interaction) | [User Interaction](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/test_user_interaction) | different possibilities of user-interaction in JKQtPlotter |
## Data Management (Tutorials) & Statistics
## Data Management & Statistics (Tutorials)
| Screenshot | Description | Notes |
|:-------------:| ------------- | ------------- |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/simpletest_datastore_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore) | [Tutorial: Basic Usage of JKQTPDatastore](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore) | Basic Data Management with JKQTPDatastore <br/> Copying data into a JKQTPDatastore <br/> Editing data inside a JKQTPDatastore <br/> Editing Image Data in a JKQTPDatastore |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics) | [Tutorial: Advanced 1-Dimensional Statistics with JKQTPDatastore](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics) | Advanced 1-Dimensional Statistical Computation with JKQTPDatastore (and the internal statistics library) |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/simpletest_datastore_iterators_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_iterators) | [Tutorial: Iterator-based access to JKQTPDatastore](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_iterators) | Iterator-based Data Management with JKQTPDatastore |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics) | [Tutorial: Advanced 1-Dimensional Statistics with JKQTPDatastore](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics) | Advanced 1-Dimensional Statistical Computation with JKQTPDatastore<br>using the internal statistics library<br>basic statistics (mean, standard deviation, ...)<br>boxplots<br>histograms<br>kernel density estimates (KDE) |
## More Complex Examples

View File

@ -1,7 +1,17 @@
# Tutorial (JKQTPlotter): Basic Usage of JKQTPDatastore {#JKQTPlotterBasicJKQTPDatastore}
# Tutorial (JKQTPDatastore): Basic Usage of JKQTPDatastore {#JKQTPlotterBasicJKQTPDatastore}
[JKQTPlotterBasicJKQTPDatastore]: @ref JKQTPlotterBasicJKQTPDatastore "Basic Usage of JKQTPDatastore"
[JKQTPlotterBasicJKQTPDatastoreIterators]: @ref JKQTPlotterBasicJKQTPDatastoreIterators "Iterator-Based usage of JKQTPDatastore"
[JKQTPlotterBasicJKQTPDatastoreStatistics]: @ref JKQTPlotterBasicJKQTPDatastoreStatistics "Advanced 1-Dimensional Statistics with JKQTPDatastore"
[statisticslibrary]: @ref jkqtptools_math_statistics "JKQTPlotter Statistics Library"
This tutorial project (see `./examples/simpletest_datastore/`) explains several options of JKQTPDatastore, which is the class used to centrally store the data for (most) graphs on a JKQTPlotter widget.
***Note*** that there are additional tutorial explaining other aspects of data mangement in JKQTPDatastore:
- [JKQTPlotterBasicJKQTPDatastore]
- [JKQTPlotterBasicJKQTPDatastoreIterators]
- [JKQTPlotterBasicJKQTPDatastoreStatistics]
[TOC]
The source code of the main application can be found in [`jkqtplotter_simpletest_datastore.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore/jkqtplotter_simpletest_datastore.cpp).
@ -14,7 +24,7 @@ In every code-segment below, we will use these two declarations from the code to
JKQTPDatastore* datastore=plot.getDatastore();
```
# Copy Data from different data structures into JKQTPDatastore
# Copying Data from External COntainers into JKQTPDatastore
## Copy Data from a Vector into a column of the JKQTPDatastore
@ -118,7 +128,7 @@ In addition to the variants of `JKQTPDatastore::addColumn()`, that do not transf
It is also possible to leave the data mangement completely to the JKQTPDatastore and just edit the data with access functions from JKQTPDatastore.
## Generating Columns Non-Initialized Columns and Filling Them
## Generating Non-Initialized Columns and Filling Them
The most basic way to generate data for a plot is to generate two non-initialized columns for the x- and y-coordinates of the graph points
```.cpp
@ -140,22 +150,6 @@ Plotting these two columns versus each other results in a simple sine graph:
![simpletest_datastore_sine](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/simpletest_datastore_sine.png)
## Iterator Interface
Alternatively you can also access the column via a C++ iterator:
```.cpp
auto itX=datastore->begin(colX))
auto itY=datastore->begin(colY))
for (; itX!=datastore->end(colX); ++itX, ++itY) {
const double x=double(i)/double(Ndata)*8.0*M_PI;
*itX=x;
*itY=sin(x);
}
```
This, together with `JKQTPDatastore::backInserter()` allows to use `JKQTDatastore` together with algorithms from the C++ standard template libarary and other templated algorithms based on the same iterator-based interfaces (e.g. in boost).
## Generating Columns Preinitialized Columns
@ -325,3 +319,39 @@ The result will look like this (`JKQTPXYParametrizedScatterGraph` on the left an
![simpletest_datastore_image](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/simpletest_datastore_image.png)
# Iterator Interface
Some sections before we discussed a code-fragment
```.cpp
size_t itXColumn=datastore->addColumn(50, "cos curve: x-data");
size_t itYColumn=datastore->addColumn(50, "cos curve: y-data");
for (int i=0; i<datastore->getRows(itXColumn); i++) {
const double x=30.0+i/25.0*M_PI;
datastore->set(itXColumn, i, x);
datastore->set(itYColumn, i, cos(x));
}
```
in which an image was calculated pixel-by-pixel with explicit int indices. Alternatively you can also access the columns via C++ iterators:
```.cpp
auto itX=datastore->begin(colX))
auto itY=datastore->begin(colY))
for (; itX!=datastore->end(colX); ++itX, ++itY) {
const double x=double(i)/double(Ndata)*8.0*M_PI;
*itX=x;
*itY=sin(x);
}
```
All these code fragments result in the same graphs:
![simpletest_datastore_image](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/simpletest_datastore_image.png)
You can also use this interface to interface with algorithms e.g. from the C++ standard template library. E.g. if you want to sort the data in a column, you can simply call
```.cpp
std::sort(datastore->begin(colY), datastore->end(colY));
```
![simpletest_datastore_image_sorted](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/simpletest_datastore_image_sorted.png)
This, together with `JKQTPDatastore::backInserter()` allows to use `JKQTDatastore` together with algorithms from the C++ standard template libarary and other templated algorithms based on the same iterator-based interfaces (e.g. in boost).

View File

@ -8,7 +8,7 @@
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpgraphsscatter.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include <algorithm>
int main(int argc, char* argv[])
{
@ -22,6 +22,11 @@ int main(int argc, char* argv[])
JKQTPColumnMathImage* imggraph;
JKQTPXYParametrizedScatterGraph* paramscattergraph;
/////////////////////////////////////////////////////////////////////////////////////////////////
/// externally provided data (i.e. from different containers)
/////////////////////////////////////////////////////////////////////////////////////////////////
// 2. first we create data inside a QVector for a simple plot (a sine curve) ... and add the plot
// note that you could use a std::vector equally well
QVector<double> X, Y;
@ -43,6 +48,7 @@ int main(int argc, char* argv[])
// 3. Now we generate a plot from data in a C-array, just reference in the JKQTPDatastore
// Note: JKQTPDatastore does not take ownership of your data!
#define NDATA 5
double XCA[NDATA]= { 1, 2, 3, 4, 5 };
double YCA[NDATA]= { 1, 0, 1, 0, 1 };
@ -70,6 +76,10 @@ int main(int argc, char* argv[])
/////////////////////////////////////////////////////////////////////////////////////////////////
/// internally managed data
/////////////////////////////////////////////////////////////////////////////////////////////////
// 5. It is also possible to leave the data mangement completely to the JKQTPDatastore
// and just edit the data with access functions from JKQTPDatastore:
plot.addGraph(linegraph=new JKQTPXYLineGraph(&plot));
@ -129,6 +139,7 @@ int main(int argc, char* argv[])
// 6. autoscale the plot so the graph is contained
plot.zoomToFit();

View File

@ -0,0 +1,106 @@
# Tutorial (JKQTPDatastore): Iterator-Based usage of JKQTPDatastore {#JKQTPlotterBasicJKQTPDatastoreIterators}
[JKQTPlotterBasicJKQTPDatastore]: @ref JKQTPlotterBasicJKQTPDatastore "Basic Usage of JKQTPDatastore"
[JKQTPlotterBasicJKQTPDatastoreIterators]: @ref JKQTPlotterBasicJKQTPDatastoreIterators "Iterator-Based usage of JKQTPDatastore"
[JKQTPlotterBasicJKQTPDatastoreStatistics]: @ref JKQTPlotterBasicJKQTPDatastoreStatistics "Advanced 1-Dimensional Statistics with JKQTPDatastore"
[statisticslibrary]: @ref jkqtptools_math_statistics "JKQTPlotter Statistics Library"
This tutorial project (see `./examples/simpletest_datastore_iterators/`) explains how to use the iterator-based interface to JKQTPDatastore.
***Note*** that there are additional tutorial explaining other aspects of data mangement in JKQTPDatastore:
- [JKQTPlotterBasicJKQTPDatastore]
- [JKQTPlotterBasicJKQTPDatastoreIterators]
- [JKQTPlotterBasicJKQTPDatastoreStatistics]
[TOC]
The source code of the main application can be found in [`jkqtplotter_simpletest_datastore_iterators.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_iterators/jkqtplotter_simpletest_datastore_iterators.cpp).
This tutorial cites parts of this code to demonstrate different ways of working with JKQTPDatastore's iterator-interface.
In every code-segment below, we will use these two declarations from the code to access the internal datastore of the JKQTPlotter instance:
```.cpp
// 1. create a plotter window and get a pointer to the internal datastore (for convenience)
JKQTPlotter plot;
JKQTPDatastore* datastore=plot.getDatastore();
```
In the example [JKQTPlotterBasicJKQTPDatastore] we discussed how to copy data from external container into and explicitly access data in columns inside a JKQTPDatastore. This tutorial explains how to use the iterator interface of JKQTPDatastore to access the data, build columns and also interact with algorithms from the C++ standard template library (or other iterator-based libraries, like e.g. boost). Also have a look at the [statisticslibrary] and [JKQTPlotterBasicJKQTPDatastoreStatistics], as these also use the iterator-interface of JKQTPDatastore.
# Iterator-based Column Data Access To Existing Rows
In other tutorials we used e.g. `JKQTPDatastore::set()` to set values in data columns. Using this scheme, you can write code like shown below to draw a cose curve:
```.cpp
size_t XCol=datastore->addLinearColumn(50, 0, 4.0*M_PI, "cos curve: x-data");
size_t YCol=datastore->addColumn(datastore->getRows(XCol), "cos curve: y-data");
for (size_t i=0; i<datastore->getRows(XCol); i++) {
datastore->set(YCol, i, cos(datastore->get(XCol, i)));
}
```
Here we added two columns with 50 entries. `XCol` contains linearly spaced values between 0 and 2*pi and `YCol` contains 50 uninitialized values. Then we iterate an index `i` over all these items (`datastore->getRows(XCol)` returns the rows in a column, i.e. 50 in the example above) and used `JKQTPDatastore::set()` to store the calculated values in the two columns. The current x-values is read from `XCol` using `JKQTPDatastore::get()`. The resulting plot looks like this:
![simpletest_datastore_iterators_cosine](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/simpletest_datastore_iterators_cosine.png)
The same loop can be written using iterators:
```.cpp
size_t XCol=datastore->addLinearColumn(50, 0, 4.0*M_PI, "cos curve: x-data");
size_t YCol=datastore->addColumn(datastore->getRows(XCol), "cos curve: y-data");
auto itY=datastore->begin(YCol);
for (auto itX=datastore->begin(XCol); itX!=datastore->end(XCol); ++itX, ++itY) {
*itY=cos(*itX);
}
```
# Back-Inserter for Columns
Above we used two previously sized columns and accessed (read and writing) existing rows in them. But `JKQTPDatastore` also provides an iterator comparable to [`std::back_inserter`](https://de.cppreference.com/w/cpp/iterator/back_inserter), which allows to add rows at the end of an existing (here initially empty) column:
```.cpp
size_t XCol=datastore->addColumn("cos curve: x-data");
size_t YCol=datastore->addColumn("cos curve: y-data");
auto biXCol=datastore->backInserter(XCol);
auto biYCol=datastore->backInserter(YCol);
for (double x=0; x<4.0*M_PI; x+=4.0*M_PI/50.0) {
*++biXCol=x;
*++biYCol=cos(x);
}
```
# Using C++ STL algorithms
You can write this a bit more compact, if you use `JKQTPDatastore::addLinearColumn()` and the C++ STL-algorithm [`std::transform()`](https://de.cppreference.com/w/cpp/algorithm/transform):
```.cpp
size_t XCol=datastore->addLinearColumn(50, 0, 4.0*M_PI, "cos curve: x-data");
size_t YCol=datastore->addColumn("cos curve: y-data");
std::transform(datastore->begin(XCol), datastore->end(XCol), datastore->backInserter(YCol), &cos);
```
Of course you can now also interface other algorithms, like e.g. [`std::sort()`](https://de.cppreference.com/w/cpp/algorithm/sort):
```.cpp
std::sort(datastore->begin(colY), datastore->end(colY));
```
With this line of code, the `YCol` is sorted in ascending order and the plot becomes:
![simpletest_datastore_iterators_cosine_ysorted](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/simpletest_datastore_iterators_cosine_ysorted.png)
Another example would be to replace all value `y<-0.5` with the value `1.0` using [`std::replace_if()`](https://de.cppreference.com/w/cpp/algorithm/replace):
```.cpp
std::replace_if(datastore->begin(YCol), datastore->end(YCol), [](double v) { return v<-0.5; }, 1.0);
```
![simpletest_datastore_iterators_cosine_yreplaced](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/simpletest_datastore_iterators_cosine_yreplaced.png)
Finally also the [erase-remove idiom](https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom) (e.g. known from `std::vector`) is supported:
```.cpp
datastore->eraseFromColumn(std::remove_if(datastore->begin(YCol), datastore->end(YCol), [](double v) { return v<0; }), datastore->end(YCol));
```
# Special Properties of the JKQTPDatastore-Iterators
Note that the iterator classes of `JKQTPDatastore` (namely `JKQTPColumnIterator` and `JKQTPColumnConstIterator`) provide additional function to access the properties of the data-column row they point to:
- `JKQTPColumnIterator::isValid()` checks whether the iterator points to a valid row in a column. it is `false` e.g. for an iterator returned by `JKQTPDatastore::end()`
- `JKQTPColumnIterator::getPosition()` returns the row/position inside the column the iterator points to
- `JKQTPColumnIterator::getImagePosition()` / `JKQTPColumnIterator::getImagePositionX()` / `JKQTPColumnIterator::getImagePositionY()` return the x-/y-location of the pointed-to pixel in an image column
- `JKQTPColumnIterator::getImageColumns()` / `JKQTPColumnIterator::getImageRows()` return the width/height of the image represented by the image column (the pointed-to pixel is part of)

View File

@ -0,0 +1,72 @@
/** \example jkqtplotter_simpletest_datastore_iterators.cpp
* Iterator-base data Management in JKQTPDatastore.
*
* \ref JKQTPlotterBasicJKQTPDatastoreIterators
*/
#include <QApplication>
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/jkqtpgraphsscatter.h"
#include "jkqtplotter/jkqtpgraphsimage.h"
#include <algorithm>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
// 1. create a plotter window and get a pointer to the internal datastore (for convenience)
JKQTPlotter plot;
JKQTPDatastore* datastore=plot.getDatastore();
JKQTPXYLineGraph* linegraph;
// 2. now we create a cos-curve plot with the standard means of JKQTPDatastore::addColumn(NRows, "name")
// and JKQTPDatastore::set() to actually set the values:
//size_t XCol=datastore->addLinearColumn(50, 0, 4.0*M_PI, "cos curve: x-data");
//size_t YCol=datastore->addColumn(datastore->getRows(XCol), "cos curve: y-data");
//for (size_t i=0; i<datastore->getRows(XCol); i++) {
// datastore->set(YCol, i, cos(datastore->get(XCol, i)));
//}
// 2.1. the for-loop above can also be expressed in terms of (random-access) iterators:
//auto itY=datastore->begin(YCol);
//for (auto itX=datastore->begin(XCol); itX!=datastore->end(XCol); ++itX, ++itY) {
// *itY=cos(*itX);
//}
// 2.2 with backInserter() you can generate an object liek a std::back_inserter, which
// removes the requirement to pre-allocate the columns:
size_t XCol=datastore->addColumn("cos curve: x-data");
size_t YCol=datastore->addColumn("cos curve: y-data");
auto biXCol=datastore->backInserter(XCol);
auto biYCol=datastore->backInserter(YCol);
for (double x=0; x<4.0*M_PI; x+=4.0*M_PI/50.0) {
*++biXCol=x;
*++biYCol=cos(x);
}
// 2.3 combining with addLinearColumn() you can also use C++ STL algorithms:
//size_t XCol=datastore->addLinearColumn(50, 0, 4.0*M_PI, "cos curve: x-data");
//size_t YCol=datastore->addColumn("cos curve: y-data");
//std::transform(datastore->begin(XCol), datastore->end(XCol), datastore->backInserter(YCol), cos);
// 2.4. Just for fun we can now sort the data:
//std::sort(datastore->begin(YCol), datastore->end(YCol));
// or replace any value <-0.5 with 1:
//std::replace_if(datastore->begin(YCol), datastore->end(YCol), [](double v) { return v<-0.5; }, 1.0);
// 2.5. Also the erase-remove idiom is supported:
//datastore->eraseFromColumn(std::remove_if(datastore->begin(YCol), datastore->end(YCol), [](double v) { return v<0; }), datastore->end(YCol));
plot.addGraph(linegraph=new JKQTPXYLineGraph(&plot));
linegraph->setXColumn(XCol);
linegraph->setYColumn(YCol);
linegraph->setTitle(QObject::tr("cosine graph"));
// 6. autoscale the plot so the graph is contained
plot.zoomToFit();
// show plotter and make it a decent size
plot.show();
plot.resize(600,400);
return app.exec();
}

View File

@ -0,0 +1,27 @@
# source code for this simple demo
SOURCES = jkqtplotter_simpletest_datastore_iterators.cpp
# configure Qt
CONFIG += link_prl qt
QT += core gui xml svg
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
# output executable name
TARGET = jkqtplotter_simpletest_datastore_iterators
# include JKQTPlotter source headers and link against library
DEPENDPATH += ../../lib ../../staticlib/jkqtplotterlib
INCLUDEPATH += ../../lib
CONFIG (debug, debug|release) {
LIBS += -L../../staticlib/jkqtplotterlib/debug -ljkqtplotterlib_debug
} else {
LIBS += -L../../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 jkqtplotter_simpletest_datastore_iterators
jkqtplotterlib.file = ../../staticlib/jkqtplotterlib/jkqtplotterlib.pro
jkqtplotter_simpletest_datastore_iterators.file=$$PWD/jkqtplotter_simpletest_datastore_iterators.pro
jkqtplotter_simpletest_datastore_iterators.depends = jkqtplotterlib

View File

@ -1,7 +1,18 @@
# Tutorial (JKQTPlotter): Advanced 1-Dimensional Statistics with JKQTPDatastore {#JKQTPlotterBasicJKQTPDatastoreStatistics}
# Tutorial (JKQTPDatastore): Advanced 1-Dimensional Statistics with JKQTPDatastore {#JKQTPlotterBasicJKQTPDatastoreStatistics}
This tutorial project (see `./examples/simpletest_datastore_statistics/`) explains several advanced functions of JKQTPDatastore in combination with the statistics library conatined in JKQTPlotter.
[JKQTPlotterBasicJKQTPDatastore]: @ref JKQTPlotterBasicJKQTPDatastore "Basic Usage of JKQTPDatastore"
[JKQTPlotterBasicJKQTPDatastoreIterators]: @ref JKQTPlotterBasicJKQTPDatastoreIterators "Iterator-Based usage of JKQTPDatastore"
[JKQTPlotterBasicJKQTPDatastoreStatistics]: @ref JKQTPlotterBasicJKQTPDatastoreStatistics "Advanced 1-Dimensional Statistics with JKQTPDatastore"
[statisticslibrary]: @ref jkqtptools_math_statistics "JKQTPlotter Statistics Library"
This tutorial project (see `./examples/simpletest_datastore_statistics/`) explains several advanced functions of JKQTPDatastore in combination with the [[statisticslibrary]] conatined in JKQTPlotter.
***Note*** that there are additional tutorial explaining other aspects of data mangement in JKQTPDatastore:
- [JKQTPlotterBasicJKQTPDatastore]
- [JKQTPlotterBasicJKQTPDatastoreIterators]
- [JKQTPlotterBasicJKQTPDatastoreStatistics]
[TOC]
The source code of the main application can be found in [`jkqtplotter_simpletest_datastore_statistics.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/simpletest_datastore_statistics/jkqtplotter_simpletest_datastore_statistics.cpp).
@ -50,7 +61,7 @@ This (if repeated for all three columns) results in a plot like this:
![jkqtplotter_simpletest_datastore_statistics_dataonly](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/jkqtplotter_simpletest_datastore_statistics_dataonly.png)
Based on the raw data we can now use JKQTPlotter's statistics library to calculate some basic properties, like the average (`jkqtpstatAverage()`) or the standard deviation (`jkqtpstatStdDev()`):
Based on the raw data we can now use JKQTPlotter's [statisticslibrary] to calculate some basic properties, like the average (`jkqtpstatAverage()`) or the standard deviation (`jkqtpstatStdDev()`):
```.cpp
size_t N=0;
@ -86,7 +97,7 @@ All these functions use all values in the given range and convert each value to
## Standard Boxplots
As mentioned above and shown in several other examples, JKQTPlotter supports [Boxplots](https://en.wikipedia.org/wiki/Box_plot) with the classes `JKQTPBoxplotHorizontalElement`, `JKQTPBoxplotVerticalElement`, as well as `JKQTPBoxplotHorizontal` and `JKQTPBoxplotVertical`. You can then use the 5-Number Summray functions from the statistics library to calculate the data for such a boxplot (e.g. `jkqtpstat5NumberStatistics()`) and set it up by hand. Code would look roughly like this:
As mentioned above and shown in several other examples, JKQTPlotter supports [Boxplots](https://en.wikipedia.org/wiki/Box_plot) with the classes `JKQTPBoxplotHorizontalElement`, `JKQTPBoxplotVerticalElement`, as well as `JKQTPBoxplotHorizontal` and `JKQTPBoxplotVertical`. You can then use the 5-Number Summray functions from the [statisticslibrary] to calculate the data for such a boxplot (e.g. `jkqtpstat5NumberStatistics()`) and set it up by hand. Code would look roughly like this:
```.cpp
JKQTPStat5NumberStatistics stat=jkqtpstat5NumberStatistics(data.begin(), data.end(), 0.25, .5);
JKQTPBoxplotVerticalElement* res=new JKQTPBoxplotVerticalElement(plotter);
@ -106,7 +117,7 @@ As mentioned above and shown in several other examples, JKQTPlotter supports [Bo
plotter->addGraph(res);
```
In order to save you the work of writing out this code, the statistics library provides "adaptors", such as `jkqtpstatAddVBoxplot()`, which basically implements the code above. Then drawing a boxplot is reduced to:
In order to save you the work of writing out this code, the [statisticslibrary] provides "adaptors", such as `jkqtpstatAddVBoxplot()`, which basically implements the code above. Then drawing a boxplot is reduced to:
```.cpp
JKQTPBoxplotHorizontalElement* gBox2=jkqtpstatAddHBoxplot(plot1box->getPlotter(), datastore1->begin(randomdatacol2), datastore1->end(randomdatacol2), -0.25);
@ -138,7 +149,7 @@ As you can see this restuns the `JKQTPBoxplotHorizontalElement` and in addition
# Histograms
Calculating 1D-Histograms is supported by several functions from the statistics library, e.g. `jkqtpstatHistogram1DAutoranged()`. You can use the result to fill new columns in a `JKQTPDatastore`, which can then be used to draw the histogram (here wit 15 bins, spanning the full data range):
Calculating 1D-Histograms is supported by several functions from the [statisticslibrary], e.g. `jkqtpstatHistogram1DAutoranged()`. You can use the result to fill new columns in a `JKQTPDatastore`, which can then be used to draw the histogram (here wit 15 bins, spanning the full data range):
```.cpp
size_t histcolX=plotter->getDatastore()->addColumn(histogramcolumnBaseName+", bins");
@ -165,7 +176,7 @@ The resulting plot looks like this (the distributions used to generate the rando
# Kernel Density Estimates (KDE)
Especially when only few samples from a distribution are available, histograms are not good at representing the underlying data distribution. In such cases, [Kernel Density Estimates (KDE)](https://en.wikipedia.org/wiki/Kernel_density_estimation) can help, which are basically a smoothed variant of a histogram. The statistics library supports calculating them via e.g. `jkqtpstatKDE1D()`:
Especially when only few samples from a distribution are available, histograms are not good at representing the underlying data distribution. In such cases, [Kernel Density Estimates (KDE)](https://en.wikipedia.org/wiki/Kernel_density_estimation) can help, which are basically a smoothed variant of a histogram. The [statisticslibrary] supports calculating them via e.g. `jkqtpstatKDE1D()`:
```.cpp
size_t kdecolX=plotter->getDatastore()->addColumn(KDEcolumnBaseName+", bins");
@ -188,7 +199,7 @@ The function accepts different kernel functions (any C++ functor `double f(doubl
The three parameters `-5.0, 0.01, 10.0` tell the function `jkqtpstatKDE1D()` to evaluate the KDE at positions between -5 and 10, in steps of 0.01.
Finally the bandwidth constrols the smoothing and the statistics library provides a simple function to estimate it automatically from the data:
Finally the bandwidth constrols the smoothing and the [statisticslibrary] provides a simple function to estimate it automatically from the data:
```.cpp
double kdeBandwidth=jkqtpstatEstimateKDEBandwidth(datastore1->begin(randomdatacol1subset), datastore1->end(randomdatacol1subset));
```

View File

@ -26,23 +26,16 @@
In the context of the sequencer program this is a tool class that can be used by the classes
in the project. E.g. used by JKQTPXParsedFunctionLineGraph, JKQTPYParsedFunctionLineGraph
*/
\defgroup jkmpultil JKQTPMathParser: Utilities
\ingroup jkmp
/**
* \defgroup jkmpultil utilities for JKQTPMathParser function parser class
* \ingroup jkmp
\defgroup jkmpNodes JKQTPMathParser: Memory Representation of Expressions
\ingroup jkmp
\defgroup jkmpErrorhandling JKQTPMathParser Error Handling
\ingroup jkmp
*/
/**
* \defgroup jkmpNodes memory representation of expressions
* \ingroup jkmp
*/
/**
* \defgroup jkmpErrorhandling error handling
* \ingroup jkmp
*/
#include <iostream>
#include <cmath>
#include <string>

View File

@ -714,6 +714,7 @@ class JKQTP_LIB_EXPORT JKQTMathText : public QObject {
public:
/** \brief subclass representing one node in the syntax tree
* \ingroup jkqtmathtext_items
*
* \image html jkqtmathtext_node_geo.png
*/
@ -785,7 +786,9 @@ class JKQTP_LIB_EXPORT JKQTMathText : public QObject {
void doDrawBoxes(QPainter& painter, double x, double y, JKQTMathText::MTenvironment currentEv);
};
/** \brief subclass representing one text node in the syntax tree */
/** \brief subclass representing one text node in the syntax tree
* \ingroup jkqtmathtext_items
*/
class MTtextNode: public MTnode {
public:
MTtextNode(JKQTMathText* parent, const QString& text, bool addWhitespace, bool stripInnerWhitepace=false);
@ -807,7 +810,9 @@ class JKQTP_LIB_EXPORT JKQTMathText : public QObject {
virtual QString textTransform(const QString& text, JKQTMathText::MTenvironment currentEv, bool forSize=false);
};
/** \brief subclass representing one text node in the syntax tree */
/** \brief subclass representing one text node in the syntax tree
* \ingroup jkqtmathtext_items
*/
class MTplainTextNode: public MTtextNode {
public:
MTplainTextNode(JKQTMathText* parent, const QString& text, bool addWhitespace, bool stripInnerWhitepace=false);
@ -817,7 +822,9 @@ class JKQTP_LIB_EXPORT JKQTMathText : public QObject {
/** \copydoc MTtextNode::textTransform() */
virtual QString textTransform(const QString& text, JKQTMathText::MTenvironment currentEv, bool forSize=false) override;
};
/** \brief subclass representing one whitepsace node in the syntax tree */
/** \brief subclass representing one whitepsace node in the syntax tree
* \ingroup jkqtmathtext_items
*/
class MTwhitespaceNode: public MTtextNode {
public:
MTwhitespaceNode(JKQTMathText* parent);
@ -829,7 +836,9 @@ class JKQTP_LIB_EXPORT JKQTMathText : public QObject {
virtual bool toHtml(QString& html, JKQTMathText::MTenvironment currentEv, JKQTMathText::MTenvironment defaultEv) override;
};
/** \brief subclass representing one symbol (e.g. \c \\alpha , \c \\cdot ...) node in the syntax tree */
/** \brief subclass representing one symbol (e.g. \c \\alpha , \c \\cdot ...) node in the syntax tree
* \ingroup jkqtmathtext_items
*/
class MTsymbolNode: public MTnode {
public:
MTsymbolNode(JKQTMathText* parent, const QString& name, bool addWhitespace);
@ -874,6 +883,7 @@ class JKQTP_LIB_EXPORT JKQTMathText : public QObject {
};
/** \brief subclass representing a list of nodes in the syntax tree
* \ingroup jkqtmathtext_items
*/
class MTlistNode: public MTnode {
public:
@ -899,7 +909,9 @@ class JKQTP_LIB_EXPORT JKQTMathText : public QObject {
QSet<QString> subsupOperations;
};
/** \brief subclass representing an instruction node with exactly one argument in the syntax tree */
/** \brief subclass representing an instruction node with exactly one argument in the syntax tree
* \ingroup jkqtmathtext_items
*/
class MTinstruction1Node: public MTnode {
public:
MTinstruction1Node(JKQTMathText* parent, const QString& name, MTnode* child, const QStringList& parameters=QStringList());
@ -938,6 +950,7 @@ class JKQTP_LIB_EXPORT JKQTMathText : public QObject {
/** \brief subclass representing an subscript node with exactly one argument in the syntax tree
* \ingroup jkqtmathtext_items
*
* \image html jkqtmathtext_subscriptnode_getSizeInternal.png
*/
@ -963,6 +976,7 @@ class JKQTP_LIB_EXPORT JKQTMathText : public QObject {
};
/** \brief subclass representing an superscript node with exactly one argument in the syntax tree
* \ingroup jkqtmathtext_items
*
* \image html jkqtmathtext_subscriptnode_getSizeInternal.png
*
@ -990,7 +1004,9 @@ class JKQTP_LIB_EXPORT JKQTMathText : public QObject {
MTnode* child;
};
/** \brief subclass representing a brace node */
/** \brief subclass representing a brace node
* \ingroup jkqtmathtext_items
*/
class MTbraceNode: public MTnode {
public:
MTbraceNode(JKQTMathText* parent, const QString& openbrace, const QString& closebrace, MTnode* child, bool showRightBrace=true);
@ -1031,7 +1047,9 @@ class JKQTP_LIB_EXPORT JKQTMathText : public QObject {
};
/** \brief subclass representing a sqrt node */
/** \brief subclass representing a sqrt node
* \ingroup jkqtmathtext_items
*/
class MTsqrtNode: public MTnode {
public:
MTsqrtNode(JKQTMathText* parent, MTnode* child, int degree=2);
@ -1073,7 +1091,9 @@ class JKQTP_LIB_EXPORT JKQTMathText : public QObject {
static QString fracModeToString(MTfracMode mode);
/** \brief subclass representing a \\frac node */
/** \brief subclass representing a \\frac node
* \ingroup jkqtmathtext_items
*/
class MTfracNode: public MTnode {
public:
MTfracNode(JKQTMathText* parent, MTnode* child_top, MTnode* child_bottom, MTfracMode mode);
@ -1105,7 +1125,9 @@ class JKQTP_LIB_EXPORT JKQTMathText : public QObject {
MTfracMode mode;
};
/** \brief subclass representing a \\begin{matrix} node */
/** \brief subclass representing a \\begin{matrix} node
* \ingroup jkqtmathtext_items
*/
class MTmatrixNode: public MTnode {
public:
MTmatrixNode(JKQTMathText* parent, QVector<QVector<MTnode*> > children);
@ -1152,7 +1174,9 @@ class JKQTP_LIB_EXPORT JKQTMathText : public QObject {
};
static QString decorationToString(MTdecoration mode);
/** \brief subclass representing a decorated text m (e.g. \c \\vec \c \\hat ...) node */
/** \brief subclass representing a decorated text m (e.g. \c \\vec \c \\hat ...) node
* \ingroup jkqtmathtext_items
*/
class MTdecoratedNode: public MTnode {
public:
MTdecoratedNode(JKQTMathText* parent, MTdecoration decoration, MTnode* child);

View File

@ -210,6 +210,20 @@ JKQTPDatastoreItem::JKQTPDatastoreItem(size_t columns, size_t rows){
this->allocated=true;
}
////////////////////////////////////////////////////////////////////////////////////////////////
JKQTPDatastoreItem::JKQTPDatastoreItem(const QVector<double>& data_)
{
this->storageType=StorageType::Internal;
this->allocated=false;
this->dataformat=JKQTPDatastoreItemFormat::SingleColumn;
this->storageType=StorageType::Vector;
this->datavec=data_;
this->data=datavec.data();
this->columns=1;
this->rows=static_cast<int>(data_.size());
this->allocated=true;
}
////////////////////////////////////////////////////////////////////////////////////////////////
bool JKQTPDatastoreItem::resizeColumns(size_t new_rows) {
bool dataRetained=false;

View File

@ -193,6 +193,9 @@ enum class JKQTPDatastoreItemFormat {
* - appendToColumn()
* .
*
* \see \ref JKQTPlotterBasicJKQTPDatastoreIterators
*
*
*
* \subsection jkqtpdatastore_column_management_images Image Column
*
@ -401,6 +404,36 @@ class JKQTP_LIB_EXPORT JKQTPDatastore{
/** \brief returns a const iterator behind the last data entry data in the \a i -th column in the JKQTPDatastore \see JKQTPColumn::const_iterator */
JKQTPColumnConstIterator end(size_t i) const;
/** \brief removes the entry \a pos
*
* \warning If the memory was externally managed before, it will be internally managed afterwards
*
* \warning the iterator \a pos is rendered invalid by this column, as the in some cases the internal column is redefined!
*/
inline void eraseFromColumn(const JKQTPColumnIterator &pos);
/** \brief removes the entry \a pos
*
* \warning If the memory was externally managed before, it will be internally managed afterwards
*
* \warning the iterator \a pos is rendered invalid by this column, as the in some cases the internal column is redefined!
*/
inline void eraseFromColumn(const JKQTPColumnConstIterator &pos);
/** \brief removes the entries \a pos to \a posEnd
*
* \warning If the memory was externally managed before, it will be internally managed afterwards
*
* \warning the iterator \a pos is rendered invalid by this column, as the in some cases the internal column is redefined!
*/
inline void eraseFromColumn(const JKQTPColumnConstIterator &pos, const JKQTPColumnConstIterator &posEnd);
/** \brief removes the entries \a pos to \a posEnd
*
* \warning If the memory was externally managed before, it will be internally managed afterwards
*
* \warning the iterator \a pos is rendered invalid by this column, as the in some cases the internal column is redefined!
*/
inline void eraseFromColumn(const JKQTPColumnIterator &pos, const JKQTPColumnIterator &posEnd);
/** \brief returns a back-inserter iterator (JKQTPColumnBackInserter) to the \a i -th column in the JKQTPDatastore \see JKQTPColumnBackInserter */
JKQTPColumnBackInserter backInserter(int i);
/** \brief returns a back-inserter iterator (JKQTPColumnBackInserter) to the \a i -th column in the JKQTPDatastore \see JKQTPColumnBackInserter */
@ -1249,10 +1282,6 @@ class JKQTP_LIB_EXPORT JKQTPColumn {
QString name;
/** \brief is this item valid?/usable? */
bool valid;
protected:
inline JKQTPDatastore* getDatastore() { return datastore; }
inline const JKQTPDatastore* getDatastore() const { return datastore; }
public:
typedef JKQTPColumnIterator iterator;
typedef JKQTPColumnConstIterator const_iterator;
@ -1268,6 +1297,14 @@ class JKQTP_LIB_EXPORT JKQTPColumn {
inline bool isValid() const { return valid; }
/** \brief two columns are equal, if the same memory in the same datastore is referenced */
inline bool operator==(const JKQTPColumn& other) const {
return (datastoreItem==other.datastoreItem)
&& (datastoreOffset==other.datastoreOffset)
&& (datastore==other.datastore)
&& (valid==other.valid);
}
/*! \copydoc name */
void setName (const QString& __value);
/*! \copydoc name */
@ -1415,8 +1452,22 @@ class JKQTP_LIB_EXPORT JKQTPColumn {
inline const_iterator end() const;
friend class JKQTPDatastore;
friend class JKQTPColumnIterator;
friend class JKQTPColumnConstIterator;
protected:
inline JKQTPDatastore* getDatastore() { return datastore; }
inline const JKQTPDatastore* getDatastore() const { return datastore; }
inline void replaceMemory(size_t datastoreItem_=0, size_t datastoreOffset_=0) {
datastoreItem=datastoreItem_;
datastoreOffset=datastoreOffset_;
}
/** \brief removes the entry \a row */
inline void erase(size_t row);
/** \brief removes the entries \a row to \a rowEnd */
inline void erase(size_t row, size_t rowEnd);
};
/** \brief iterator over the data in the column of a JKQTPDatastore
@ -1447,22 +1498,167 @@ class JKQTPColumnIterator {
inline JKQTPColumnIterator(JKQTPColumnIterator&&)=default;
inline JKQTPColumnIterator& operator=(const JKQTPColumnIterator&)=default;
inline JKQTPColumnIterator& operator=(JKQTPColumnIterator&&)=default;
inline self_type operator++(int /*junk*/) { self_type i = *this; pos_++; return i; }
inline self_type operator++() { pos_++; return *this; }
inline self_type operator--(int /*junk*/) { self_type i = *this; pos_--; return i; }
inline self_type operator--() { pos_--; return *this; }
inline self_type operator+=(int inc) { pos_+=inc; return *this; }
inline self_type operator-=(int dec) { pos_-=dec; return *this; }
inline self_type operator++(int /*junk*/) {
self_type i = *this;
if (!isValid()) pos_++;
return i;
}
inline self_type operator++() {
if (!isValid()) return self_type(col_);
pos_++; return *this;
}
inline self_type operator--(int /*junk*/) {
self_type i = *this;
if (isValid()) {
pos_--;
} else {
JKQTPASSERT(col_);
pos_=static_cast<int>(col_->getRows())-1;
}
return i;
}
inline self_type operator--() {
if (isValid()) {
pos_--;
} else {
JKQTPASSERT(col_);
pos_=static_cast<int>(col_->getRows())-1;
}
return *this;
}
inline self_type operator+=(int inc) {
if (isValid()) {
pos_+=inc;
} else if (inc<0) {
JKQTPASSERT(col_);
pos_=static_cast<int>(col_->getRows())+inc;
}
return *this;
}
inline self_type operator-=(int dec) {
if (isValid()) {
pos_-=dec;
} else {
JKQTPASSERT(col_);
pos_=static_cast<int>(col_->getRows())-dec;
}
return *this;
}
friend self_type operator+(difference_type off, const self_type& right) {
if (right.isValid()) {
return self_type(right.col_, off + right.pos_);
} else {
if (off<0) return self_type(right.col_, off + static_cast<int>(right.col_->getRows()));
else return self_type(right.col_);
}
}
friend self_type operator-(difference_type off, const self_type& right) {
if (right.isValid()) {
return self_type(right.col_, off - right.pos_);
} else {
return self_type(right.col_);
}
}
inline self_type operator+(difference_type rhs) const {
if (isValid()) {
return self_type(col_, pos_+rhs);
} else if (rhs<0){
JKQTPASSERT(col_);
return self_type(col_, static_cast<int>(col_->getRows())+rhs);
} else {
return self_type(col_);
}
}
inline self_type operator-(difference_type rhs) const {
if (isValid()) {
return self_type(col_, pos_-rhs);
} else {
JKQTPASSERT(col_);
return self_type(col_, static_cast<int>(col_->getRows())-rhs);
}
}
inline difference_type operator-(self_type rhs) const {
if (!isValid() && !rhs.isValid()) return 0;
if (!isValid() && rhs.isValid() && col_==rhs.col_) return static_cast<difference_type>(col_->getRows())-rhs.pos_;
if (isValid() && !rhs.isValid() && col_==rhs.col_) return pos_-static_cast<difference_type>(col_->getRows());
JKQTPASSERT(isValid() && rhs.isValid() && col_==rhs.col_);
return pos_-rhs.pos_;
}
/** \brief dereferences the iterator, throws an exception if the iterator is invalid (see isValid() ) or the value does not exist in the column */
inline reference operator*() {
JKQTPASSERT(col_!=nullptr && pos_>=0 && pos_<static_cast<int>(col_->getRows()));
return col_->at(pos_);
}
inline reference operator[](difference_type off) const
{
if (!isValid() && off<0) {
return col_->at(static_cast<int>(col_->getRows())+off);
}
JKQTPASSERT(col_!=nullptr && pos_+off>=0 && pos_+off<static_cast<int>(col_->getRows()));
return col_->at(pos_+off);
}
/** \brief dereferences the iterator, throws an exception if the iterator is invalid (see isValid() ) or the value does not exist in the column */
inline const_reference operator*() const {
JKQTPASSERT(col_!=nullptr && pos_>=0 && pos_<static_cast<int>(col_->getRows()));
return col_->at(pos_);
}
/** \brief comparison operator (less than)
*
* rules:
* - ivalid iterators are never smaller than valid operators
* - two valid operator must reference the same column
* - a valid operator is smaller than another, if it points to a pos_ before another
* .
*
* \see operator<=(), operator>(), operator>=()
* */
inline bool operator<(const self_type& rhs) const {
JKQTPASSERT(isValid() || rhs.isValid());
if (!isValid() && rhs.isValid()) {
return false;
} else if (isValid() && !rhs.isValid()) {
return true;
} else {
JKQTPASSERT(col_ == rhs.col_);
return pos_<rhs.pos_;
}
}
/** \brief comparison operator (less than, or equal)
* \see operator==(), operator<(), operator>(), operator>=()
* */
inline bool operator<=(const self_type& rhs) const {
return operator==(rhs) || operator<(rhs);
}
/** \brief comparison operator (larger than)
*
* rules:
* - ivalid iterators are always larger than valid operators
* - two valid operator must reference the same column
* - a valid operator is smaller than another, if it points to a pos_ before another
* .
*
* \see operator<=(), operator<(), operator>=()
* */
inline bool operator>(const self_type& rhs) const {
JKQTPASSERT(isValid() || rhs.isValid());
if (!isValid() && rhs.isValid()) {
return true;
} else if (isValid() && !rhs.isValid()) {
return false;
} else {
JKQTPASSERT(col_ == rhs.col_);
return pos_>rhs.pos_;
}
}
/** \brief comparison operator (larger than, or equal)
* \see operator==(), operator<(), operator>(), operator<=()
* */
inline bool operator>=(const self_type& rhs) const {
return operator==(rhs) || operator>(rhs);
}
/** \brief comparison operator (equals)
*
* two iterators are equal, if:
@ -1526,6 +1722,7 @@ class JKQTPColumnIterator {
}
friend class JKQTPColumnConstIterator;
friend class JKQTPColumn;
friend class JKQTPDatastore;
protected:
/** \brief returns the referenced column */
inline JKQTPColumn* getColumn() { return col_; }
@ -1631,17 +1828,167 @@ class JKQTPColumnConstIterator {
rhs.pos_=-1;
return *this;
}
inline self_type operator++(int /*junk*/) { self_type i = *this; pos_++; return i; }
inline self_type operator++() { pos_++; return *this; }
inline self_type operator--(int /*junk*/) { self_type i = *this; pos_--; return i; }
inline self_type operator--() { pos_--; return *this; }
inline self_type operator+=(int inc) { pos_+=inc; return *this; }
inline self_type operator-=(int dec) { pos_-=dec; return *this; }
inline self_type operator++(int /*junk*/) {
self_type i = *this;
if (!isValid()) pos_++;
return i;
}
inline self_type operator++() {
if (!isValid()) return self_type(col_);
pos_++; return *this;
}
inline self_type operator--(int /*junk*/) {
self_type i = *this;
if (isValid()) {
pos_--;
} else {
JKQTPASSERT(col_);
pos_=static_cast<int>(col_->getRows())-1;
}
return i;
}
inline self_type operator--() {
if (isValid()) {
pos_--;
} else {
JKQTPASSERT(col_);
pos_=static_cast<int>(col_->getRows())-1;
}
return *this;
}
inline self_type operator+=(int inc) {
if (isValid()) {
pos_+=inc;
} else if (inc<0) {
JKQTPASSERT(col_);
pos_=static_cast<int>(col_->getRows())+inc;
}
return *this;
}
inline self_type operator-=(int dec) {
if (isValid()) {
pos_-=dec;
} else {
JKQTPASSERT(col_);
pos_=static_cast<int>(col_->getRows())-dec;
}
return *this;
}
friend self_type operator+(difference_type off, const self_type& right) {
if (right.isValid()) {
return self_type(right.col_, off + right.pos_);
} else {
if (off<0) return self_type(right.col_, off + static_cast<int>(right.col_->getRows()));
else return self_type(right.col_);
}
}
friend self_type operator-(difference_type off, const self_type& right) {
if (right.isValid()) {
return self_type(right.col_, off - right.pos_);
} else {
return self_type(right.col_);
}
}
inline self_type operator+(difference_type rhs) const {
if (isValid()) {
return self_type(col_, pos_+rhs);
} else if (rhs<0){
JKQTPASSERT(col_);
return self_type(col_, static_cast<int>(col_->getRows())+rhs);
} else {
return self_type(col_);
}
}
inline self_type operator-(difference_type rhs) const {
if (isValid()) {
return self_type(col_, pos_-rhs);
} else {
JKQTPASSERT(col_);
return self_type(col_, static_cast<int>(col_->getRows())-rhs);
}
}
inline difference_type operator-(self_type rhs) const {
if (!isValid() && !rhs.isValid()) return 0;
if (!isValid() && rhs.isValid() && col_==rhs.col_) return static_cast<difference_type>(col_->getRows())-rhs.pos_;
if (isValid() && !rhs.isValid() && col_==rhs.col_) return pos_-static_cast<difference_type>(col_->getRows());
JKQTPASSERT(isValid() && rhs.isValid() && col_==rhs.col_);
return pos_-rhs.pos_;
}
/** \brief dereferences the iterator, throws an exception if the iterator is invalid (see isValid() ) or the value does not exist in the column */
inline reference operator*() const {
inline reference operator*() {
JKQTPASSERT(col_!=nullptr && pos_>=0 && pos_<static_cast<int>(col_->getRows()));
return col_->at(pos_);
}
inline reference operator[](difference_type off) const
{
if (!isValid() && off<0) {
return col_->at(static_cast<int>(col_->getRows())+off);
}
JKQTPASSERT(col_!=nullptr && pos_+off>=0 && pos_+off<static_cast<int>(col_->getRows()));
return col_->at(pos_+off);
}
/** \brief dereferences the iterator, throws an exception if the iterator is invalid (see isValid() ) or the value does not exist in the column */
inline const_reference operator*() const {
JKQTPASSERT(col_!=nullptr && pos_>=0 && pos_<static_cast<int>(col_->getRows()));
return col_->at(pos_);
}
/** \brief comparison operator (less than)
*
* rules:
* - ivalid iterators are never smaller than valid operators
* - two valid operator must reference the same column
* - a valid operator is smaller than another, if it points to a pos_ before another
* .
*
* \see operator<=(), operator>(), operator>=()
* */
inline bool operator<(const self_type& rhs) const {
JKQTPASSERT(isValid() || rhs.isValid());
if (!isValid() && rhs.isValid()) {
return false;
} else if (isValid() && !rhs.isValid()) {
return true;
} else {
JKQTPASSERT(col_ == rhs.col_);
return pos_<rhs.pos_;
}
}
/** \brief comparison operator (less than, or equal)
* \see operator==(), operator<(), operator>(), operator>=()
* */
inline bool operator<=(const self_type& rhs) const {
return operator==(rhs) || operator<(rhs);
}
/** \brief comparison operator (larger than)
*
* rules:
* - ivalid iterators are always larger than valid operators
* - two valid operator must reference the same column
* - a valid operator is smaller than another, if it points to a pos_ before another
* .
*
* \see operator<=(), operator<(), operator>=()
* */
inline bool operator>(const self_type& rhs) const {
JKQTPASSERT(isValid() || rhs.isValid());
if (!isValid() && rhs.isValid()) {
return true;
} else if (isValid() && !rhs.isValid()) {
return false;
} else {
JKQTPASSERT(col_ == rhs.col_);
return pos_>rhs.pos_;
}
}
/** \brief comparison operator (larger than, or equal)
* \see operator==(), operator<(), operator>(), operator<=()
* */
inline bool operator>=(const self_type& rhs) const {
return operator==(rhs) || operator>(rhs);
}
/** \brief comparison operator (equals)
*
* two iterators are equal, if:
@ -1653,7 +2000,7 @@ class JKQTPColumnConstIterator {
* \see operator!=()
* */
inline bool operator==(const self_type& rhs) const {
if (col_ == nullptr && rhs.col_==nullptr) return true;
if (!isValid() && !rhs.isValid()) return true;
if (col_ == rhs.col_) {
if ((pos_<0 || pos_>=static_cast<int>(rhs.col_->getRows())) && (pos_<0 || rhs.pos_>=static_cast<int>(rhs.col_->getRows()))) return true;
return pos_==rhs.pos_;
@ -1665,6 +2012,7 @@ class JKQTPColumnConstIterator {
* \see operator==()
* */
inline bool operator!=(const self_type& rhs) const { return !this->operator==(rhs); }
/** \brief checks the iterator for validity (i.e. points to an existing column and position is in a valid range) */
inline bool isValid() const {
return col_ && pos_>=0 && pos_<static_cast<int>(col_->getRows());
@ -1705,6 +2053,7 @@ class JKQTPColumnConstIterator {
}
friend class JKQTPColumn;
friend class JKQTPDatastore;
protected:
/** \brief returns the referenced column */
inline const JKQTPColumn* getColumn() const { return col_; }
@ -1755,9 +2104,12 @@ class JKQTP_LIB_EXPORT JKQTPDatastoreItem {
protected:
/** \brief hidden default constructor */
JKQTPDatastoreItem();
public:
/** \brief class constructor: initializes the object for internal data storage */
JKQTPDatastoreItem(size_t columns, size_t rows);
/** \brief class constructor: initializes the object for internal data storage with the given data */
JKQTPDatastoreItem(const QVector<double> &data);
/** \brief class constructor: initializes the object for external data storage */
JKQTPDatastoreItem(JKQTPDatastoreItemFormat dataformat, double* data, size_t columns, size_t rows);
/** \brief class constructor: initializes the object for external data storage */
@ -1775,7 +2127,30 @@ class JKQTP_LIB_EXPORT JKQTPDatastoreItem {
inline size_t getColumns() const
{ return columns; }
/** \brief checks whether dataformat==JKQTPDatastoreItemFormat::SingleColumn and storageType==StorageType::Vector */
inline bool isVector() const {
return dataformat==JKQTPDatastoreItemFormat::SingleColumn && storageType==StorageType::Vector;
}
/** \brief if \c isValid() : erase the row \a row */
inline void erase(size_t row) {
JKQTPASSERT(isVector());
datavec.erase(datavec.begin()+row, datavec.end());
rows=static_cast<int>(datavec.size());
data=datavec.data();
}
/** \brief if \c isValid() : erase all rows (and including) from \a row to \a rowEnd */
inline void erase(size_t row, size_t rowEnd) {
if (row>rowEnd) erase(rowEnd, row);
else if (row==rowEnd) erase(row);
else {
JKQTPASSERT(isVector());
if (rowEnd>=static_cast<size_t>(datavec.size())) datavec.erase(datavec.begin()+row, datavec.end());
else datavec.erase(datavec.begin()+row, datavec.begin()+rowEnd);
rows=static_cast<int>(datavec.size());
data=datavec.data();
}
}
/** \brief returns the data at the position (\a column, \a row ).
*
* \note The column index specifies the column inside THIS item, not the global column number. */
@ -1912,7 +2287,6 @@ class JKQTP_LIB_EXPORT JKQTPDatastoreItem {
}
return false;
}
};
@ -1988,6 +2362,16 @@ JKQTPColumn::const_iterator JKQTPColumn::end() const {
return JKQTPColumn::const_iterator(this, -1);
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPColumn::erase(size_t row) {
datastore->getItem(datastoreItem)->erase(row);
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPColumn::erase(size_t row, size_t rowEnd) {
datastore->getItem(datastoreItem)->erase(row, rowEnd);
}
////////////////////////////////////////////////////////////////////////////////////////////////
inline double JKQTPColumn::getValue(size_t n) const {
@ -2018,6 +2402,7 @@ inline double& JKQTPColumn::at(int n) {
return datastore->getItem(datastoreItem)->at(datastoreOffset, static_cast<size_t>(n));
}
////////////////////////////////////////////////////////////////////////////////////////////////
size_t JKQTPDatastore::getRows(size_t column) const {
return columns.value(column).getRows();
@ -2136,6 +2521,74 @@ inline void JKQTPDatastore::appendToColumn(size_t column, TIterator first, TIter
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPDatastore::eraseFromColumn(const JKQTPColumnIterator &pos) {
if (pos.isValid()) {
bool ok=pos.getColumn()->getDatastoreItem()->isVector();
auto itc=columns.key(*pos.getColumn());
if (!ok) {
QVector<double> old_data;
for (auto it=pos.getColumn()->begin(); it!=pos; ++it) old_data.push_back(*it);
size_t itemID=addItem(new JKQTPDatastoreItem(old_data));
columns[itc].replaceMemory(itemID, 0);
} else {
columns[itc].erase(static_cast<size_t>(pos.getPosition()));
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPDatastore::eraseFromColumn(const JKQTPColumnConstIterator &pos) {
if (pos.isValid()) {
bool ok=pos.getColumn()->getDatastoreItem()->isVector();
auto itc=columns.key(*pos.getColumn());
if (!ok) {
QVector<double> old_data;
for (auto it=pos.getColumn()->begin(); it!=pos; ++it) old_data.push_back(*it);
size_t itemID=addItem(new JKQTPDatastoreItem(old_data));
columns[itc].replaceMemory(itemID, 0);
} else {
columns[itc].erase(static_cast<size_t>(pos.getPosition()));
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPDatastore::eraseFromColumn(const JKQTPColumnIterator &pos, const JKQTPColumnIterator &posEnd) {
if (pos.isValid()) {
bool ok=pos.getColumn()->getDatastoreItem()->isVector();
auto itc=columns.key(*pos.getColumn());
if (!ok) {
QVector<double> old_data;
for (auto it=pos.getColumn()->begin(); it!=pos.getColumn()->end(); ++it) old_data.push_back(*it);
size_t itemID=addItem(new JKQTPDatastoreItem(old_data));
columns[itc].replaceMemory(itemID, 0);
}
if (posEnd.isValid()) columns[itc].erase(static_cast<size_t>(pos.getPosition()), static_cast<size_t>(posEnd.getPosition()));
else columns[itc].erase(static_cast<size_t>(pos.getPosition()), static_cast<size_t>(pos.getPosition())+columns[itc].getRows()+1);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
void JKQTPDatastore::eraseFromColumn(const JKQTPColumnConstIterator &pos, const JKQTPColumnConstIterator &posEnd) {
if (pos.isValid()) {
bool ok=pos.getColumn()->getDatastoreItem()->isVector();
auto itc=columns.key(*pos.getColumn());
if (!ok) {
QVector<double> old_data;
for (auto it=pos.getColumn()->begin(); it!=pos.getColumn()->end(); ++it) old_data.push_back(*it);
size_t itemID=addItem(new JKQTPDatastoreItem(old_data));
columns[itc].replaceMemory(itemID, 0);
}
if (posEnd.isValid()) columns[itc].erase(static_cast<size_t>(pos.getPosition()), static_cast<size_t>(posEnd.getPosition()));
else columns[itc].erase(static_cast<size_t>(pos.getPosition()), static_cast<size_t>(pos.getPosition())+columns[itc].getRows()+1);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
inline double JKQTPDatastore::getPixel(size_t column, size_t x, size_t y) const {
return columns.value(column).getPixelValue(x, y);

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB