COPASI API  4.16.103
CopasiPlot.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010 - 2014 by Pedro Mendes, Virginia Tech Intellectual
2 // Properties, Inc., University of Heidelberg, and The University
3 // of Manchester.
4 // All rights reserved.
5 
6 // Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
7 // Properties, Inc., EML Research, gGmbH, University of Heidelberg,
8 // and The University of Manchester.
9 // All rights reserved.
10 
11 // Copyright (C) 2003 - 2007 by Pedro Mendes, Virginia Tech Intellectual
12 // Properties, Inc. and EML Research, gGmbH.
13 // All rights reserved.
14 
15 #include <QtCore/QString>
16 #include <QtGui/QColor> //might need to go to the header file
17 #include <QtGui/QCursor>
18 #include <QtCore/QMutexLocker>
19 
20 #include <qwt_symbol.h>
21 #include <qwt_legend.h>
22 #include <qwt_legend_item.h>
23 #include <qwt_scale_engine.h>
24 
25 #include <limits>
26 #include <algorithm>
27 #include <cmath>
28 
29 #include "scrollzoomer.h"
30 
31 #include "copasi.h"
32 #include "CopasiPlot.h"
33 #include "CQPlotColors.h"
35 #include "UI/qtUtilities.h"
37 #include "model/CModel.h"
39 
40 #define ActivitySize 8
41 
42 //******************** data *********************************************
44  QwtData(),
45  mpX(NULL),
46  mpY(NULL),
47  mSize(0),
48  mMaxSize(0),
49  mLastRectangle(0),
50  mMinX(std::numeric_limits<double>::quiet_NaN()),
51  mMaxX(std::numeric_limits<double>::quiet_NaN()),
52  mMinY(std::numeric_limits<double>::quiet_NaN()),
53  mMaxY(std::numeric_limits<double>::quiet_NaN())
54 {}
55 
57  QwtData(),
58  mpX(x.array()),
59  mpY(y.array()),
60  mSize(size),
61  mMaxSize(x.size()),
62  mLastRectangle(0),
63  mMinX(std::numeric_limits<double>::quiet_NaN()),
64  mMaxX(std::numeric_limits<double>::quiet_NaN()),
65  mMinY(std::numeric_limits<double>::quiet_NaN()),
66  mMaxY(std::numeric_limits<double>::quiet_NaN())
67 {
68  assert(x.size() == y.size());
69  assert(mSize <= mMaxSize);
70 }
71 
73 {}
74 
75 QwtData * C2DCurveData::copy() const
76 {
77  C2DCurveData * pCopy = new C2DCurveData();
78 
79  *pCopy = *this;
80 
81  return pCopy;
82 }
83 
84 size_t C2DCurveData::size() const
85 {
86  return mSize;
87 }
88 
89 double C2DCurveData::x(size_t i) const
90 {
91  return *(mpX + i);
92 }
93 
94 double C2DCurveData::y(size_t i) const
95 {
96  return *(mpY + i);
97 }
98 
99 QwtDoubleRect C2DCurveData::boundingRect() const
100 {
101  if (mSize <= 0)
102  return QwtDoubleRect(1.0, 1.0, -2.0, -2.0); // invalid
103 
104  if (mLastRectangle == mSize)
105  return QwtDoubleRect(mMinX, mMinY, mMaxX - mMinX, mMaxY - mMinY);
106 
107  const double *xIt = mpX + mLastRectangle;
108  const double *yIt = mpY + mLastRectangle;
109  const double *end = mpX + mSize;
110 
111  mLastRectangle = mSize;
112 
113  // We have to remember whether we have an initial NaN
114  bool MinXisNaN = isnan(mMinX);
115  bool MaxXisNaN = isnan(mMaxX);
116  bool MinYisNaN = isnan(mMinY);
117  bool MaxYisNaN = isnan(mMaxY);
118 
119  while (xIt < end)
120  {
121  const double xv = *xIt++;
122 
123  if (!isnan(xv))
124  {
125  if ((xv < mMinX || MinXisNaN) && xv > -std::numeric_limits< double >::infinity())
126  {
127  mMinX = xv;
128  MinXisNaN = false;
129  }
130 
131  if ((xv > mMaxX || MaxXisNaN) && xv < std::numeric_limits< double >::infinity())
132  {
133  mMaxX = xv;
134  MaxXisNaN = false;
135  }
136  }
137 
138  const double yv = *yIt++;
139 
140  if (!isnan(yv))
141  {
142  if ((yv < mMinY || MinYisNaN) && yv > -std::numeric_limits< double >::infinity())
143  {
144  mMinY = yv;
145  MinYisNaN = false;
146  }
147 
148  if ((yv > mMaxY || MaxYisNaN) && yv < std::numeric_limits< double >::infinity())
149  {
150  mMaxY = yv;
151  MaxYisNaN = false;
152  }
153  }
154  }
155 
156  if (isnan(mMinX + mMaxX + mMinY + mMaxY))
157  return QwtDoubleRect(1.0, 1.0, -2.0, -2.0); // invalid
158 
159  // We need to avoid very small data ranges (absolute and relative)
160  C_FLOAT64 minRange = fabs(mMinX + mMaxX) * 5.e-5 + std::numeric_limits< C_FLOAT64 >::min() * 100.0;
161 
162  if (mMaxX - mMinX < minRange)
163  {
164  mMinX = mMinX - minRange * 0.5;
165  mMaxX = mMaxX + minRange * 0.5;
166  }
167 
168  minRange = fabs(mMinY + mMaxY) * 5e-5 + std::numeric_limits< C_FLOAT64 >::min() * 100.0;
169 
170  if (mMaxY - mMinY < minRange)
171  {
172  mMinY = mMinY - minRange * 0.5;
173  mMaxY = mMaxY + minRange * 0.5;
174  }
175 
176  return QwtDoubleRect(mMinX, mMinY, mMaxX - mMinX, mMaxY - mMinY);
177 }
178 
179 void C2DCurveData::setSize(const size_t & size)
180 {
181  mSize = size;
182  assert(mSize <= mMaxSize);
183 }
184 
186 {
187  mpX = pX->array();
188  mpY = pY->array();
189  mMaxSize = pX->size();
190 
191  assert(mSize <= mMaxSize);
192 }
193 
195 {
196  mpX = rhs.mpX;
197  mpY = rhs.mpY;
198  mSize = rhs.mSize;
199  mMaxSize = rhs.mMaxSize;
201  mMinX = rhs.mMinX;
202  mMaxX = rhs.mMaxX;
203  mMinY = rhs.mMinY;
204  mMaxY = rhs.mMaxY;
205 
206  return * this;
207 }
208 
209 //******************** CBandedGraphData *********************************
211  QwtData(),
212  mpX(NULL),
213  mpY1(NULL),
214  mpY2(NULL),
215  mSize(0),
216  mMaxSize(0),
217  mLastRectangle(0),
218  mMinX(std::numeric_limits<double>::quiet_NaN()),
219  mMaxX(std::numeric_limits<double>::quiet_NaN()),
220  mMinY(std::numeric_limits<double>::quiet_NaN()),
221  mMaxY(std::numeric_limits<double>::quiet_NaN())
222 {}
223 
225  const CVector< double > & y1,
226  const CVector< double > & y2,
227  size_t size):
228  QwtData(),
229  mpX(x.array()),
230  mpY1(y1.array()),
231  mpY2(y2.array()),
232  mSize(size),
233  mMaxSize(x.size()),
234  mLastRectangle(0),
235  mMinX(std::numeric_limits<double>::quiet_NaN()),
236  mMaxX(std::numeric_limits<double>::quiet_NaN()),
237  mMinY(std::numeric_limits<double>::quiet_NaN()),
238  mMaxY(std::numeric_limits<double>::quiet_NaN())
239 {
240  assert(x.size() == y1.size());
241  assert(x.size() == y2.size());
242  assert(mSize <= mMaxSize);
243 }
244 
246 {}
247 
248 QwtData *
250 {
251  CBandedGraphData * pCopy = new CBandedGraphData();
252 
253  *pCopy = *this;
254 
255  return pCopy;
256 }
257 
258 size_t
260 {return 2 * mSize;}
261 
262 double CBandedGraphData::x(size_t i) const
263 {
264  // to make a polygon out of the two data curves
265  // one curve goes in order, the other backwards
266  if (i >= mSize)
267  i = (2 * mSize - i - 1);
268 
269  return *(mpX + i);
270 }
271 
272 double CBandedGraphData::y(size_t i) const
273 {
274  double ret;
275 
276  // to make a polygon out of the two data curves
277  // one curve goes in order, the other backwards
278  if (i < mSize)
279  ret = *(mpY1 + i);
280  else
281  ret = *(mpY2 + (2 * mSize - i - 1));
282 
283  return ret;
284 }
285 
286 double CBandedGraphData::y1(size_t i) const
287 {
288  return *(mpY1 + i);
289 }
290 
291 double CBandedGraphData::y2(size_t i) const
292 {
293  return *(mpY2 + i);
294 }
295 
296 QwtDoubleRect
298 {
299  if (mSize <= 0)
300  return QwtDoubleRect(1.0, 1.0, -2.0, -2.0); // invalid
301 
302  if (mLastRectangle == mSize)
303  return QwtDoubleRect(mMinX, mMinY, mMaxX - mMinX, mMaxY - mMinY);
304 
305  const double *xIt = mpX + mLastRectangle;
306  const double *yIt1 = mpY1 + mLastRectangle;
307  const double *yIt2 = mpY2 + mLastRectangle;
308  const double *end = mpX + mSize;
309 
310  mLastRectangle = mSize;
311 
312  // We have to remember whether we have an initial NaN
313  bool MinXisNaN = isnan(mMinX);
314  bool MaxXisNaN = isnan(mMaxX);
315  bool MinYisNaN = isnan(mMinY);
316  bool MaxYisNaN = isnan(mMaxY);
317 
318  while (xIt < end)
319  {
320  const double xv = *xIt++;
321 
322  if (!isnan(xv))
323  {
324  if (xv < mMinX || MinXisNaN)
325  {
326  mMinX = xv;
327  MinXisNaN = false;
328  }
329 
330  if (xv > mMaxX || MaxXisNaN)
331  {
332  mMaxX = xv;
333  MaxXisNaN = false;
334  }
335  }
336 
337  double yv1 = *yIt1++;
338  double yv2 = *yIt2++;
339 
340  if (isnan(yv1) || isnan(yv2))
341  {
342  yv1 = isnan(yv1) ? yv2 : yv1;
343  yv2 = yv1;
344  }
345  else if (yv1 > yv2)
346  {
347  double tmp = yv1;
348  yv1 = yv2;
349  yv2 = tmp;
350  } // now: yv1 <= yv2
351 
352  if (!isnan(yv1))
353  {
354  if (yv1 < mMinY || MinYisNaN)
355  {
356  mMinY = yv1;
357  MinYisNaN = false;
358  }
359 
360  if (yv2 > mMaxY || MaxYisNaN)
361  {
362  mMaxY = yv2;
363  MaxYisNaN = false;
364  }
365  }
366  }
367 
368  if (isnan(mMinX + mMaxX + mMinY + mMaxY))
369  return QwtDoubleRect(1.0, 1.0, -2.0, -2.0); // invalid
370 
371  // We need to avoid very small data ranges (absolute and relative)
372  C_FLOAT64 minRange = fabs(mMinX + mMaxX) * 5.e-5 + std::numeric_limits< C_FLOAT64 >::min() * 100.0;
373 
374  if (mMaxX - mMinX < minRange)
375  {
376  mMinX = mMinX - minRange * 0.5;
377  mMaxX = mMaxX + minRange * 0.5;
378  }
379 
380  minRange = fabs(mMinY + mMaxY) * 5e-5 + std::numeric_limits< C_FLOAT64 >::min() * 100.0;
381 
382  if (mMaxY - mMinY < minRange)
383  {
384  mMinY = mMinY - minRange * 0.5;
385  mMaxY = mMaxY + minRange * 0.5;
386  }
387 
388  return QwtDoubleRect(mMinX, mMinY, mMaxX - mMinX, mMaxY - mMinY);
389 }
390 
391 void
392 CBandedGraphData::setSize(const size_t & size)
393 {
394  mSize = size;
395  assert(mSize <= mMaxSize);
396 }
397 
398 void
400 {
401  mpX = pX->array();
402  mpY1 = pY1->array();
403  mpY2 = pY2->array();
404  mMaxSize = pX->size();
405 
406  assert(mSize <= mMaxSize);
407 }
408 
410 {
411  mpX = rhs.mpX;
412  mpY1 = rhs.mpY1;
413  mpY2 = rhs.mpY2;
414  mSize = rhs.mSize;
415  mMaxSize = rhs.mMaxSize;
417  mMinX = rhs.mMinX;
418  mMaxX = rhs.mMaxX;
419  mMinY = rhs.mMinY;
420  mMaxY = rhs.mMaxY;
421 
422  return * this;
423 }
424 
425 //******************** data *********************************************
427  QwtData(),
428  mpX(NULL),
429  mSize(0),
430  mMaxSize(0),
431  mLastRectangle(0),
432  mMinX(std::numeric_limits<double>::quiet_NaN()),
433  mMaxX(std::numeric_limits<double>::quiet_NaN()),
434  mMinY(std::numeric_limits<double>::quiet_NaN()),
435  mMaxY(std::numeric_limits<double>::quiet_NaN()),
436  mIncrement(1.0),
437  mMap(),
438  mHistoX(0),
439  mHistoY(0)
440 {}
441 
443  size_t size,
444  const C_FLOAT64 & increment):
445  QwtData(),
446  mpX(x.array()),
447  mSize(size),
448  mMaxSize(x.size()),
449  mLastRectangle(0),
450  mMinX(std::numeric_limits<double>::quiet_NaN()),
451  mMaxX(std::numeric_limits<double>::quiet_NaN()),
452  mMinY(std::numeric_limits<double>::quiet_NaN()),
453  mMaxY(std::numeric_limits<double>::quiet_NaN()),
454  mIncrement(increment),
455  mMap(),
456  mHistoX(0),
457  mHistoY(0)
458 {
459  assert(mSize <= mMaxSize);
460 }
461 
463 {}
464 
465 QwtData * CHistoCurveData::copy() const
466 {
467  CHistoCurveData * pCopy = new CHistoCurveData();
468 
469  *pCopy = *this;
470 
471  return pCopy;
472 }
473 
474 size_t CHistoCurveData::size() const
475 {
476  return mHistoX.size();
477 }
478 
479 double CHistoCurveData::x(size_t i) const
480 {
481  return mHistoX[i];
482 }
483 
484 double CHistoCurveData::y(size_t i) const
485 {
486  return mHistoY[i];
487 }
488 
489 QwtDoubleRect CHistoCurveData::boundingRect() const
490 {
491  if (mSize <= 0)
492  return QwtDoubleRect(1.0, 1.0, -2.0, -2.0); // invalid
493 
494  if (mLastRectangle == mSize)
495  return QwtDoubleRect(mMinX, mMinY, mMaxX - mMinX, mMaxY - mMinY);
496 
497  const double *xIt = mpX + mLastRectangle;
498  const double *end = mpX + mSize;
499 
500  mLastRectangle = mSize;
501 
502  double InvIncrement = 1.0 / mIncrement;
503 
504  for (; xIt != end; ++xIt)
505  {
506  //just ignore breaks. Later we perhaps want to start a new histogram...
507  if (isnan(*xIt)) //NaN
508  continue;
509 
510  if (-std::numeric_limits< C_FLOAT64 >::infinity() < *xIt &&
511  *xIt < std::numeric_limits< C_FLOAT64 >::infinity())
512  {
513  mMap[(C_INT32) floor(*xIt * InvIncrement)]++;
514  mMap[(C_INT32) floor(*xIt * InvIncrement) + 1];
515  }
516  }
517 
518  //construct arrays
519  mHistoX.resize(mMap.size() + 1);
520  mHistoY.resize(mMap.size() + 1);
521 
522  double *pX = mHistoX.array();
523  double *pY = mHistoY.array();
524 
525  //add one bin to the left
526  if (mMap.size() > 0)
527  {
528  *pX = (mMap.begin()->first - 1) * mIncrement;
529  }
530  else
531  {
532  *pX = 0.0;
533  }
534 
535  *pY = 0.0;
536 
537  mMinX = mMaxX = *pX++;
538  mMinY = mMaxY = *pY++;
539 
540  C_FLOAT64 tmpFactor = 1.0 / (mSize * mIncrement);
541  std::map<C_INT32, C_INT32>::const_iterator it = mMap.begin();
542  std::map<C_INT32, C_INT32>::const_iterator itEnd = mMap.end();
543 
544  for (; it != itEnd; ++it, ++pX, ++pY)
545  {
546  //TODO use pointer increments instead of [...]
547  *pX = it->first * mIncrement;
548  *pY = (double)it->second * 100.0 / (double)mSize;
549 
550  if (*pX < mMinX)
551  mMinX = *pX;
552 
553  if (*pX > mMaxX)
554  mMaxX = *pX;
555 
556  if (*pY < mMinY)
557  mMinY = *pY;
558 
559  if (*pY > mMaxY)
560  mMaxY = *pY;
561  }
562 
563  return QwtDoubleRect(mMinX, mMinY, mMaxX - mMinX, mMaxY - mMinY);
564 }
565 
566 void CHistoCurveData::setSize(const size_t & size)
567 {
568  mSize = size;
569  assert(mSize <= mMaxSize);
570 }
571 
573 {
574  mpX = pX->array();
575  mMaxSize = pX->size();
576 
577  assert(mSize <= mMaxSize);
578 }
579 
581 {
582  mpX = rhs.mpX;
583  mSize = rhs.mSize;
584  mMaxSize = rhs.mMaxSize;
585 
587  mMinX = rhs.mMinX;
588  mMaxX = rhs.mMaxX;
589  mMinY = rhs.mMinY;
590  mMaxY = rhs.mMaxY;
591 
592  mIncrement = rhs.mIncrement;
593  mMap = rhs.mMap;
594  mHistoX = rhs.mHistoX;
595  mHistoY = rhs.mHistoY;
596 
597  return * this;
598 }
599 
600 //******************** curve ********************************************
601 
602 void C2DPlotCurve::setDataSize(const size_t & size)
603 {
604  switch (mCurveType)
605  {
606  case CPlotItem::curve2d:
607  static_cast< C2DCurveData * >(&data())->setSize(size);
608  break;
609 
611  static_cast< CBandedGraphData * >(&data())->setSize(size);
612  break;
613 
615  static_cast< CHistoCurveData * >(&data())->setSize(size);
616  break;
617 
618  default:
619  fatalError();
620  break;
621  }
622 }
623 
625 {
626 
627  switch (mCurveType)
628  {
629  case CPlotItem::curve2d:
630  static_cast< C2DCurveData * >(&data())->reallocated(pX, pY);
631  break;
632 
634  static_cast< CBandedGraphData * >(&data())->reallocated(pX, pY, pY2);
635  break;
636 
638  static_cast< CHistoCurveData * >(&data())->reallocated(pX);
639  break;
640 
641  default:
642  fatalError();
643  break;
644  }
645 }
646 
647 void C2DPlotCurve::setIncrement(const C_FLOAT64 & increment)
648 {
649  mIncrement = increment;
650 }
651 
653 {
654  return mIncrement;
655 }
656 
658 {
659  return mCurveType;
660 }
661 
663 {
664  return mActivity;
665 }
666 
667 //draw the several curves, separated by NaNs.
668 void C2DPlotCurve::myDrawLines(QPainter *painter,
669  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
670  int from, int to) const
671 {
672  int to2;
673 
674  do
675  {
676  int i;
677 
678  for (i = from; i <= to; ++i)
679  if (isnan(x(i)) || isnan(y(i))) //NaN
680  break;
681 
682  if (i == from)
683  {
684  ++from;
685  continue;
686  }
687 
688  to2 = i - 1;
689 
690  QwtPlotCurve::drawLines(painter, xMap, yMap, from, to2);
691 
692  from = to2 + 2;
693  }
694  while (from < to);
695 }
696 
697 //virtual
698 void C2DPlotCurve::drawCurve(QPainter *painter, int style,
699  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
700  int from, int to) const
701 {
702  QMutexLocker Locker(mpMutex);
703 
704  if (style == Lines)
705  {
706  myDrawLines(painter, xMap, yMap, from, to);
707  }
708  else
709  {
710  QwtPlotCurve::drawCurve(painter, style, xMap, yMap, from, to);
711  }
712 }
713 
714 void C2DPlotCurve::drawSymbols(QPainter *painter, const QwtSymbol &symbol,
715  const QwtScaleMap &xMap, const QwtScaleMap &yMap,
716  int from, int to) const
717 {
718 
719  int from2 = from;
720  int to2;
721 
722  for (;;)
723  {
724 
725  //find the next not-NaN point
726  while (isnan(x(from2)) || isnan(y(from2)))
727  {
728  ++from2;
729 
730  if (from2 >= to)
731  return;
732  }
733 
734  //find the nex NaN point (or the end of data)
735  to2 = from2;
736 
737  do
738  {
739  ++to2;
740 
741  if (to2 > to)
742  break;
743  }
744  while (!(isnan(x(to2)) || isnan(y(to2))));
745 
746  --to2;
747 
748  QwtPlotCurve::drawSymbols(painter, symbol, xMap, yMap, from2, to2);
749 
750  //are we done?
751  if (to2 >= to)
752  return;
753 
754  //continue with the next data point
755  from2 = to2 + 1;
756  }
757 }
758 
759 //************************************
760 C_FLOAT64 CopasiPlot::MissingValue = std::numeric_limits<C_FLOAT64>::quiet_NaN();
761 
762 CopasiPlot::CopasiPlot(QWidget* parent):
763  QwtPlot(parent),
764  mCurves(0),
765  mCurveMap(),
766  mDataBefore(0),
767  mDataDuring(0),
768  mDataAfter(0),
769  mHaveBefore(false),
770  mHaveDuring(false),
771  mHaveAfter(false),
772  mpPlotSpecification(NULL),
773  mNextPlotTime(),
774  mIgnoreUpdate(false),
775  mpZoomer(NULL),
776  mReplotFinished(false)
777 {}
778 
779 CopasiPlot::CopasiPlot(const CPlotSpecification* plotspec, QWidget* parent):
780  QwtPlot(parent),
781  mCurves(0),
782  mCurveMap(),
783  mDataBefore(0),
784  mDataDuring(0),
785  mDataAfter(0),
786  mHaveBefore(false),
787  mHaveDuring(false),
788  mHaveAfter(false),
789  mpPlotSpecification(NULL),
790  mNextPlotTime(),
791  mIgnoreUpdate(false),
792  mpZoomer(NULL),
793  mReplotFinished(false)
794 {
795  QwtLegend *legend = new QwtLegend;
796  legend->setItemMode(QwtLegend::CheckableItem);
797 
798  // whole legend can not be displayed at bottom on DARWIN
799  // maybe a Qwt bug ?!?
800 #ifdef Darwin
801  insertLegend(legend, QwtPlot::TopLegend);
802 #else
803  insertLegend(legend, QwtPlot::BottomLegend);
804 #endif
805 
806  // Set up the zoom facility
807  mpZoomer = new ScrollZoomer(canvas());
808  mpZoomer->setRubberBandPen(QColor(Qt::black));
809  mpZoomer->setTrackerPen(QColor(Qt::black));
810  mpZoomer->setTrackerMode(QwtPicker::AlwaysOn);
811  mpZoomer->setTrackerFont(this->font());
812 
813  // white background better for printing...
814  setCanvasBackground(Qt::white);
815 
816  // setTitle(FROM_UTF8(plotspec->getTitle()));
817  setCanvasLineWidth(0);
818 
819  canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, true);
820 
821  connect(this, SIGNAL(legendChecked(QwtPlotItem *, bool)),
822  SLOT(showCurve(QwtPlotItem *, bool)));
823 
824  // Size the vectors to be able to store information for all activities.
825  mData.resize(ActivitySize);
826  mObjectValues.resize(ActivitySize);
828  mDataSize.resize(ActivitySize);
829  mDataIndex.clear();
830 
831  // Initialize from the plot specification
832  initFromSpec(plotspec);
833  connect(this, SIGNAL(replotSignal()), this, SLOT(replot()));
834 }
835 
837 {
838  mIgnoreUpdate = true;
839  mpPlotSpecification = plotspec;
840 
841  if (mpZoomer) mpZoomer->setEnabled(false);
842 
843  // size_t k, kmax = mpPlotSpecification->getItems().size();
844 
845  setTitle(FROM_UTF8(mpPlotSpecification->getTitle()));
846 
848  mCurves = NULL;
849 
850  std::map< std::string, C2DPlotCurve * >::iterator found;
851 
854 
856  Visible = true;
857  bool * pVisible = Visible.array();
858 
859  for (; itPlotItem != endPlotItem; ++itPlotItem, ++pVisible)
860  {
861  // Qwt does not like it to reuse the curve as this may lead to access
862  // violation. We therefore delete the curves but remember their visibility.
863  if ((found = mCurveMap.find((*itPlotItem)->CCopasiParameter::getKey())) != mCurveMap.end())
864  {
865  *pVisible = found->second->isVisible();
866  }
867  }
868 
869  // Remove unused curves if definition has changed
870  std::map< std::string, C2DPlotCurve * >::iterator it = mCurveMap.begin();
871  std::map< std::string, C2DPlotCurve * >::iterator end = mCurveMap.end();
872 
873  for (; it != end; ++it)
874  pdelete(it->second);
875 
876  mCurveMap.clear();
877 
878  itPlotItem = mpPlotSpecification->getItems().begin();
879  pVisible = Visible.array();
880  C2DPlotCurve ** ppCurve = mCurves.array();
881  unsigned long int k = 0;
882  bool needLeft = false;
883  bool needRight = false;
884 
885  for (; itPlotItem != endPlotItem; ++itPlotItem, ++pVisible, ++ppCurve, ++k)
886  {
887  // set up the curve
888  C2DPlotCurve * pCurve = new C2DPlotCurve(&mMutex,
889  (*itPlotItem)->getType(),
890  (*itPlotItem)->getActivity(),
891  FROM_UTF8((*itPlotItem)->getTitle()));
892  *ppCurve = pCurve;
893 
894  mCurveMap[(*itPlotItem)->CCopasiParameter::getKey()] = pCurve;
895 
896  //color handling should be similar for different curve types
897  QColor color;
898 
899  if (pCurve->getType() == CPlotItem::curve2d
900  || pCurve->getType() == CPlotItem::histoItem1d
901  || pCurve->getType() == CPlotItem::bandedGraph)
902  {
903  std::string colorstr = *(*itPlotItem)->getValue("Color").pSTRING;
904  color = CQPlotColors::getColor(colorstr, k);
905  }
906 
907  pCurve->setPen(color);
908  pCurve->attach(this);
909 
910  showCurve(pCurve, *pVisible);
911 
912  if (pCurve->getType() == CPlotItem::curve2d
913  || pCurve->getType() == CPlotItem::bandedGraph)
914  {
915  needLeft = true;
916  pCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
917 
918  unsigned C_INT32 linetype = *(*itPlotItem)->getValue("Line type").pUINT;
919 
920  if (linetype == 0 //line
921  || linetype == 3) //line+symbols
922  {
923  pCurve->setStyle(QwtPlotCurve::Lines);
924  unsigned C_INT32 linesubtype = *(*itPlotItem)->getValue("Line subtype").pUINT;
925  C_FLOAT64 width = *(*itPlotItem)->getValue("Line width").pUDOUBLE;
926 
927  switch (linesubtype) //symbol type
928  {
929  case 1:
930  pCurve->setPen(QPen(QBrush(color), width, Qt::DotLine, Qt::FlatCap));
931  break;
932 
933  case 2:
934  pCurve->setPen(QPen(QBrush(color), width, Qt::DashLine));
935  break;
936 
937  case 3:
938  pCurve->setPen(QPen(QBrush(color), width, Qt::DashDotLine));
939  break;
940 
941  case 4:
942  pCurve->setPen(QPen(QBrush(color), width, Qt::DashDotDotLine));
943  break;
944 
945  case 0:
946  default:
947  pCurve->setPen(QPen(QBrush(color), width, Qt::SolidLine));
948  break;
949  }
950  }
951 
952  if (linetype == 1) //points
953  {
954  C_FLOAT64 width = *(*itPlotItem)->getValue("Line width").pUDOUBLE;
955  pCurve->setPen(QPen(color, width, Qt::SolidLine, Qt::RoundCap));
956  pCurve->setStyle(QwtPlotCurve::Dots);
957  }
958 
959  if (linetype == 2) //only symbols
960  {
961  pCurve->setStyle(QwtPlotCurve::NoCurve);
962  }
963 
964  if (linetype == 2 //symbols
965  || linetype == 3) //line+symbols
966  {
967  unsigned C_INT32 symbolsubtype = *(*itPlotItem)->getValue("Symbol subtype").pUINT;
968 
969  switch (symbolsubtype) //symbol type
970  {
971  case 1:
972  pCurve->setSymbol(QwtSymbol(QwtSymbol::Cross, QBrush(), QPen(QBrush(color), 2), QSize(7, 7)));
973  break;
974 
975  case 2:
976  pCurve->setSymbol(QwtSymbol(QwtSymbol::Ellipse, QBrush(), QPen(QBrush(color), 1), QSize(8, 8)));
977  break;
978 
979  case 0:
980  default:
981  pCurve->setSymbol(QwtSymbol(QwtSymbol::Cross, QBrush(color), QPen(QBrush(color), 1), QSize(5, 5)));
982  break;
983  }
984  }
985  } //2d curves and banded graphs
986 
987  if (pCurve->getType() == CPlotItem::bandedGraph)
988  {
989  //set fill color
990  QColor c = color;
991  c.setAlpha(64);
992  pCurve->setBrush(c);
993  }
994 
995  if (pCurve->getType() == CPlotItem::histoItem1d)
996  {
997  pCurve->setIncrement(*(*itPlotItem)->getValue("increment").pDOUBLE);
998 
999  pCurve->setStyle(QwtPlotCurve::Steps);
1000  pCurve->setYAxis(QwtPlot::yRight);
1001  pCurve->setCurveAttribute(QwtPlotCurve::Inverted);
1002 
1003  needRight = true;
1004  }
1005  }
1006 
1007  if (plotspec->isLogX())
1008  setAxisScaleEngine(xBottom, new QwtLog10ScaleEngine());
1009  else
1010  setAxisScaleEngine(xBottom, new QwtLinearScaleEngine());
1011 
1012  setAxisAutoScale(xBottom);
1013 
1014  if (plotspec->isLogY())
1015  setAxisScaleEngine(yLeft, new QwtLog10ScaleEngine());
1016  else
1017  setAxisScaleEngine(yLeft, new QwtLinearScaleEngine());
1018 
1019  setAxisAutoScale(yLeft);
1020 
1021  enableAxis(yLeft, needLeft);
1022 
1023  if (needRight)
1024  {
1025  setAxisScaleEngine(yRight, new QwtLinearScaleEngine());
1026  setAxisTitle(yRight, "Percent %");
1027  enableAxis(yRight);
1028  }
1029 
1030  mIgnoreUpdate = false;
1031 
1032  return true; //TODO really check!
1033 }
1034 
1035 bool CopasiPlot::compile(std::vector< CCopasiContainer * > listOfContainer,
1036  const CCopasiDataModel* pDataModel)
1037 {
1038  clearBuffers();
1039 
1040  size_t i, imax;
1041  size_t j, jmax;
1042 
1043  std::pair< std::set< const CCopasiObject * >::iterator, bool > Inserted;
1044  std::pair< Activity, size_t > DataIndex;
1045  std::vector< std::set < const CCopasiObject * > > ActivityObjects;
1046 
1047  ActivityObjects.resize(ActivitySize);
1048 
1049  // Loop over all curves.
1050  imax = mpPlotSpecification->getItems().size();
1051  mDataIndex.resize(imax);
1052 
1053  std::vector< std::vector < const CCopasiObject * > >::iterator itX;
1054  assert(pDataModel != NULL);
1055 
1056  for (i = 0; i < imax; ++i)
1057  {
1058  CPlotItem * pItem = mpPlotSpecification->getItems()[i];
1059  Activity ItemActivity = pItem->getActivity();
1060  DataIndex.first = ItemActivity;
1061 
1062  // Loop over all channels
1063  jmax = pItem->getNumChannels();
1064  mDataIndex[i].resize(jmax);
1065 
1066  for (j = 0; j < jmax; ++j)
1067  {
1068  const CCopasiObject* pObj =
1069  pDataModel->ObjectFromName(listOfContainer, pItem->getChannels()[j]);
1070 
1071  if (pObj)
1072  mObjects.insert(pObj);
1073  else
1075  pItem->getChannels()[j].c_str());
1076 
1077  // Remember the actual order for saving the data.
1078  // Note, we are currently only dealing with 2D curves and histograms.
1079  // In addition the data is not normalized. The same data column may appear
1080  // multiple times, e.g. as X value and as Y value for another curve.
1081  if (j == 0)
1082  {
1083  // We have an X value
1084  for (itX = mSaveCurveObjects.begin(); itX != mSaveCurveObjects.end(); ++itX)
1085  if (*itX->begin() == pObj) break;
1086 
1087  if (itX == mSaveCurveObjects.end())
1088  {
1089  std::vector < const CCopasiObject * > NewX;
1090  NewX.push_back(pObj);
1091 
1092  mSaveCurveObjects.push_back(NewX);
1093  itX = mSaveCurveObjects.end() - 1;
1094 
1095  setAxisUnits(xBottom, pObj);
1096  }
1097 
1098  if (pItem->getType() == CPlotItem::histoItem1d)
1099  mSaveHistogramObjects.push_back(pObj);
1100  }
1101  else
1102  {
1103  itX->push_back(pObj);
1104  setAxisUnits(yLeft, pObj);
1105  }
1106 
1107  Inserted = ActivityObjects[ItemActivity].insert(pObj);
1108 
1109  if (Inserted.second)
1110  {
1111  if (ItemActivity & COutputInterface::BEFORE) mHaveBefore = true;
1112 
1113  if (ItemActivity & COutputInterface::DURING) mHaveDuring = true;
1114 
1115  if (ItemActivity & COutputInterface::AFTER) mHaveAfter = true;
1116 
1117  // The insert was successful
1118  DataIndex.second = ActivityObjects[ItemActivity].size() - 1;
1119 
1120  // Allocate the data buffer
1121  mData[ItemActivity].push_back(new CVector<double>(1000));
1122 
1123  // Store the pointer to the current object value. (Only if it has a double or integer value
1124  // and the value pointer actually exists. If not, use a dummy value.)
1125  void * tmp;
1126 
1127  if ((pObj && (pObj->isValueInt() || pObj->isValueDbl())) && (tmp = pObj->getValuePointer()))
1128  {
1129  mObjectValues[ItemActivity].push_back((C_FLOAT64 *) tmp); //pObj->getValuePointer());
1130  mObjectInteger[ItemActivity].push_back(pObj->isValueInt());
1131  }
1132  else
1133  {
1134  mObjectValues[ItemActivity].push_back(&MissingValue);
1135  mObjectInteger[ItemActivity].push_back(false);
1136  }
1137 
1138  // Store [curve][channel] to data index
1139  mDataIndex[i][j] = DataIndex;
1140 
1141  // Store the [Activity][object] to data index.
1142  mObjectIndex[ItemActivity][pObj] = DataIndex.second;
1143  }
1144  else
1145  {
1146  // The object already existed we only need to
1147  // store [curve][channel] to data index.
1148  DataIndex.second = mObjectIndex[ItemActivity][pObj];
1149  mDataIndex[i][j] = DataIndex;
1150  }
1151  }
1152  }
1153 
1154  // We need to set the curve data here!
1155  size_t k = 0;
1156  C2DPlotCurve ** itCurves = mCurves.array();
1157  C2DPlotCurve ** endCurves = itCurves + mCurves.size();
1158 
1159  for (; itCurves != endCurves; ++itCurves, ++k)
1160  {
1161  std::vector< CVector< double > * > & data = mData[(*itCurves)->getActivity()];
1162 
1163  switch ((*itCurves)->getType())
1164  {
1165  case CPlotItem::curve2d:
1166  (*itCurves)->setData(C2DCurveData(*data[mDataIndex[k][0].second],
1167  *data[mDataIndex[k][1].second],
1168  0));
1169  break;
1170 
1172  (*itCurves)->setData(CBandedGraphData(*data[mDataIndex[k][0].second],
1173  *data[mDataIndex[k][1].second],
1174  *data[mDataIndex[k][2].second],
1175  0));
1176  break;
1177 
1179  (*itCurves)->setData(CHistoCurveData(*data[mDataIndex[k][0].second],
1180  0,
1181  mCurves[k]->getIncrement()));
1182 
1183  break;
1184 
1185  default:
1186  fatalError();
1187  break;
1188  }
1189  }
1190 
1192  mReplotFinished = true;
1193 
1194  return true;
1195 }
1196 
1197 void CopasiPlot::output(const Activity & activity)
1198 {
1199  size_t i, imax;
1200  C_INT32 ItemActivity;
1201 
1202  if (mHaveBefore && (activity == COutputInterface::BEFORE)) mDataBefore++;
1203  else if (mHaveDuring && (activity == COutputInterface::DURING)) mDataDuring++;
1204  else if (mHaveAfter && (activity == COutputInterface::AFTER)) mDataAfter++;
1205 
1206  for (ItemActivity = 0; ItemActivity < ActivitySize; ItemActivity++)
1207  if ((ItemActivity & activity) && mData[ItemActivity].size())
1208  {
1209  std::vector< CVector< double > * > & data = mData[ItemActivity];
1210  size_t & ndata = mDataSize[ItemActivity];
1211 
1212  if ((imax = data.size()) != 0)
1213  {
1214  if (ndata >= data[0]->size())
1215  {
1216  resizeCurveData(ItemActivity);
1217  }
1218 
1219  //the data that needs to be stored internally:
1220  for (i = 0; i < imax; ++i)
1221  if (mObjectInteger[ItemActivity][i])
1222  (*data[i])[ndata] = *(C_INT32 *)mObjectValues[ItemActivity][i];
1223  else
1224  (*data[i])[ndata] = *mObjectValues[ItemActivity][i];
1225 
1226  ++ndata;
1227  }
1228  }
1229 
1230  updatePlot();
1231 }
1232 
1233 void CopasiPlot::separate(const Activity & activity)
1234 {
1235  size_t i, imax;
1236  C_INT32 ItemActivity;
1237 
1238  if (mHaveBefore && (activity == COutputInterface::BEFORE)) mDataBefore++;
1239 
1240  if (mHaveDuring && (activity == COutputInterface::DURING)) mDataDuring++;
1241 
1242  if (mHaveAfter && (activity == COutputInterface::AFTER)) mDataAfter++;
1243 
1244  for (ItemActivity = 0; ItemActivity < ActivitySize; ItemActivity++)
1245  if ((ItemActivity & activity) && mData[ItemActivity].size())
1246  {
1247  std::vector< CVector< double > * > & data = mData[ItemActivity];
1248  size_t & ndata = mDataSize[ItemActivity];
1249 
1250  if ((imax = data.size()) != 0)
1251  {
1252  if (ndata >= data[0]->size())
1253  {
1254  resizeCurveData(ItemActivity);
1255  }
1256 
1257  //the data that needs to be stored internally:
1258  for (i = 0; i < imax; ++i)
1259  (*data[i])[ndata] = MissingValue;
1260 
1261  ++ndata;
1262  }
1263  }
1264 
1265  updatePlot();
1266 
1267  return;
1268 }
1269 
1271 {
1272  // We need to force a replot, i.e., the next mNextPlotTime should be in the past.
1273  mNextPlotTime = 0;
1274  replot();
1275 
1276  if (mpZoomer)
1277  {
1278  mpZoomer->setEnabled(true);
1279  mpZoomer->setZoomBase();
1280  }
1281 }
1282 
1283 void CopasiPlot::updateCurves(const size_t & activity)
1284 {
1285  if (activity == C_INVALID_INDEX)
1286  {
1287  C_INT32 ItemActivity;
1288 
1289  for (ItemActivity = 0; ItemActivity < ActivitySize; ItemActivity++)
1290  updateCurves(ItemActivity);
1291 
1292  return;
1293  }
1294 
1295  size_t k = 0;
1296  C2DPlotCurve ** itCurves = mCurves.array();
1297  C2DPlotCurve ** endCurves = itCurves + mCurves.size();
1298 
1299  for (; itCurves != endCurves; ++itCurves, ++k)
1300  if ((size_t)(*itCurves)->getActivity() == activity)
1301  {
1302  (*itCurves)->setDataSize(mDataSize[activity]);
1303  }
1304 }
1305 
1306 void CopasiPlot::resizeCurveData(const size_t & activity)
1307 {
1308  std::vector< CVector< double > * > & data = mData[activity];
1309  std::vector< CVector< double > * >::iterator it = data.begin();
1310 
1311  std::vector< CVector< double > * > OldData = data;
1312  std::vector< CVector< double > * >::iterator itOld = OldData.begin();
1313  std::vector< CVector< double > * >::iterator endOld = OldData.end();
1314 
1315  size_t oldSize = (*it)->size();
1316  size_t newSize = 2 * (*it)->size();
1317 
1318  // We must not deallocate the old data since this will create a window of time
1319  // were the GUI thread may access the old location before it is notified.
1320  for (; itOld != endOld; ++itOld, ++it)
1321  {
1322  *it = new CVector< double >(newSize);
1323  memcpy((*it)->array(), (*itOld)->array(), oldSize * sizeof(double));
1324  }
1325 
1326  // Tell the curves that the location of the data has changed
1327  // otherwise repaint events could crash
1328  size_t k = 0;
1329  C2DPlotCurve ** itCurves = mCurves.array();
1330  C2DPlotCurve ** endCurves = itCurves + mCurves.size();
1331 
1332  for (; itCurves != endCurves; ++itCurves, ++k)
1333  {
1334  if ((size_t)(*itCurves)->getActivity() == activity)
1335  {
1336  std::vector< CVector< double > * > & data = mData[activity];
1337 
1338  switch ((*itCurves)->getType())
1339  {
1340  case CPlotItem::curve2d:
1341  (*itCurves)->reallocatedData(data[mDataIndex[k][0].second],
1342  data[mDataIndex[k][1].second]);
1343  break;
1344 
1346  (*itCurves)->reallocatedData(data[mDataIndex[k][0].second],
1347  data[mDataIndex[k][1].second],
1348  data[mDataIndex[k][2].second]);
1349  break;
1350 
1352  (*itCurves)->reallocatedData(data[mDataIndex[k][0].second],
1353  NULL);
1354  break;
1355 
1356  default:
1357  fatalError();
1358  break;
1359  }
1360  }
1361  }
1362 
1363  // It is now save to delete the old data since the GUI thread has been notified.
1364  for (itOld = OldData.begin(); itOld != endOld; ++itOld)
1365  {
1366  pdelete(*itOld);
1367  }
1368 }
1369 
1371 {
1372  if (mReplotFinished)
1373  {
1374  mReplotFinished = false;
1375  emit replotSignal();
1376  }
1377 }
1378 
1379 //-----------------------------------------------------------------------------
1380 
1381 /*void CopasiPlot::enableZoom(bool enabled)
1382 {
1383  zoomOn = enabled;
1384 }*/
1385 
1386 //-----------------------------------------------------------------------------
1387 
1389 {
1390  clearBuffers();
1391 }
1392 
1393 bool CopasiPlot::saveData(const std::string & filename)
1394 {
1395  // No objects.
1396  if (!mObjects.size()) return true;
1397 
1398  // Find out whether we have any data.
1399  C_INT32 ItemActivity;
1400 
1401  for (ItemActivity = 0; ItemActivity < ActivitySize; ItemActivity++)
1402  if (mDataSize[ItemActivity] != 0) break;
1403 
1404  // No data
1405  if (ItemActivity == ActivitySize) return true;
1406 
1407  std::ofstream fs(CLocaleString::fromUtf8(filename).c_str());
1408 
1409  if (!fs.good()) return false;
1410 
1411  // Write the table header
1412  fs << "# ";
1413 
1414  std::vector< std::vector < const CCopasiObject * > >::const_iterator itX;
1415  std::vector< std::vector < const CCopasiObject * > >::const_iterator endX =
1416  mSaveCurveObjects.end();
1417 
1418  std::vector < const CCopasiObject * >::const_iterator it;
1419  std::vector < const CCopasiObject * >::const_iterator end;
1420 
1421  for (itX = mSaveCurveObjects.begin(); itX != endX; ++itX)
1422  for (it = itX->begin(), end = itX->end(); it != end; ++it)
1423  if (*it != NULL)
1424  fs << (*it)->getObjectDisplayName() << "\t";
1425  else
1426  fs << "Not found\t";
1427 
1428  fs << "\n";
1429 
1430  size_t i, imax = mObjects.size();
1431  std::vector< CVector< double > * > Data;
1432  Data.resize(imax);
1433 
1434  std::vector< CVector< double > * >::const_iterator itData;
1435  std::vector< CVector< double > * >::const_iterator endData = Data.end();
1436 
1437  std::vector< size_t > Offset;
1438  std::vector< size_t >::const_iterator itOffset;
1439 
1440  Offset.resize(imax);
1441 
1442  std::map< Activity, std::map< const CCopasiObject *, size_t > >::iterator itActivity;
1443  std::map< const CCopasiObject *, size_t >::iterator itObject;
1444 
1445  if (mDataBefore)
1446  {
1447  for (itX = mSaveCurveObjects.begin(), i = 0; itX != endX; ++itX)
1448  for (it = itX->begin(), end = itX->end(); it != end; ++it, ++i)
1449  {
1450  if ((itActivity = mObjectIndex.find(COutputInterface::BEFORE)) != mObjectIndex.end() &&
1451  (itObject = itActivity->second.find(*it)) != itActivity->second.end())
1452  {
1453  Data[i] = mData[COutputInterface::BEFORE][itObject->second];
1454  continue;
1455  }
1456 
1458  (itObject = itActivity->second.find(*it)) != itActivity->second.end())
1459  {
1460  Data[i] = mData[COutputInterface::BEFORE | COutputInterface::DURING][itObject->second];
1461  continue;
1462  }
1463 
1465  (itObject = itActivity->second.find(*it)) != itActivity->second.end())
1466  {
1467  Data[i] = mData[COutputInterface::BEFORE | COutputInterface::AFTER][itObject->second];
1468  continue;
1469  }
1470 
1472  (itObject = itActivity->second.find(*it)) != itActivity->second.end())
1473  {
1475  continue;
1476  }
1477 
1478  Data[i] = NULL;
1479  }
1480 
1481  for (i = 0; i < mDataBefore; i++)
1482  {
1483  for (itData = Data.begin(); itData != endData; ++itData)
1484  {
1485  if (*itData) fs << (**itData)[i];
1486  else fs << MissingValue;
1487 
1488  fs << "\t";
1489  }
1490 
1491  fs << std::endl;
1492  }
1493  }
1494 
1495  if (mDataDuring)
1496  {
1497  for (itX = mSaveCurveObjects.begin(), i = 0; itX != endX; ++itX)
1498  for (it = itX->begin(), end = itX->end(); it != end; ++it, ++i)
1499  {
1500  if ((itActivity = mObjectIndex.find(COutputInterface::DURING)) != mObjectIndex.end() &&
1501  (itObject = itActivity->second.find(*it)) != itActivity->second.end())
1502  {
1503  Data[i] = mData[COutputInterface::DURING][itObject->second];
1504  Offset[i] = 0;
1505  continue;
1506  }
1507 
1509  (itObject = itActivity->second.find(*it)) != itActivity->second.end())
1510  {
1511  Data[i] = mData[COutputInterface::BEFORE | COutputInterface::DURING][itObject->second];
1512  Offset[i] = mDataBefore;
1513  continue;
1514  }
1515 
1517  (itObject = itActivity->second.find(*it)) != itActivity->second.end())
1518  {
1519  Data[i] = mData[COutputInterface::DURING | COutputInterface::AFTER][itObject->second];
1520  Offset[i] = 0;
1521  continue;
1522  }
1523 
1525  (itObject = itActivity->second.find(*it)) != itActivity->second.end())
1526  {
1528  Offset[i] = mDataBefore;
1529  continue;
1530  }
1531 
1532  Data[i] = NULL;
1533  }
1534 
1535  for (i = 0; i < mDataDuring; i++)
1536  {
1537  for (itData = Data.begin(), itOffset = Offset.begin(); itData != endData; ++itData)
1538  {
1539  if (*itData) fs << (**itData)[i + *itOffset];
1540  else fs << MissingValue;
1541 
1542  fs << "\t";
1543  }
1544 
1545  fs << std::endl;
1546  }
1547  }
1548 
1549  if (mDataAfter)
1550  {
1551  for (itX = mSaveCurveObjects.begin(), i = 0; itX != endX; ++itX)
1552  for (it = itX->begin(), end = itX->end(); it != end; ++it, ++i)
1553  {
1554  if ((itActivity = mObjectIndex.find(COutputInterface::AFTER)) != mObjectIndex.end() &&
1555  (itObject = itActivity->second.find(*it)) != itActivity->second.end())
1556  {
1557  Data[i] = mData[COutputInterface::AFTER][itObject->second];
1558  Offset[i] = 0;
1559  continue;
1560  }
1561 
1563  (itObject = itActivity->second.find(*it)) != itActivity->second.end())
1564  {
1565  Data[i] = mData[COutputInterface::BEFORE | COutputInterface::AFTER][itObject->second];
1566  Offset[i] = mDataBefore;
1567  continue;
1568  }
1569 
1571  (itObject = itActivity->second.find(*it)) != itActivity->second.end())
1572  {
1573  Data[i] = mData[COutputInterface::DURING | COutputInterface::AFTER][itObject->second];
1574  Offset[i] = mDataDuring;
1575  continue;
1576  }
1577 
1579  (itObject = itActivity->second.find(*it)) != itActivity->second.end())
1580  {
1582  Offset[i] = mDataBefore + mDataDuring;
1583  continue;
1584  }
1585 
1586  Data[i] = NULL;
1587  }
1588 
1589  for (i = 0; i < mDataAfter; i++)
1590  {
1591  for (itData = Data.begin(), itOffset = Offset.begin(); itData != endData; ++itData)
1592  {
1593  if (*itData) fs << (**itData)[i + *itOffset];
1594  else fs << MissingValue;
1595 
1596  fs << "\t";
1597  }
1598 
1599  fs << std::endl;
1600  }
1601  }
1602 
1603  bool FirstHistogram = true;
1604  size_t HistogramIndex = 0;
1605 
1606  C2DPlotCurve ** itCurves = mCurves.array();
1607  C2DPlotCurve ** endCurves = itCurves + mCurves.size();
1608 
1609  for (; itCurves != endCurves; ++itCurves)
1610  {
1611  if ((*itCurves)->getType() == CPlotItem::histoItem1d)
1612  {
1613  if (FirstHistogram)
1614  {
1615  fs << "\n# The histograms: \n";
1616  FirstHistogram = false;
1617  }
1618 
1619  if (mSaveHistogramObjects[HistogramIndex] != NULL)
1620  fs << mSaveHistogramObjects[HistogramIndex]->getObjectDisplayName();
1621  else
1622  fs << "Not found";
1623 
1624  fs << std::endl;
1625 
1626  CHistoCurveData * pData = static_cast< CHistoCurveData * >(&(*itCurves)->data());
1627  size_t i, imax = pData->size();
1628 
1629  for (i = 0; i < imax; ++i)
1630  {
1631  fs << pData->x(i) << "\t" << pData->y(i) << "\n";
1632  }
1633  }
1634  }
1635 
1636  fs.close();
1637 
1638  if (!fs.good()) return false;
1639 
1640  return true;
1641 }
1642 
1643 void CopasiPlot::showCurve(QwtPlotItem *item, bool on)
1644 {
1645  item->setVisible(on);
1646  item->setItemAttribute(QwtPlotItem::AutoScale, on);
1647  QWidget *w = legend()->find(item);
1648 
1649  if (w && w->inherits("QwtLegendItem"))
1650  static_cast< QwtLegendItem * >(w)->setChecked(on);
1651 
1652  if (!mIgnoreUpdate)
1653  replot();
1654 }
1655 
1656 void CopasiPlot::setCurvesVisibility(const bool & visibility)
1657 {
1658  std::map< std::string, C2DPlotCurve * >::iterator it = mCurveMap.begin();
1659  std::map< std::string, C2DPlotCurve * >::iterator end = mCurveMap.end();
1660 
1661  for (; it != end; ++it)
1662  {
1663  it->second->setVisible(visibility);
1664  it->second->setItemAttribute(QwtPlotItem::AutoScale, visibility);
1665  QWidget *w = legend()->find(it->second);
1666 
1667  if (w && w->inherits("QwtLegendItem"))
1668  static_cast< QwtLegendItem * >(w)->setChecked(visibility);
1669  }
1670 
1671  if (!mIgnoreUpdate)
1672  replot();
1673 }
1674 
1676 {
1677  mObjects.clear();
1678 
1679  size_t Activity;
1680  size_t i, imax;
1681 
1682  for (Activity = 0; Activity < ActivitySize; Activity++)
1683  {
1684  std::vector< CVector< double > * > & data = mData[Activity];
1685 
1686  // Delete each QMemArray
1687  for (i = 0, imax = data.size(); i < imax; i++)
1688  if (data[i] != NULL) delete data[i];
1689 
1690  data.clear();
1691 
1692  mObjectValues[Activity].clear();
1693  mObjectInteger[Activity].clear();
1694  mDataSize[Activity] = 0;
1695  }
1696 
1697  mDataIndex.clear();
1698  mObjectIndex.clear();
1699 
1700  mSaveCurveObjects.clear();
1701  mSaveHistogramObjects.clear();
1702 
1703  mDataBefore = 0;
1704  mDataDuring = 0;
1705  mDataAfter = 0;
1706 
1707  mHaveBefore = false;
1708  mHaveDuring = false;
1709  mHaveAfter = false;
1710 }
1711 
1713  const CCopasiObject * pObject)
1714 {
1715  if (pObject == NULL) return;
1716 
1717  std::string Units = pObject->getUnits();
1718 
1719  if (Units != "")
1720  setAxisTitle(index, FROM_UTF8(Units));
1721 
1722  return;
1723 }
1724 
1725 // virtual
1727 {
1729  {
1731 
1732  {
1733  QMutexLocker Locker(&mMutex);
1735  }
1736 
1737  QwtPlot::replot();
1738 
1739  Delta = CCopasiTimeVariable::getCurrentWallTime() - Delta;
1741  }
1742 
1743  mReplotFinished = true;
1744 }
std::vector< size_t > mDataSize
Definition: CopasiPlot.h:370
CPlotItem::Type mCurveType
Definition: CopasiPlot.h:208
virtual size_t size() const
Definition: CopasiPlot.cpp:474
void resizeCurveData(const size_t &activity)
CVector< double > mHistoX
Definition: CopasiPlot.h:159
bool isValueInt() const
static C_FLOAT64 MissingValue
Definition: CopasiPlot.h:334
static QColor getColor(std::string colorstr, size_t colorindex)
CBandedGraphData & operator=(const CBandedGraphData &rhs)
Definition: CopasiPlot.cpp:409
#define pdelete(p)
Definition: copasi.h:215
#define FROM_UTF8(__x)
Definition: qtUtilities.h:73
virtual void separate(const Activity &activity)
void setIncrement(const C_FLOAT64 &increment)
Definition: CopasiPlot.cpp:647
size_t mDataAfter
Definition: CopasiPlot.h:416
CopasiPlot(QWidget *parent=NULL)
Definition: CopasiPlot.cpp:762
bool mHaveBefore
Definition: CopasiPlot.h:422
virtual ~CHistoCurveData()
Definition: CopasiPlot.cpp:462
double mMinX
Definition: CopasiPlot.h:72
const CPlotSpecification * mpPlotSpecification
Definition: CopasiPlot.h:439
virtual double x(size_t i) const
Definition: CopasiPlot.cpp:479
virtual size_t size() const
virtual size_t size() const
Definition: CopasiPlot.cpp:84
virtual QwtDoubleRect boundingRect() const
Definition: CopasiPlot.cpp:489
std::map< std::string, C2DPlotCurve * > mCurveMap
Definition: CopasiPlot.h:391
iterator begin()
#define fatalError()
bool mIgnoreUpdate
Definition: CopasiPlot.h:449
double y2(size_t i) const
Definition: CopasiPlot.cpp:291
void setSize(const size_t &size)
Definition: CopasiPlot.cpp:566
std::vector< CPlotDataChannelSpec > & getChannels()
Definition: CPlotItem.cpp:214
size_t getNumChannels() const
Definition: CPlotItem.cpp:220
void resize(size_t size, const bool &copy=false)
Definition: CVector.h:301
#define C_INVALID_INDEX
Definition: copasi.h:222
void setCurvesVisibility(const bool &visibility)
double y1(size_t i) const
Definition: CopasiPlot.cpp:286
virtual double y(size_t i) const
Definition: CopasiPlot.cpp:272
std::vector< std::vector< const CCopasiObject * > > mSaveCurveObjects
Definition: CopasiPlot.h:360
virtual QwtDoubleRect boundingRect() const
Definition: CopasiPlot.cpp:297
double mMaxY
Definition: CopasiPlot.h:75
size_t mDataBefore
Definition: CopasiPlot.h:406
#define C_INT32
Definition: copasi.h:90
CHistoCurveData & operator=(const CHistoCurveData &rhs)
Definition: CopasiPlot.cpp:580
size_t mSize
Definition: CopasiPlot.h:68
std::vector< std::vector< bool > > mObjectInteger
Definition: CopasiPlot.h:354
virtual QwtData * copy() const
Definition: CopasiPlot.cpp:465
virtual QwtDoubleRect boundingRect() const
Definition: CopasiPlot.cpp:99
const CPlotItem::Type & getType() const
Definition: CopasiPlot.cpp:657
void setSize(const size_t &size)
Definition: CopasiPlot.cpp:179
void updatePlot()
virtual void replot()
virtual ~CopasiPlot()
bool mHaveDuring
Definition: CopasiPlot.h:428
#define MCCopasiTask
void setAxisUnits(const C_INT32 &index, const CCopasiObject *pObject)
void updateCurves(const size_t &activity)
void reallocated(const CVector< double > *pX)
Definition: CopasiPlot.cpp:572
iterator end()
#define ActivitySize
Definition: CopasiPlot.cpp:40
virtual double x(size_t i) const
Definition: CopasiPlot.cpp:89
virtual bool compile(std::vector< CCopasiContainer * > listOfContainer, const CCopasiDataModel *pDataModel)
const C_FLOAT64 & getIncrement() const
Definition: CopasiPlot.cpp:652
CVector< double > mHistoY
Definition: CopasiPlot.h:160
void reallocated(const CVector< double > *pX, const CVector< double > *pY)
Definition: CopasiPlot.cpp:185
std::vector< std::vector< std::pair< Activity, size_t > > > mDataIndex
Definition: CopasiPlot.h:375
std::map< Activity, std::map< const CCopasiObject *, size_t > > mObjectIndex
Definition: CopasiPlot.h:381
const double * mpX
Definition: CopasiPlot.h:107
QMutex mMutex
Definition: CopasiPlot.h:339
double mMinY
Definition: CopasiPlot.h:74
QwtPlotZoomer * mpZoomer
Definition: CopasiPlot.h:455
const double * mpY
Definition: CopasiPlot.h:67
std::vector< std::vector< const C_FLOAT64 * > > mObjectValues
Definition: CopasiPlot.h:349
virtual double y(size_t i) const
Definition: CopasiPlot.cpp:484
void setDataSize(const size_t &size)
Definition: CopasiPlot.cpp:602
size_t mLastRectangle
Definition: CopasiPlot.h:71
const CPlotItem::Type & getType() const
Definition: CPlotItem.cpp:158
const double * mpX
Definition: CopasiPlot.h:66
void reallocated(const CVector< double > *pX, const CVector< double > *pY1, const CVector< double > *pY2)
Definition: CopasiPlot.cpp:399
QMutex * mpMutex
Definition: CopasiPlot.h:206
COutputInterface::Activity mActivity
Definition: CopasiPlot.h:212
static CCopasiTimeVariable getCurrentWallTime()
Definition: CopasiTime.cpp:160
size_t mLastRectangle
Definition: CopasiPlot.h:150
CVector< C2DPlotCurve * > mCurves
Definition: CopasiPlot.h:386
virtual ~C2DCurveData()
Definition: CopasiPlot.cpp:72
virtual QwtData * copy() const
Definition: CopasiPlot.cpp:75
std::vector< std::vector< CVector< double > * > > mData
Definition: CopasiPlot.h:344
void replotSignal()
const COutputInterface::Activity & getActivity() const
Definition: CPlotItem.cpp:179
void clearBuffers()
double mIncrement
Definition: CopasiPlot.h:156
virtual double y(size_t i) const
Definition: CopasiPlot.cpp:94
std::map< C_INT32, C_INT32 > mMap
Definition: CopasiPlot.h:158
std::set< const CCopasiObject * > mObjects
std::vector< const CCopasiObject * > mSaveHistogramObjects
Definition: CopasiPlot.h:365
size_t size() const
Definition: CVector.h:100
void setSize(const size_t &size)
Definition: CopasiPlot.cpp:392
C2DCurveData & operator=(const C2DCurveData &rhs)
Definition: CopasiPlot.cpp:194
void showCurve(QwtPlotItem *item, bool on)
virtual std::string getUnits() const
const double * mpX
Definition: CopasiPlot.h:146
bool mReplotFinished
Definition: CopasiPlot.h:458
virtual void drawCurve(QPainter *painter, int style, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to) const
Definition: CopasiPlot.cpp:698
const CCopasiVector< CPlotItem > & getItems() const
#define C_FLOAT64
Definition: copasi.h:92
CType * array()
Definition: CVector.h:139
size_t mDataDuring
Definition: CopasiPlot.h:411
bool initFromSpec(const CPlotSpecification *plotspec)
Definition: CopasiPlot.cpp:836
virtual double x(size_t i) const
Definition: CopasiPlot.cpp:262
C_INT64 getMicroSeconds(const bool &bounded=false) const
Definition: CopasiTime.cpp:112
virtual ~CBandedGraphData()
Definition: CopasiPlot.cpp:245
virtual QwtData * copy() const
Definition: CopasiPlot.cpp:249
bool isValueDbl() const
bool saveData(const std::string &filename)
const double * mpY2
Definition: CopasiPlot.h:109
virtual void * getValuePointer() const
size_t mMaxSize
Definition: CopasiPlot.h:69
bool mHaveAfter
Definition: CopasiPlot.h:434
static CLocaleString fromUtf8(const std::string &utf8)
const std::string & getTitle() const
Definition: CPlotItem.cpp:228
void reallocatedData(const CVector< double > *pX, const CVector< double > *pY, const CVector< double > *pY2=0)
Definition: CopasiPlot.cpp:624
virtual size_t size() const
Definition: CopasiPlot.cpp:259
size_t mLastRectangle
Definition: CopasiPlot.h:114
CCopasiObject * ObjectFromName(const std::vector< CCopasiContainer * > &listOfContainer, const CCopasiObjectName &CN) const
const COutputInterface::Activity & getActivity() const
Definition: CopasiPlot.cpp:662
virtual void finish()
virtual void output(const Activity &activity)
double mMaxX
Definition: CopasiPlot.h:73
C_FLOAT64 mIncrement
Definition: CopasiPlot.h:210
#define min(a, b)
Definition: f2c.h:175
void myDrawLines(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to) const
Definition: CopasiPlot.cpp:668
const double * mpY1
Definition: CopasiPlot.h:108
virtual void drawSymbols(QPainter *painter, const QwtSymbol &symbol, const QwtScaleMap &xMap, const QwtScaleMap &yMap, int from, int to) const
Definition: CopasiPlot.cpp:714
CCopasiTimeVariable mNextPlotTime
Definition: CopasiPlot.h:444