From 82b71d8360e875ba7dc7cfb78ff0bc3820a90cef Mon Sep 17 00:00:00 2001 From: koldo Date: Fri, 10 Mar 2017 22:42:35 +0000 Subject: [PATCH] ScatterDraw: Improved PSD and added new spectral options. git-svn-id: svn://ultimatepp.org/upp/trunk@10933 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/ScatterDraw/DataSource.cpp | 327 +++++++++++++++++++++++++---- uppsrc/ScatterDraw/DataSource.h | 118 +++++++---- uppsrc/ScatterDraw/Equation.cpp | 20 +- uppsrc/ScatterDraw/Equation.h | 1 + uppsrc/ScatterDraw/ScatterDraw.cpp | 28 ++- uppsrc/ScatterDraw/ScatterDraw.h | 4 +- 6 files changed, 408 insertions(+), 90 deletions(-) diff --git a/uppsrc/ScatterDraw/DataSource.cpp b/uppsrc/ScatterDraw/DataSource.cpp index 910e801f7..82bea9008 100644 --- a/uppsrc/ScatterDraw/DataSource.cpp +++ b/uppsrc/ScatterDraw/DataSource.cpp @@ -36,6 +36,71 @@ double DataSource::Max(Getdatafun getdata, int64& id) { return maxVal; } +void DataSource::MaxList(Getdatafun getdataY, Getdatafun getdataX, Vector &id, double width) { + id.Clear(); + for (int64 i = 1; i < GetCount() - 1; ++i) { + double d = Membercall(getdataY)(i); + if (IsNull(d)) + continue; + int64 ii; + for (ii = i-1; ii >= 0; --ii) { + if (!IsNull(Membercall(getdataY)(ii))) + break; + } + if (ii < 0) + continue; + double d_1 = Membercall(getdataY)(ii); + for (ii = i+1; ii < GetCount(); ++ii) { + if (!IsNull(Membercall(getdataY)(ii))) + break; + } + if (ii >= GetCount()) + continue; + double d1 = Membercall(getdataY)(ii); + if (d >= d_1 && d > d1) { + if (id.GetCount() == 0 || + (Membercall(getdataX)(i) - Membercall(getdataX)(id.GetCount() - 1) >= width)) + id << i; + } + } +} + +Pointf DataSource::MaxSubDataImp(Getdatafun getdataY, Getdatafun getdataX, int64 maxId, int64 width) +{ + Vector p; + + int iw; + int64 idMin, idMax; + iw = 0; + for (idMin = maxId - 1; idMin >= 0 && iw < width; idMin--) { + if (IsNull(Membercall(getdataY)(idMin)) || IsNull(Membercall(getdataX)(idMin))) + continue; + iw++; + } + if (idMin < 0) + idMin = 0; + iw = 0; + for (idMax = maxId + 1; idMax < GetCount() && iw < width; idMax++) { + if (IsNull(Membercall(getdataY)(idMax)) || IsNull(Membercall(getdataX)(idMax))) + continue; + iw++; + } + if (idMax >= GetCount()) + idMax = GetCount() - 1; + for (int64 i = idMin; i <= idMax; ++i) { + if (IsNull(Membercall(getdataY)(i)) || IsNull(Membercall(getdataX)(i))) + continue; + p << Pointf(Membercall(getdataX)(i), Membercall(getdataY)(i)); + } + VectorPointf pf(p); + PolynomialEquation2 polyFit; + polyFit.Fit(pf); + const Vector &coeff = polyFit.GetCoeff(); + double b = coeff[1]; + double a = coeff[2]; + return Pointf(-b/2/a, polyFit.f(-b/2/a)); +} + double DataSource::Avg(Getdatafun getdata) { double ret = 0; int count = 0; @@ -327,43 +392,49 @@ double CArray::znFixed(int n, int64 id) { return Null; } - -Vector DataSource::FFT(Getdatafun getdata, double tSample, bool frequency, int type, bool window) { - int numData = int(GetCount()); - VectorXd timebuf(numData); - int num = 0; - for (int i = 0; i < numData; ++i) { - double data = Membercall(getdata)(i); - if (!IsNull(data)) { - timebuf[i] = Membercall(getdata)(i); - num++; - } - } - Vector res; - if (num < 3) - return res; - timebuf.resize(num); +Vector FFTSimple(VectorXd &data, double tSample, bool frequency, int type, + int window, int numOver) { + int numData = int(data.size()); - double windowSum = 0; - if (window) { - for (int i = 0; i < numData; ++i) { - double windowDat = 0.54 - 0.46*cos(2*M_PI*i/numData); - windowSum += windowDat; - timebuf[i] *= windowDat; // Hamming window - } - } else - windowSum = numData; - + double numDataFact = 0; + switch (window) { + case DataSource::HAMMING: + for (int i = 0; i < numData; ++i) { + double windowFact = 0.54 - 0.46*cos(2*M_PI*i/numData); + numDataFact += windowFact; + data[i] *= windowFact; + } + break; + case DataSource::COS: + for (int i = 0; i < numOver; ++i) { + double windowFact = 0.5*(1 - cos(M_PI*i/numOver)); + numDataFact += windowFact; + data[i] *= windowFact; + } + for (int i = numOver; i < numData - numOver; ++i) { + double windowFact = 1; // 1.004 + numDataFact += windowFact; + //data[i] *= windowFact; + } + for (int i = numData - numOver; i < numData; ++i) { + double windowFact = 0.5*(1 + cos(M_PI*(numData - i - numOver)/numOver)); + numDataFact += windowFact; + data[i] *= windowFact; + } + break; + default: numDataFact = numData; + } + Vector res; VectorXcd freqbuf; try { Eigen::FFT fft; fft.SetFlag(fft.HalfSpectrum); - fft.fwd(freqbuf, timebuf); + fft.fwd(freqbuf, data); } catch(...) { return res; } double threshold = 0; - if (type == T_PHASE) { + if (type == DataSource::T_PHASE) { for (int i = 0; i < int(freqbuf.size()); ++i) { if (threshold < std::abs(freqbuf[i])) threshold = std::abs(freqbuf[i]); @@ -375,13 +446,16 @@ Vector DataSource::FFT(Getdatafun getdata, double tSample, bool frequenc double xdata = i/(tSample*numData); switch (type) { - case T_PHASE: if (std::abs(freqbuf[i]) > threshold) - res << Pointf(xdata, std::arg(freqbuf[i])); - else - res << Pointf(xdata, 0); - break; - case T_FFT: res << Pointf(xdata, 2*std::abs(freqbuf[i])/windowSum); break; - case T_PSD: res << Pointf(xdata, 2*sqr(std::abs(freqbuf[i]))/(windowSum/tSample)); + case DataSource::T_PHASE: + if (std::abs(freqbuf[i]) > threshold) + res << Pointf(xdata, std::arg(freqbuf[i])); + else + res << Pointf(xdata, 0); + break; + case DataSource::T_FFT: + res << Pointf(xdata, 2*std::abs(freqbuf[i])/numDataFact); break; + case DataSource::T_PSD: + res << Pointf(xdata, 2*sqr(std::abs(freqbuf[i]))/(numDataFact/tSample)); } } } else { @@ -389,19 +463,188 @@ Vector DataSource::FFT(Getdatafun getdata, double tSample, bool frequenc double xdata = (tSample*numData)/i; switch (type) { - case T_PHASE: if (std::abs(freqbuf[i]) > threshold) - res << Pointf(xdata, std::arg(freqbuf[i])); - else - res << Pointf(xdata, 0); - break; - case T_FFT: res << Pointf(xdata, 2*std::abs(freqbuf[i])/windowSum); break; - case T_PSD: res << Pointf(xdata, 2*sqr(std::abs(freqbuf[i]))/(windowSum/tSample)); + case DataSource::T_PHASE: + if (std::abs(freqbuf[i]) > threshold) + res << Pointf(xdata, std::arg(freqbuf[i])); + else + res << Pointf(xdata, 0); + break; + case DataSource::T_FFT: + res << Pointf(xdata, 2*std::abs(freqbuf[i])/numDataFact); break; + case DataSource::T_PSD: + res << Pointf(xdata, 2*sqr(std::abs(freqbuf[i]))/(numDataFact/tSample)); } } } return res; } +Vector DataSource::FFT(Getdatafun getdata, double tSample, bool frequency, int type, + int window, int numSub, double overlapping) { + int numData = int(GetCount()); + + VectorXd data(numData); + int num = 0; + for (int i = 0; i < numData; ++i) { + double d = Membercall(getdata)(i); + if (!IsNull(d)) { + data[i] = d; + num++; + } + } + numData = num; + + Vector res; + if (num < 3) + return res; + data.resize(numData); + double numOver; + + if (numSub == 1) { + numOver = numData*overlapping; + return FFTSimple(data, tSample, frequency, type, window, int(numOver)); + } else { // solve v t=2*(v-f*v/2) + (n-2)*(v-f*v) ==> v=t/(f + n -f*n) + double numDataPart = numData/(overlapping + numSub - overlapping*numSub); + int inumDataPart = int(numDataPart); + numOver = numDataPart*overlapping; + VectorXd dataPart(inumDataPart); + double izero = 0; + int izerod = 0; + Vector fft; + for (int iPart = 0; iPart < numSub; ++iPart) { + if (iPart > 0) { + izero += int(numDataPart - numOver); + izerod = int(izero); + } + for (int i = 0; i < inumDataPart; ++i) + dataPart[i] = data[izerod + i]; + Vector fftPart; + fftPart = FFTSimple(dataPart, tSample, frequency, type, window, int(numOver)); + if (iPart == 0) + fft = clone(fftPart); // pick() + else { + for (int i = 0; i < fftPart.GetCount(); ++i) { + fft[i].y += fftPart[i].y; + ASSERT(fft[i].x == fftPart[i].x); + } + } + } + for (int i = 0; i < fft.GetCount(); ++i) + fft[i].y /= numSub; + return fft; + } +} + +double DataSource::Integral(double from, double to, double n) { + double h = (to - from)/n; + double h2 = h/2; + + double sum1 = 0, sum2 = 0; + for(int i = 0; i < n; i++) { + sum1 += f(from + h*i + h2); + sum2 += f(from + h*i); + } + return h/6*(f(from) + f(to) + 4*sum1 + 2*sum2); +} + +double DataSource::Integral(Getdatafun getdataY, Getdatafun getdataX) { + double prevx = Membercall(getdataX)(0); + double prevy = Membercall(getdataY)(0); + double sum = 0; + for (int i = 1; i < GetCount(); ++i) { + double x = Membercall(getdataX)(i); + double y = Membercall(getdataY)(i); + sum += (x - prevx)*(y + prevy); + prevx = x; + prevy = y; + } + return sum/2; +} + +void DataSource::GetSpectralMoments(double from, double to, double n, bool frequency, + double &m_1, double &m0, double &m1, double &m2) { + if (!frequency) { + from = 1/to; + to = 1/from; + } + double h = (to - from)/n; + double h2 = h/2; + + double sum1_m_1 = 0, sum2_m_1 = 0; + double sum1_m0 = 0, sum2_m0 = 0; + double sum1_m1 = 0, sum2_m1 = 0; + double sum1_m2 = 0, sum2_m2 = 0; + double f1, f2, x1, x2; + for(int i = 0; i < n; i++) { + if (frequency) { + x1 = from + h*i + h2; + x2 = from + h*i; + f1 = f(x1); + f2 = f(x2); + } else { + x1 = 1/(from + h*i + h2); + x2 = 1/(from + h*i); + f1 = f(1/x1); + f2 = f(1/x2); + } + sum1_m_1 += f1/x1; + sum2_m_1 += f2/x2; + sum1_m0 += f1; + sum2_m0 += f2; + sum1_m1 += f1*x1; + sum2_m1 += f2*x2; + sum1_m2 += f1*x1*x1; + sum2_m2 += f2*x2*x2; + } + double f_from, f_to; + if (frequency) { + f_from = f(from); + f_to = f(to); + } else { + f_from = f(1/from); + f_to = f(1/to); + } + m_1 = h/6*(f_from/from + f_to/to + 4*sum1_m_1 + 2*sum2_m_1); + m0 = h/6*(f_from + f(to) + 4*sum1_m0 + 2*sum2_m0); + m1 = h/6*(f_from*from + f_to*to + 4*sum1_m1 + 2*sum2_m1); + m2 = h/6*(f_from*from*from + f_to*to*to + 4*sum1_m2 + 2*sum2_m2); +} + +void DataSource::GetSpectralMoments(Getdatafun getdataY, Getdatafun getdataX, bool frequency, + double &m_1, double &m0, double &m1, double &m2) { + double prevx = Membercall(getdataX)(0); + double Si_1 = Membercall(getdataY)(0); + m_1 = m0 = m1 = m2 = 0; + for (int i = 1; i < GetCount(); ++i) { + double x = Membercall(getdataX)(i); + double Si = Membercall(getdataY)(i); + + double deltaX; + double fi, fi_1; + if (frequency) { + fi = x; + fi_1 = prevx; + deltaX = fi - fi_1; + } else { + fi = 1/x; + fi_1 = 1/prevx; + deltaX = fi_1 - fi; + } + if (fi != 0 && fi_1 != 0) { + m_1 += (Si/fi + Si_1/fi_1)*deltaX; + m0 += (Si + Si_1)*deltaX; + m1 += (Si*fi + Si_1*fi_1)*deltaX; + m2 += (Si*fi*fi + Si_1*fi_1*fi_1)*deltaX; + } + prevx = x; + Si_1 = Si; + } + m_1 /= 2; + m0 /= 2; + m1 /= 2; + m2 /= 2; +} + bool DataSource::SameX(DataSource &data) { int64 num = GetCount(); if (data.GetCount() != num) diff --git a/uppsrc/ScatterDraw/DataSource.h b/uppsrc/ScatterDraw/DataSource.h index 20cea01ec..e679b4012 100644 --- a/uppsrc/ScatterDraw/DataSource.h +++ b/uppsrc/ScatterDraw/DataSource.h @@ -50,14 +50,32 @@ public: virtual Vector LowerEnvelopeY(double width) {return LowerEnvelope(&DataSource::y, &DataSource::x, width);} virtual Vector MovingAverageY(double width) {return MovingAverage(&DataSource::y, &DataSource::x, width);} virtual Vector SectorAverageY(double width) {return SectorAverage(&DataSource::y, &DataSource::x, width);} + virtual void MaxListY(Vector &id, double width){MaxList(&DataSource::y, &DataSource::x, id, width);} + virtual Pointf MaxSubDataImpY(int64 maxId, int width) {return MaxSubDataImp(&DataSource::y, &DataSource::x, maxId, width);} virtual void ZeroCrossingY(bool ascending, bool descending, Vector &zeros, Vector &ids) { - return ZeroCrossing(&DataSource::y, &DataSource::x, ascending, descending, zeros, ids);} + return ZeroCrossing(&DataSource::y, &DataSource::x, ascending, descending, zeros, ids);} + virtual double IntegralY() {return Integral(&DataSource::y, &DataSource::x);} + virtual double IntegralY(double from, double to, double n) {return Integral(from, to, n);} - enum FFT_TYPE {T_FFT = 0, T_PHASE, T_PSD}; - - Upp::Vector FFTY(double tSample, bool frequency = false, int type = FFT_TYPE::T_FFT, bool window = false) { - return FFT(&DataSource::y, tSample, frequency, type, window);} + enum FFT_WINDOW {NO_WINDOW = 0, HAMMING, COS}; + enum FFT_TYPE {T_FFT = 0, T_PHASE, T_PSD}; + Upp::Vector FFTY(double tSample, bool frequency = false, int type = FFT_TYPE::T_FFT, + int window = FFT_WINDOW::HAMMING, int numSub = 1, double overlapping = 0) { + return FFT(&DataSource::y, tSample, frequency, type, window, numSub, overlapping);} + static int GetFFTWindowCount() {return 3;} + static const char *GetFFTWindowStr(int i) { + const char *str[] = {"no window", "hamming", "cos"}; + if (i < 0 || i >= GetFFTWindowCount()) + return 0; + return str[i]; + } + void GetSpectralMomentsY(double from, double to, double n, bool frequency, + double &m_1, double &m0, double &m1, double &m2) + {GetSpectralMoments(from, to, n, frequency, m_1, m0, m1, m2);} + void GetSpectralMomentsY(bool frequency, double &m_1, double &m0, double &m1, double &m2) + {GetSpectralMoments(&DataSource::y, &DataSource::x, frequency, m_1, m0, m1, m2);} + double Min(Getdatafun getdata, int64& id); double Max(Getdatafun getdata, int64& id); double Avg(Getdatafun getdata); @@ -69,18 +87,27 @@ public: Vector LowerEnvelope(Getdatafun getdataY, Getdatafun getdataX, double width); Vector MovingAverage(Getdatafun getdataY, Getdatafun getdataX, double width); Vector SectorAverage(Getdatafun getdataY, Getdatafun getdataX, double width); + void MaxList(Getdatafun getdataY, Getdatafun getdataX, Vector &id, double width); + Pointf MaxSubDataImp(Getdatafun getdataY, Getdatafun getdataX, int64 maxId, int64 width); void ZeroCrossing(Getdatafun getdataY, Getdatafun getdataX, bool ascending, bool descending, Vector &zeros, Vector &ids); + double Integral(Getdatafun getdataY, Getdatafun getdataX); + double Integral(double from, double to, double n); + double SinEstim_Amplitude(double avg = Null); bool SinEstim_FreqPhase(double &frequency, double &phase, double avg = Null); Vector FFT(Getdatafun getdata, double tSample, bool frequency = false, - int type = FFT_TYPE::T_FFT, bool window = false); - + int type = FFT_TYPE::T_FFT, int window = FFT_WINDOW::HAMMING, + int numSub = 1, double overlapping = 0); + void GetSpectralMoments(double from, double to, double n, bool frequency, + double &m_1, double &m0, double &m1, double &m2); + void GetSpectralMoments(Getdatafun getdataY, Getdatafun getdataX, bool frequency, + double &m_1, double &m0, double &m1, double &m2); bool SameX(DataSource &data); protected: bool isParam, isExplicit; - + private: int key; @@ -172,7 +199,13 @@ private: double x0, deltaX; public: - VectorY(Vector &yData, double x0, double deltaX) : yData(&yData), x0(x0), deltaX(deltaX) {} + VectorY() : yData(0), x0(0), deltaX(0) {} + VectorY(Vector &yData, double x0, double deltaX) {Init(yData, x0, deltaX);} + void Init(Vector &yData, double x0, double deltaX) { + this->yData = &yData; + this->x0 = x0; + this->deltaX = deltaX; + } virtual inline double y(int64 id) {return (*yData)[int(id)];} virtual inline double x(int64 id) {return id*deltaX + x0;} virtual inline int64 GetCount() {return yData->GetCount();} @@ -188,7 +221,13 @@ private: double x0, deltaX; public: - ArrayY(Upp::Array &yData, double x0, double deltaX) : yData(&yData), x0(x0), deltaX(deltaX) {} + ArrayY() : yData(0), x0(0), deltaX(0) {} + ArrayY(Upp::Array &yData, double x0, double deltaX) {Init(yData, x0, deltaX);} + void Init(Upp::Array &yData, double x0, double deltaX) { + this->yData = &yData; + this->x0 = x0; + this->deltaX = deltaX; + } virtual inline double y(int64 id) {return (*yData)[ptrdiff_t(id)];} virtual inline double x(int64 id) {return id*deltaX + x0;} virtual inline int64 GetCount() {return yData->GetCount();} @@ -210,35 +249,35 @@ private: public: VectorVectorY() : data(0), useRows(true), beginData(0), numData(Null), idx(0), idy(1) {} VectorVectorY(Vector > &data, int idx, int idy, - Vector &idsx, Vector &idsy, Vector &idsFixed, bool useRows = true, int beginData = 0, int numData = Null) : - data(&data), useRows(useRows), beginData(beginData), numData(numData) { + Vector &idsx, Vector &idsy, Vector &idsFixed, + bool useRows = true, int beginData = 0, int numData = Null) { Init(data, idx, idy, idsx, idsy, idsFixed, useRows, beginData, numData); } - void Init(Vector > &_data, int _idx, int _idy, Vector &_idsx, Vector &_idsy, Vector &_idsFixed, - bool _useRows = true, int _beginData = 0, int _numData = Null) { - data = &_data; - useRows = _useRows; + void Init(Vector > &data, int idx, int idy, Vector &idsx, Vector &idsy, Vector &idsFixed, + bool useRows = true, int beginData = 0, int numData = Null) { + this->data = &data; + this->useRows = useRows; - idx = _idx; - idy = _idy; - idsx = clone(_idsx); - idsy = clone(_idsy); - idsFixed = clone(_idsFixed); - beginData = _beginData; - numData = _numData; - if (IsNull(_numData)) { + this->idx = idx; + this->idy = idy; + this->idsx = clone(idsx); + this->idsy = clone(idsy); + this->idsFixed = clone(idsFixed); + this->beginData = beginData; + this->numData = numData; + if (IsNull(numData)) { if (!useRows) { - if (data->IsEmpty()) - numData = 0; + if (data.IsEmpty()) + this->numData = 0; else - numData = (*data)[0].GetCount() - beginData; + this->numData = data[0].GetCount() - beginData; } else - numData = data->GetCount() - beginData; + this->numData = data.GetCount() - beginData; } } - void Init(Vector > &_data, int idx, int idy, bool _useRows = true, int _beginData = 0, int _numData = Null) { + void Init(Vector > &data, int idx, int idy, bool useRows = true, int beginData = 0, int numData = Null) { static Vector idsVoid; - Init(_data, idx, idy, idsVoid, idsVoid, idsVoid, _useRows, _beginData, _numData); + Init(data, idx, idy, idsVoid, idsVoid, idsVoid, useRows, beginData, numData); } virtual inline double y(int64 id) { if (!IsNull(idy) && idy >= 0) { @@ -342,22 +381,23 @@ public: virtual inline double x(int64 id) {return (*data).GetKey(int(id));} virtual inline int64 GetCount() {return data->GetCount();} }; - + class FuncSource : public DataSource { -private: - double (*function)(double); +protected: + Function function; public: - FuncSource(double (*function)(double)) : function(function) {isExplicit = true;} + FuncSource() {isExplicit = true;} + FuncSource(Function function) : function(function) {isExplicit = true;} virtual inline double f(double x) {return function(x);} }; class FuncSourceV : public DataSource { private: - void (*function)(double&, double); + Event function; public: - FuncSourceV(void (*function)(double&, double)) : function(function) {isExplicit = true;} + FuncSourceV(Event function) : function(function) {isExplicit = true;} virtual inline double f(double x) {double y; function(y, x); return y;} }; @@ -392,8 +432,9 @@ public: virtual inline int64 GetCount() {return numPoints;} }; -typedef Callback2 PlotExplicFunc; -typedef Callback2 PlotParamFunc; +typedef Event PlotExplicFunc; +typedef Event PlotParamFunc; + class PlotExplicFuncSource : public DataSource { private: @@ -439,7 +480,6 @@ struct PointfLess { bool operator () (const Pointf& a, const Pointf& b) const { return a.x < b.x; } }; - } #endif diff --git a/uppsrc/ScatterDraw/Equation.cpp b/uppsrc/ScatterDraw/Equation.cpp index 6e3836fd0..b63fd8991 100644 --- a/uppsrc/ScatterDraw/Equation.cpp +++ b/uppsrc/ScatterDraw/Equation.cpp @@ -29,7 +29,6 @@ void ExplicitEquation::SetNumCoeff(int num) { } ExplicitEquation::FitError ExplicitEquation::Fit(DataSource &series, double &r2) { - r2 = 0; if (series.IsExplicit() || series.IsParam()) return InadequateDataSource; @@ -61,20 +60,27 @@ ExplicitEquation::FitError ExplicitEquation::Fit(DataSource &series, double &r2) if (ret == LevenbergMarquardtSpace::TooManyFunctionEvaluation) return TooManyFunctionEvaluation; - double mean = series.AvgY(); + r2 = R2Y(series); + + return NoError; +} + +double ExplicitEquation::R2Y(DataSource &series, double mean) { + if (IsNull(mean)) + mean = series.AvgY(); double sse = 0, sst = 0; for (int64 i = 0; i < series.GetCount(); ++i) { double y = series.y(i); if (!IsNull(y)) { - double res = y - f(series.x(i)); - sse += res*res; + double err = y - f(series.x(i)); + sse += err*err; double d = y - mean; sst += d*d; } } - r2 = 1 - sse/sst; - - return NoError; + if (sst == 0) + return Null; + return 1 - sse/sst; } int ExplicitEquation::maxFitFunctionEvaluations = 1000; diff --git a/uppsrc/ScatterDraw/Equation.h b/uppsrc/ScatterDraw/Equation.h index d761b0d39..efeeaf56d 100644 --- a/uppsrc/ScatterDraw/Equation.h +++ b/uppsrc/ScatterDraw/Equation.h @@ -61,6 +61,7 @@ public: } return *this; } + double R2Y(DataSource &series, double mean = Null); protected: Vector coeff; diff --git a/uppsrc/ScatterDraw/ScatterDraw.cpp b/uppsrc/ScatterDraw/ScatterDraw.cpp index 54bdc1f20..818afd9fa 100644 --- a/uppsrc/ScatterDraw/ScatterDraw.cpp +++ b/uppsrc/ScatterDraw/ScatterDraw.cpp @@ -779,6 +779,19 @@ double ScatterDraw::GetValueX(int index, int64 idata) { } } +Value ScatterDraw::GetStringX(int index, int64 idata) { + double ret = GetValueX(index, idata); + if (IsNull(ret)) + return Null; + if (cbModifFormatX) { + String sret; + cbModifFormatX(sret, int(idata), ret); + return sret; + } else + return ret; +} + + double ScatterDraw::GetValueY(int index, int64 idata) { ASSERT(IsValid(index) && !IsNull(GetCount(index))); ASSERT(idata >= 0 && idata < series[index].PointsData()->GetCount()); @@ -789,8 +802,21 @@ double ScatterDraw::GetValueY(int index, int64 idata) { return Null; } } + +Value ScatterDraw::GetStringY(int index, int64 idata) { + double ret = GetValueY(index, idata); + if (IsNull(ret)) + return Null; + String sret; + if (cbModifFormatY) { + String sret; + cbModifFormatY(sret, int(idata), ret); + return sret; + } else + return ret; +} - ScatterDraw &ScatterDraw::SetNoPlot(int index) { +ScatterDraw &ScatterDraw::SetNoPlot(int index) { ASSERT(IsValid(index)); series[index].seriesPlot = NULL; diff --git a/uppsrc/ScatterDraw/ScatterDraw.h b/uppsrc/ScatterDraw/ScatterDraw.h index 74e0a9e9a..aa24ad70e 100644 --- a/uppsrc/ScatterDraw/ScatterDraw.h +++ b/uppsrc/ScatterDraw/ScatterDraw.h @@ -217,7 +217,7 @@ public: ScatterDraw &SetZoomStyleX(ZoomStyle style = TO_CENTER) {zoomStyleX = style; return *this;} ScatterDraw &SetZoomStyleY(ZoomStyle style = TO_CENTER) {zoomStyleY = style; return *this;} - ScatterDraw& SetRange(double rx, double ry, double ry2 = 100); + ScatterDraw& SetRange(double rx, double ry = Null, double ry2 = Null); //double GetRangeX() {return xRange;} //double GetRangeY() {return yRange;} //double GetRangeY2() {return yRange2;} @@ -363,7 +363,9 @@ public: int64 GetCount(int index); void GetValues(int index, int64 idata, double &x, double &y); double GetValueX(int index, int64 idata); + Value GetStringX(int index, int64 idata); double GetValueY(int index, int64 idata); + Value GetStringY(int index, int64 idata); ScatterDraw &SetNoPlot(int index);