Image Component Library (ICL)
|
Default AbstractPlotWidget implementation for plotting different kinds of data. More...
#include <LowLevelPlotWidget.h>
Public Member Functions | |
LowLevelPlotWidget (QWidget *parent=0) | |
constructor | |
~LowLevelPlotWidget () | |
destructor | |
virtual utils::Rect32f | getDataViewPort () const |
returns the data viewport | |
void | addSeriesData (const float *data, int len, const AbstractPlotWidget::PenPtr &style=new AbstractPlotWidget::Pen(QColor(255, 0, 0)), const std::string &name="", int stride=1, bool deepCopy=true, bool passOwnerShip=false) |
adds series data | |
void | addBarPlotData (const float *data, int len, const AbstractPlotWidget::PenPtr &style=new AbstractPlotWidget::Pen(QColor(255, 0, 0)), const std::string &name="", int stride=1, bool deepCopy=true, bool passOwnerShip=false) |
adds data for a bar plots | |
void | addScatterData (char symbol, const float *xs, const float *ys, int num, const std::string &name="", int r=255, int g=0, int b=0, int size=5, bool connectingLine=false, int xStride=1, int yStride=1, bool filled=false, bool deepCopyData=true, bool passDataOwnerShip=false) |
adds a list of symbols | |
void | clearScatterData () |
clears the scatter data draw list | |
void | clearSeriesData () |
clears series data draw list | |
void | clearBarPlotData () |
clears the bar plot draw list | |
void | clear () |
clears all contained data | |
Protected Member Functions | |
virtual void | drawLegend (QPainter &p, const utils::Rect &where, bool horizontal) |
internally used | |
virtual bool | drawSeriesData (QPainter &p, const DrawState &state) |
draws the series data | |
virtual bool | drawScatterData (QPainter &p, const DrawState &state) |
draws the sctter data | |
virtual bool | drawBarPlotData (QPainter &p, const DrawState &state) |
draws the bar plot data | |
virtual bool | drawData (QPainter &p) |
draws all the data | |
virtual utils::Range32f | estimateDataXRange () const |
estimates the data xrange (for automatic viewport adaption) | |
virtual utils::Range32f | estimateDataYRange () const |
estimates the data yrange (for automatic viewport adaption) | |
Private Attributes | |
Data * | data |
pimpl |
Default AbstractPlotWidget implementation for plotting different kinds of data.
ICL's plotting framework does also provide a derived class called icl::PlotWidget. We strongly recommend to use the PlotWidget instead of the LowLevelPlotWidget be cause the PlotWidget provides a simpler interface and it's usage is more similar to the usage of ICL's image annotation framework (see ICLDrawWidget and ICLDrawWidget3D). However, in some special situations, the LowLevelPlotWidget provides a better performance, since it can e.g. visualize data that is just linked into it using a shallow copy. In contrast to the LowLevelPlotWidget, the PlotWidget does also provide template methods, that can be used to draw data of all POD types directly. In short: The LowLevelPlotWidget provides a low level interface for data visualization. It's functions are tuned for speed. Usually, the derived class icl::PlotWidget is simpler to use.
So far, the LowLevelPlotWidget can be used as scatter plot, bar-plot and as series-plot (graph-plot). All types can be used in parallel for overlayed visualization.
The scatter plot engine uses a set of data sets, that can be added successively. Each dataset is basically defined by a set of N (x,y) points, where the x- and y- coordinates are both taken from a data pointer that is read using a stride value. To add scatter data, the method LowLevelPlotWidget::addScatterData is provided. Scatter data is usually visualized by scattered colored symbols, and it can be visualized with- and without connecting lines between the points and if the shape that is described by the points is convex, it can also be filled automatically.
In order to draw function graphs, the X-viewport is used in slightly adapted way . Basically, a single function data-set is defined by a 'strided' float array of N elements. If a data-viewport is given to the inherited AbstractPlotWidget, the data X-values (which are not given) are assumed to be equally distributed withing the data-viewport's x-range. If no data viewport is provided, the X-range is automatically estimated to [0, N-1], which is the data index range.
Basically, bar plots are quite similar to function data/series plots. The viewport adaptions is managed indentically here. If several bar plots are used in one graph, the bars of each bin become smaller and the different bins are shown in an interleaved manner. As for function data, the longest bar plot row is used to determine the data x-range if no x-range is provided explicitly.
Please Note: If both, scatter- and function data is given, but not viewport information is available, it is not clear, whether to use the scatter-data X-range or the function data index-range. Therefore, visualizing scatter and function data at once is only supported if the data viewport is given.
The data interfaces are hold very low-level. The provide the option copy given data shallowly and deeply. However drawing the data needs some viewport calculations. Note, in the widget's right-button context menu, you can directly see the rendering time!
Here are some examples, to get an idea of the performance (using a 4-Core Intel(R) Xeon(R) CPU E5530 running at 2.40GHz and an optimized build)
Please note, that the example application can be found at ICLQt/examples/plot-component-demo.cpp the binary name is icl-plot-component-demo.
LowLevelPlotWidget pw; static std::vector<float> sinData(100); // fill it pw.setPropertyValue("tics.y-distance",0.25); pw.setPropertyValue("enable fill",true); pw.addSeriesData(sinData.data(), sinData.size(), new AbstractPlotWidget::Pen(QColor(255,0,0),Qt::NoPen,' ',5, QColor(255,0,0,100)), "sin(x)");
static std::vector<float> tanData(100); // fill it! pw.setPropertyValue("tics.y-distance",0.25); pw.addSeriesData(tanData.data(), tanData.size(), new AbstractPlotWidget::Pen(QColor(0,100,255),Qt::NoPen,' ',2, QColor(0,100,255,100)), "tan(x)");
static std::vector<float> cosData(100); // fill it! pw.setPropertyValue("tics.y-distance",0.25); // we use symbols of radius 2, the 'o' selects circles pw.addSeriesData(cosData.data(), cosData.size(), new AbstractPlotWidget::Pen(QColor(0,255,0),QColor(0,255,0),'o',2, QColor(0,255,0,100)), "cos(x)");
// use sin, cos and tan data from above pw.setPropertyValue("tics.y-distance",0.25); pw.addSeriesData(sinData.data(), sinData.size(), new AbstractPlotWidget::Pen(QColor(255,0,0)), "sin(x)"); pw.addSeriesData(cosData.data(), cosData.size(), new AbstractPlotWidget::Pen(QColor(0,255,0)), "cos(x)"); pw.addSeriesData(tanData.data(), tanData.size(), new AbstractPlotWidget::Pen(QColor(0,100,255)), "tan(x)");
static std::vector<utils::Point32f> scatterData1(10000); // fill it! static std::vector<float> scatterData2(20000); // fill it! pw.setPropertyValue("tics.x-distance",3); pw.setPropertyValue("tics.y-distance",3); pw.addScatterData('.',&scatterData1[0].x,&scatterData1[0].y,scatterData1.size(), "some noise", 255, 0, 0, 2, false, 2, 2, false, false, false); pw.addScatterData('.',&scatterData2[0],&scatterData2[0]+10000,scatterData2.size()/2, "some other noise", 0, 100, 255, 2, false, 1, 1, false, false, false);
static std::vector<utils::Point32f> scatterData3(1000); static utils::Time t = utils::Time::now(); float dtSec = (utils::Time::now()-t).toSecondsDouble(); for(unsigned int i=0;i<scatterData3.size();++i){ float rel = float(i)/(scatterData3.size()-1) * 2 * M_PI; float r = 2 + 3 * sin(4*rel+dtSec); scatterData3[i].x = r * cos(rel); scatterData3[i].y = r * sin(rel); } // again, we use stride values of two for the interleaved data // this time, connectLines is true pw.addScatterData('.',&scatterData3[0].x,&scatterData3[0].y,scatterData3.size(), "some shape", 0, 100, 255, 2, true, 2, 2, true, false, false); pw.addAnnotations('r',FixedMatrix<float,1,4>(-.2,-.2,.4,.4).data() ,1,QColor(255,0,0), QColor(255,0,0,100)); pw.addAnnotations('l',FixedMatrix<float,1,4>(0,0,3,3).data(),1,QColor(255,0,0)); pw.addAnnotations('t',FixedMatrix<float,1,2>(3.f,3.f).data(),1,QColor(255,0,0),Qt::NoBrush,"the center");
icl::qt::LowLevelPlotWidget::LowLevelPlotWidget | ( | QWidget * | parent = 0 | ) |
constructor
destructor
void icl::qt::LowLevelPlotWidget::addBarPlotData | ( | const float * | data, |
int | len, | ||
const AbstractPlotWidget::PenPtr & | style = new AbstractPlotWidget::Pen(QColor(255, 0, 0)) , |
||
const std::string & | name = "" , |
||
int | stride = 1 , |
||
bool | deepCopy = true , |
||
bool | passOwnerShip = false |
||
) |
adds data for a bar plots
Bar plots basically work like function/series data except for the fact, that bars are drawn instead of a (filled) function graph line
void icl::qt::LowLevelPlotWidget::addScatterData | ( | char | symbol, |
const float * | xs, | ||
const float * | ys, | ||
int | num, | ||
const std::string & | name = "" , |
||
int | r = 255 , |
||
int | g = 0 , |
||
int | b = 0 , |
||
int | size = 5 , |
||
bool | connectingLine = false , |
||
int | xStride = 1 , |
||
int | yStride = 1 , |
||
bool | filled = false , |
||
bool | deepCopyData = true , |
||
bool | passDataOwnerShip = false |
||
) |
adds a list of symbols
symbol | symbol type |
xs | x-coordinate pointer (using xStride as stride) |
ys | y-coordinate pointer (using yStride as stride) |
num | number of symbols (i.e. xs and ys have xStride * num elements |
name | |
r | symbol red component |
g | symbol green component |
b | symbol blue component |
size | symbol size (in screen pixels) |
connectingLine | draw a line that connects successive symbols |
xStride | stride for xs-data (in units of sizeof(float), i.e. if the underlying data is interleaved (x,y)-data, the strides are 2 ) |
yStride | stride for ys-data (in units of sizeof(float)) |
filled | defines whether the symbol must be filled (for triangle, circle, rect and diamond only) |
deepCopyData | if set to true, xs, and ys are copied deeply otherwise, they are just linked (via pointer) |
passDataOwnerShip | if set to true, the plot widget will take the ownership of the given data |
void icl::qt::LowLevelPlotWidget::addSeriesData | ( | const float * | data, |
int | len, | ||
const AbstractPlotWidget::PenPtr & | style = new AbstractPlotWidget::Pen(QColor(255, 0, 0)) , |
||
const std::string & | name = "" , |
||
int | stride = 1 , |
||
bool | deepCopy = true , |
||
bool | passOwnerShip = false |
||
) |
adds series data
data | data pointer |
len | number of elements in the data pointer |
style | draw style |
name | |
stride | data stride (in units of sizeof(float)) |
deepCopy | if true, the data is copied into the drawer, otherwise, it is just linked. If the data is linked, it must remain valid until the seriesData is removed using LowLevelPlotWidget::clearSeriesData or LowLevelPlotWidget::clear. |
passOwnerShip | This flag is only used if deepCopy is false. If passOwnerShip is true, the LowLevelPlotWidget will delete the data at deletion or when LowLevelPlotWidget::clearSeriesData or LowLevelPlotWidget::clear is called. |
void icl::qt::LowLevelPlotWidget::clear | ( | ) | [virtual] |
clears all contained data
Reimplemented from icl::qt::AbstractPlotWidget.
Reimplemented in icl::qt::PlotWidget.
clears the bar plot draw list
clears the scatter data draw list
clears series data draw list
virtual bool icl::qt::LowLevelPlotWidget::drawBarPlotData | ( | QPainter & | p, |
const DrawState & | state | ||
) | [protected, virtual] |
draws the bar plot data
virtual bool icl::qt::LowLevelPlotWidget::drawData | ( | QPainter & | p | ) | [protected, virtual] |
draws all the data
Implements icl::qt::AbstractPlotWidget.
virtual void icl::qt::LowLevelPlotWidget::drawLegend | ( | QPainter & | p, |
const utils::Rect & | where, | ||
bool | horizontal | ||
) | [protected, virtual] |
virtual bool icl::qt::LowLevelPlotWidget::drawScatterData | ( | QPainter & | p, |
const DrawState & | state | ||
) | [protected, virtual] |
draws the sctter data
virtual bool icl::qt::LowLevelPlotWidget::drawSeriesData | ( | QPainter & | p, |
const DrawState & | state | ||
) | [protected, virtual] |
draws the series data
virtual utils::Range32f icl::qt::LowLevelPlotWidget::estimateDataXRange | ( | ) | const [protected, virtual] |
estimates the data xrange (for automatic viewport adaption)
virtual utils::Range32f icl::qt::LowLevelPlotWidget::estimateDataYRange | ( | ) | const [protected, virtual] |
estimates the data yrange (for automatic viewport adaption)
virtual utils::Rect32f icl::qt::LowLevelPlotWidget::getDataViewPort | ( | ) | const [virtual] |
returns the data viewport
If the data viewport is not given using AbstractPlotWidget::setDataViewPort
Reimplemented from icl::qt::AbstractPlotWidget.
Data* icl::qt::LowLevelPlotWidget::data [private] |