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