File indexing completed on 2024-12-22 04:17:57

0001 /***************************************************************************
0002                           histogram.cpp: Histogram for KST
0003                              -------------------
0004     begin                : July 2002
0005     copyright            : (C) 2002 by C. Barth Netterfield
0006     email                : netterfield@astro.utoronto.ca
0007  ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *                                                                         *
0011  *   This program is free software; you can redistribute it and/or modify  *
0012  *   it under the terms of the GNU General Public License as published by  *
0013  *   the Free Software Foundation; either version 2 of the License, or     *
0014  *   (at your option) any later version.                                   *
0015  *                                                                         *
0016  ***************************************************************************/
0017 
0018 
0019 #include "histogram.h"
0020 
0021 #include <assert.h>
0022 #include <math.h>
0023 #include <stdlib.h>
0024 
0025 #include <QTextDocument>
0026 #include <QXmlStreamWriter>
0027 
0028 
0029 #include "dialoglauncher.h"
0030 #include "datacollection.h"
0031 #include "objectstore.h"
0032 #include "dataobjectscriptinterface.h"
0033 
0034 namespace Kst {
0035 
0036 const QString Histogram::staticTypeString = "Histogram";
0037 const QString Histogram::staticTypeTag = "histogram";
0038 
0039 static const QLatin1String& RAWVECTOR  = QLatin1String("I");
0040 static const QLatin1String& BINS = QLatin1String("B");
0041 static const QLatin1String& HIST = QLatin1String("H");
0042 
0043 Histogram::Histogram(ObjectStore *store)
0044   : DataObject(store) {
0045   setRealTimeAutoBin(false);
0046   _typeString = staticTypeString;
0047   _type = "Histogram";
0048   _initializeShortName();
0049 
0050   // _Bins, _bVector and _hVector need to be valid, 
0051   // so initialize them as size 2 (where 2 is a small valid number)
0052   _Bins = new unsigned long[2];
0053   _NumberOfBins = 0;
0054 
0055   VectorPtr v = store->createObject<Vector>();
0056   v->setProvider(this);
0057   v->setSlaveName("bin");
0058   v->resize(2);
0059   _bVector = _outputVectors.insert(BINS, v).value();
0060 
0061   v = store->createObject<Vector>();
0062   v->setProvider(this);
0063   v->setSlaveName("num");
0064   v->resize(2);
0065   _hVector = _outputVectors.insert(HIST, v).value();
0066 }
0067 
0068 void Histogram::_initializeShortName() {
0069   _shortName = 'H'+QString::number(_histogramnum);
0070   if (_histogramnum>max_histogramnum)
0071     max_histogramnum = _histogramnum;
0072   _histogramnum++;
0073 }
0074 
0075 
0076 void Histogram::change(VectorPtr in_V,
0077                           double xmin_in,
0078                           double xmax_in,
0079                           int in_n_bins,
0080                           NormalizationType in_norm_mode,
0081                           bool realTimeAutoBin) {
0082 
0083   _NormalizationMode = in_norm_mode;
0084   _realTimeAutoBin = realTimeAutoBin;
0085   _NumberOfBins = 0;
0086 
0087   _inputVectors[RAWVECTOR] = in_V;
0088 
0089   if (xmax_in>xmin_in) {
0090     _MaxX = xmax_in;
0091     _MinX = xmin_in;
0092   } else {
0093     _MinX = xmax_in;
0094     _MaxX = xmin_in;
0095   }
0096   if (_MaxX == _MinX) {
0097     _MaxX += 1.0;
0098     _MinX -= 1.0;
0099   }
0100 
0101   _NumberOfBins = in_n_bins;
0102   if (_NumberOfBins < 2) {
0103     _NumberOfBins = 2;
0104   }
0105 
0106   delete[] _Bins;
0107   _Bins = new unsigned long[_NumberOfBins];
0108   _NS = 3 * _NumberOfBins + 1;
0109 
0110   _bVector->resize(_NumberOfBins);
0111   _hVector->resize(_NumberOfBins);
0112 }
0113 
0114 
0115 Histogram::~Histogram() {
0116   _bVector = 0L;
0117   _hVector = 0L;
0118 
0119   delete[] _Bins;
0120   _Bins = 0L;
0121 }
0122 
0123 
0124 ScriptInterface* Histogram::createScriptInterface() {
0125   return new HistogramSI(this);
0126 }
0127 
0128 void Histogram::internalUpdate() {
0129 
0130   writeLockInputsAndOutputs();
0131 
0132   int i_bin, i_pt, ns;
0133   double y = 0.0;
0134   double MaxY = 0.0;
0135   // do auto-binning if necessary
0136   if (_realTimeAutoBin) {
0137     int temp_NumberOfBins;
0138     double temp_xMin, temp_xMax;
0139     Histogram::AutoBin(_inputVectors[RAWVECTOR], &temp_NumberOfBins, &temp_xMax, &temp_xMin);
0140     internalSetNumberOfBins(temp_NumberOfBins);
0141     internalSetXRange(temp_xMin, temp_xMax);
0142   }
0143 
0144   _NS = 3 * _NumberOfBins + 1;
0145   _W = (_MaxX - _MinX)/double(_NumberOfBins);
0146 
0147   memset(_Bins, 0, _NumberOfBins*sizeof(*_Bins));
0148 
0149   ns = _inputVectors[RAWVECTOR]->length();
0150   for (i_pt = 0; i_pt < ns ; ++i_pt) {
0151     y = _inputVectors[RAWVECTOR]->interpolate(i_pt, ns);
0152     i_bin = (int)floor((y-_MinX)/_W);
0153     if (i_bin >= 0 && i_bin < _NumberOfBins) {
0154       _Bins[i_bin]++;
0155     } else {
0156       // the top boundary of the top bin is included in the top bin.
0157       // for all other bins, the top boundary is included in the next bin
0158       if (y == _MaxX) {
0159         _Bins[_NumberOfBins-1]++;
0160       }
0161     }
0162   }
0163 
0164   for (i_bin=0; i_bin<_NumberOfBins; ++i_bin) {
0165     y = _Bins[i_bin];
0166     if (y > MaxY) {
0167       MaxY = y;
0168     }
0169   }
0170 
0171   LabelInfo label_info;
0172 
0173   switch (_NormalizationMode) {
0174     case Number:
0175       _Normalization = 1.0;
0176       label_info.quantity = tr("Number");
0177       break;
0178     case Percent:
0179       if (ns > 0) {
0180         _Normalization = 100.0/(double)ns;
0181       } else {
0182         _Normalization = 1.0;
0183       }
0184       label_info.quantity = tr("Percent");
0185       break;
0186     case Fraction:
0187       if (ns > 0) {
0188         _Normalization = 1.0/(double)ns;
0189       } else {
0190         _Normalization = 1.0;
0191       }
0192       label_info.quantity = tr("Fraction");
0193       break;
0194     case MaximumOne:
0195       if (MaxY > 0) {
0196         _Normalization = 1.0/MaxY;
0197       } else {
0198         _Normalization = 1.0;
0199       }
0200       label_info.quantity = tr("Normalized Frequency");
0201       break;
0202     default:
0203       _Normalization = 1.0;
0204       label_info.quantity = tr("Number");
0205       break;
0206   }
0207 
0208   label_info.units.clear();
0209   _bVector->setLabelInfo(_inputVectors[RAWVECTOR]->labelInfo());
0210   label_info.name = tr( "Histogram of %1").arg(_bVector->labelInfo().name);
0211   label_info.file = _bVector->labelInfo().file;
0212 
0213   _hVector->setTitleInfo(label_info);
0214   _hVector->setLabelInfo(label_info);
0215 
0216 
0217   double *bins = _bVector->raw_V_ptr();
0218   double *hist = _hVector->raw_V_ptr();
0219 
0220   for ( i_bin = 0; i_bin<_NumberOfBins; ++i_bin ) {
0221     bins[i_bin] = ( double( i_bin ) + 0.5 )*_W + _MinX;
0222     hist[i_bin] = _Bins[i_bin]*_Normalization;
0223   }
0224 
0225   unlockInputsAndOutputs();
0226 
0227 }
0228 
0229 
0230 int Histogram::numberOfBins() const {
0231   return _NumberOfBins;
0232 }
0233 
0234 
0235 void Histogram::setXRange(double xmin_in, double xmax_in) {
0236   internalSetXRange(xmin_in, xmax_in);
0237 }
0238 
0239 
0240 void Histogram::internalSetXRange(double xmin_in, double xmax_in) {
0241   if (xmax_in > xmin_in) {
0242     _MaxX = xmax_in;
0243     _MinX = xmin_in;
0244   } else if (xmax_in < xmin_in) {
0245     _MinX = xmax_in;
0246     _MaxX = xmin_in;
0247   } else {
0248     _MinX = xmax_in - 1.0;
0249     _MaxX = xmax_in + 1.0;
0250   }
0251   _W = (_MaxX - _MinX)/double(_NumberOfBins);
0252 }
0253 
0254 
0255 void Histogram::internalSetNumberOfBins(int in_n_bins) {
0256   if (in_n_bins < 2) {
0257     in_n_bins = 2;
0258   }
0259   if (_NumberOfBins != in_n_bins) {
0260     _NumberOfBins = in_n_bins;
0261 
0262     delete[] _Bins;
0263     _Bins = new unsigned long[_NumberOfBins];
0264     memset(_Bins, 0, _NumberOfBins*sizeof(*_Bins));
0265 
0266     _bVector->resize(_NumberOfBins);
0267     _hVector->resize(_NumberOfBins);
0268   }
0269   _W = (_MaxX - _MinX)/double(_NumberOfBins);
0270   _NS = 3 * _NumberOfBins + 1;
0271 }
0272 
0273 
0274 void Histogram::setNumberOfBins(int in_n_bins) {
0275   _realTimeAutoBin = false;
0276   internalSetNumberOfBins(in_n_bins);
0277 }
0278 
0279 void Histogram::setVector(VectorPtr new_v) {
0280   if (new_v) {
0281     _inputVectors[RAWVECTOR] = new_v;
0282   }
0283 }
0284 
0285 
0286 VectorPtr Histogram::vector() const {
0287   return _inputVectors[RAWVECTOR];
0288 }
0289 
0290 
0291 void Histogram::save(QXmlStreamWriter &xml) {
0292   xml.writeStartElement(staticTypeTag);
0293   xml.writeAttribute("vector", _inputVectors[RAWVECTOR]->Name());
0294   xml.writeAttribute("numberofbins", QString::number(_NumberOfBins));
0295   xml.writeAttribute("realtimeautobin", QVariant(_realTimeAutoBin).toString());
0296   xml.writeAttribute("min", QString::number(_MinX));
0297   xml.writeAttribute("max", QString::number(_MaxX));
0298   xml.writeAttribute("normalizationmode", QString::number(_NormalizationMode));
0299   saveNameInfo(xml, VECTORNUM|HISTOGRAMNUM|SCALARNUM);
0300 
0301   xml.writeEndElement();
0302 }
0303 
0304 
0305 QString Histogram::propertyString() const {
0306   return tr("Histogram: %1").arg(_inputVectors[RAWVECTOR]->Name());
0307 }
0308 
0309 
0310 void Histogram::showNewDialog() {
0311   DialogLauncher::self()->showHistogramDialog();
0312 }
0313 
0314 
0315 void Histogram::showEditDialog() {
0316   DialogLauncher::self()->showHistogramDialog(this);
0317 }
0318 
0319 
0320 void Histogram::AutoBin(VectorPtr V, int *n, double *max, double *min) {
0321   double m;
0322 
0323   *max = V->max();
0324   *min = V->min();
0325   *n = V->length();
0326 
0327   if (*max < *min) {
0328     m = *max;
0329     *max = *min;
0330     *min = m;
0331   }
0332 
0333   if (*max == *min) {
0334     *max += 1.0;
0335     *min -= 1.0;
0336   }
0337 
0338   // we can do a better job auto-ranging using the tick rules from plot...
0339   // this has not been done yet, you will notice...
0340   *n /= 50;
0341   if (*n < 6) {
0342     *n = 6;
0343   }
0344   if (*n > 60) {
0345     *n = 60;
0346   }
0347 
0348   m = (*max - *min)/(100.0*double(*n));
0349   *max += m;
0350   *min -= m;
0351 }
0352 
0353 
0354 bool Histogram::slaveVectorsUsed() const {
0355   return true;
0356 }
0357 
0358 
0359 void Histogram::setRealTimeAutoBin(bool autoBin) {
0360   _realTimeAutoBin = autoBin;
0361 }
0362 
0363 
0364 bool Histogram::realTimeAutoBin() const {
0365   return _realTimeAutoBin;
0366 }
0367 
0368 
0369 double Histogram::vMax() const {
0370   return _inputVectors[RAWVECTOR]->max();
0371 }
0372 
0373 
0374 double Histogram::vMin() const {
0375   return _inputVectors[RAWVECTOR]->min();
0376 }
0377 
0378 
0379 int Histogram::vNumSamples() const {
0380   return _inputVectors[RAWVECTOR]->length();
0381 }
0382 
0383 
0384 DataObjectPtr Histogram::makeDuplicate() const {
0385 
0386   HistogramPtr histogram = store()->createObject<Histogram>();
0387 
0388   histogram->setVector(_inputVectors[RAWVECTOR]);
0389   histogram->setXRange(_MinX, _MaxX);
0390   histogram->setNumberOfBins(_NumberOfBins);
0391   histogram->setNormalizationType(_NormalizationMode);
0392   histogram->setRealTimeAutoBin(_realTimeAutoBin);
0393 
0394   if (descriptiveNameIsManual()) {
0395     histogram->setDescriptiveName(descriptiveName());
0396   }
0397 
0398   histogram->writeLock();
0399   histogram->registerChange();
0400   histogram->unlock();
0401 
0402   return DataObjectPtr(histogram);
0403 }
0404 
0405 QString Histogram::_automaticDescriptiveName() const {
0406   return (_inputVectors[RAWVECTOR]->descriptiveName());
0407 }
0408 
0409 QString Histogram::descriptionTip() const {
0410   QString tip;
0411 
0412   tip = tr("Histogram: %1").arg(Name());
0413   if (realTimeAutoBin()) {
0414     tip+= tr("\n  Auto-bin");
0415   } else {
0416     tip += tr("\n  %1 bins from %2 to %3").arg(numberOfBins()).arg(xMin()).arg(xMax());
0417   }
0418   tip += tr("\nInput: %1").arg(_inputVectors[RAWVECTOR]->descriptionTip());
0419 
0420   return tip;
0421 }
0422 
0423 }
0424 // vim: ts=2 sw=2 et