mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
ScatterDraw: New properties
git-svn-id: svn://ultimatepp.org/upp/trunk@9665 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
1cba02d0d0
commit
34d5d720b6
8 changed files with 155 additions and 133 deletions
|
|
@ -51,6 +51,19 @@ double DataSource::Avg(Getdatafun getdata) {
|
|||
return ret/count;
|
||||
}
|
||||
|
||||
double DataSource::IsSorted(Getdatafun getdata) {
|
||||
int64 num = GetCount();
|
||||
if (num == 0)
|
||||
return false;
|
||||
if (num == 1)
|
||||
return 1;
|
||||
for (int i = 1; i < num; ++i) {
|
||||
if (Membercall(getdata)(i) < Membercall(getdata)(i - 1))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
double DataSource::Variance(Getdatafun getdata, double avg) {
|
||||
if (IsNull(avg))
|
||||
avg = Avg(getdata);
|
||||
|
|
@ -111,17 +124,23 @@ Vector<int64> DataSource::Envelope(Getdatafun getdataY, Getdatafun getdataX, dou
|
|||
}
|
||||
if (IsNull(numComparisons))
|
||||
continue;
|
||||
if (numComparisons > 2)
|
||||
ret << i;
|
||||
if (numComparisons > 2) {
|
||||
if (!ret.IsEmpty()) {
|
||||
int64 prev_i = ret[ret.GetCount() - 1];
|
||||
if (Membercall(getdataX)(prev_i) != x)
|
||||
ret << i;
|
||||
} else
|
||||
ret << i;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool GreaterThan(double a, double b) {return a > b;}
|
||||
bool LowerThan(double a, double b) {return a < b;}
|
||||
bool GreaterEqualThan(double a, double b) {return a >= b;}
|
||||
bool LowerEqualThan(double a, double b) {return a <= b;}
|
||||
|
||||
Vector<int64> DataSource::UpperEnvelope(Getdatafun getdataY, Getdatafun getdataX, double width) {return Envelope(getdataY, getdataX, width, GreaterThan);}
|
||||
Vector<int64> DataSource::LowerEnvelope(Getdatafun getdataY, Getdatafun getdataX, double width) {return Envelope(getdataY, getdataX, width, LowerThan);}
|
||||
Vector<int64> DataSource::UpperEnvelope(Getdatafun getdataY, Getdatafun getdataX, double width) {return Envelope(getdataY, getdataX, width, GreaterEqualThan);}
|
||||
Vector<int64> DataSource::LowerEnvelope(Getdatafun getdataY, Getdatafun getdataX, double width) {return Envelope(getdataY, getdataX, width, LowerEqualThan);}
|
||||
|
||||
Vector<Pointf> DataSource::MovingAverage(Getdatafun getdataY, Getdatafun getdataX, double width) {
|
||||
Vector<Pointf> ret;
|
||||
|
|
@ -204,6 +223,8 @@ bool DataSource::SinEstim_FreqPhase(double &frequency, double &phase, double avg
|
|||
lastZero = zero;
|
||||
}
|
||||
}
|
||||
if (T == 0 || numT == 0)
|
||||
return false;
|
||||
T = 2*T/numT;
|
||||
frequency = 2*M_PI/T;
|
||||
phase = -frequency*firstZero;
|
||||
|
|
@ -253,100 +274,4 @@ Vector<Pointf> DataSource::FFT(Getdatafun getdata, double tSample) {
|
|||
}
|
||||
|
||||
|
||||
bool Spline::Load(Vector<double>& xdata, Vector<double>& ydata)
|
||||
{
|
||||
if(!IsInputSane(xdata, ydata))
|
||||
return false;
|
||||
|
||||
int n = xdata.GetCount() - 1;
|
||||
|
||||
Vector<double> h;
|
||||
for(int i = 0; i < n; ++i)
|
||||
h << (xdata[i+1] - xdata[i]);
|
||||
|
||||
Vector<double> alpha;
|
||||
for(int i = 0; i < n; ++i)
|
||||
alpha << (3.*(ydata[i+1] - ydata[i])/h[i] - 3*(ydata[i]-ydata[i-1])/h[i-1]);
|
||||
|
||||
Vector<double> l, mu, z;
|
||||
l.SetCount(n+1);
|
||||
mu.SetCount(n+1);
|
||||
z.SetCount(n+1);
|
||||
l[0] = 1;
|
||||
mu[0] = 0;
|
||||
z[0] = 0;
|
||||
|
||||
for(int i = 1; i < n; ++i) {
|
||||
l[i] = 2.*(xdata[i+1] - xdata[i-1]) - h[i-1]*mu[i-1];
|
||||
mu[i] = h[i]/l[i];
|
||||
z[i] = (alpha[i] - h[i-1]*z[i-1])/l[i];
|
||||
}
|
||||
|
||||
l[n] = 1.;
|
||||
z[n] = 0;
|
||||
|
||||
Vector<double> c;
|
||||
c.SetCount(n+1);
|
||||
c[n] = 0;
|
||||
|
||||
Vector<double> b, d;
|
||||
b.SetCount(n);
|
||||
d.SetCount(n);
|
||||
for(int j = n-1; j >= 0; --j) {
|
||||
c[j] = z[j] - mu[j] * c[j+1];
|
||||
b[j] = (ydata[j+1] - ydata[j])/h[j] - h[j]*(c[j+1] + 2*c[j])/3.;
|
||||
d[j] = (c[j+1] - c[j])/3./h[j];
|
||||
}
|
||||
|
||||
coeff.SetCount(n);
|
||||
for(int i = 0; i < n; ++i) {
|
||||
coeff[i].a = ydata[i];
|
||||
coeff[i].b = b[i];
|
||||
coeff[i].c = c[i];
|
||||
coeff[i].d = d[i];
|
||||
coeff[i].x = xdata[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
double Spline::GetY(double x)
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j < coeff.size(); j++) {
|
||||
if(coeff[j].x > x) {
|
||||
if(j == 0)
|
||||
j++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
j--;
|
||||
|
||||
double dx = x - coeff[j].x;
|
||||
return coeff[j].a + coeff[j].b*dx + coeff[j].c*dx*dx + coeff[j].d*dx*dx*dx;
|
||||
}
|
||||
|
||||
bool Spline::IsInputSane(Vector<double>& xdata, Vector<double>& ydata)
|
||||
{
|
||||
if(xdata.IsEmpty() || ydata.IsEmpty())
|
||||
return false;
|
||||
|
||||
if(!IsSorted(xdata))
|
||||
return false;
|
||||
|
||||
bool first = true;
|
||||
double xold;
|
||||
for(int i = 0; i < xdata.GetCount(); ++i) {
|
||||
double x = xdata[i];
|
||||
if(first)
|
||||
xold = x;
|
||||
else {
|
||||
first = false;
|
||||
if( fabs(x - xold) < 1)
|
||||
return false;
|
||||
xold = x;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -3,19 +3,6 @@
|
|||
|
||||
NAMESPACE_UPP
|
||||
|
||||
template <class T>
|
||||
bool IsSorted(T& data) {
|
||||
int num = data.GetCount();
|
||||
if (num == 0)
|
||||
return false;
|
||||
if (num == 1)
|
||||
return 1;
|
||||
for (int i = 1; i < num; ++i) {
|
||||
if (data[i] < data[i - 1])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class DataSource {
|
||||
public:
|
||||
|
|
@ -33,6 +20,7 @@ public:
|
|||
virtual double f(double x) {NEVER(); return Null;}
|
||||
virtual double f(Vector<double> zn) {NEVER(); return Null;}
|
||||
virtual int64 GetCount() {NEVER(); return Null;}
|
||||
bool IsEmpty() {return GetCount() == 0;}
|
||||
virtual int GetznxCount(int64 id) {return 0;}
|
||||
virtual int GetznyCount(int64 id) {return 0;}
|
||||
virtual int GetznFixedCount() {return 0;}
|
||||
|
|
@ -50,6 +38,9 @@ public:
|
|||
virtual double MaxX(int64& id) {return Max(&DataSource::x, id);}
|
||||
virtual double MaxX() {int64 dummy; return Max(&DataSource::x, dummy);}
|
||||
|
||||
virtual double IsSortedY() {return IsSorted(&DataSource::y);}
|
||||
virtual double IsSortedX() {return IsSorted(&DataSource::x);}
|
||||
|
||||
virtual double AvgY() {return Avg(&DataSource::y);}
|
||||
virtual double AvgX() {return Avg(&DataSource::x);}
|
||||
virtual double StdDevY(double avg = Null) {return StdDev(&DataSource::y, avg);}
|
||||
|
|
@ -63,6 +54,7 @@ public:
|
|||
double Min(Getdatafun getdata, int64& id);
|
||||
double Max(Getdatafun getdata, int64& id);
|
||||
double Avg(Getdatafun getdata);
|
||||
double IsSorted(Getdatafun getdata);
|
||||
double StdDev(Getdatafun getdata, double avg = Null);
|
||||
double Variance(Getdatafun getdata, double avg = Null);
|
||||
Vector<int64> UpperEnvelope(Getdatafun getdataY, Getdatafun getdataX, double width);
|
||||
|
|
@ -402,18 +394,11 @@ public:
|
|||
virtual inline int64 GetCount() {return numPoints;}
|
||||
};
|
||||
|
||||
class Spline {
|
||||
public:
|
||||
bool Load(Vector<double>& xdata, Vector<double>& ydata);
|
||||
double GetY(double x);
|
||||
|
||||
private:
|
||||
struct Coeff{double a, b, c, d, x;};
|
||||
Vector<Coeff> coeff;
|
||||
|
||||
bool IsInputSane(Vector<double>& xdata, Vector<double>& ydata);
|
||||
struct PointfLess {
|
||||
bool operator () (const Pointf& a, const Pointf& b) const { return a.x < b.x; }
|
||||
};
|
||||
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -334,6 +334,89 @@ String EvalExpr::EvalStr(String line, int numDigits) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
ExplicitEquation::FitError SplineEquation::Fit(DataSource &data, double &r2)
|
||||
{
|
||||
Vector<Pointf> seriesRaw;
|
||||
for (int64 i = 0; i < data.GetCount(); ++i) { // Remove Nulls
|
||||
if (!IsNull(data.x(i)) && !IsNull(data.y(i)))
|
||||
seriesRaw << Pointf(data.x(i), data.y(i));
|
||||
}
|
||||
|
||||
if(seriesRaw.IsEmpty())
|
||||
return InadequateDataSource;
|
||||
|
||||
PointfLess less;
|
||||
Sort(seriesRaw, less); // Sort
|
||||
|
||||
Vector<Pointf> series;
|
||||
for (int i = 1; i < seriesRaw.GetCount(); ++i) { // Remove points with duplicate x
|
||||
if (seriesRaw[i].x != seriesRaw[i - 1].x)
|
||||
series << seriesRaw[i];
|
||||
}
|
||||
|
||||
r2 = 0;
|
||||
|
||||
int n = int(series.GetCount()) - 1;
|
||||
|
||||
Buffer<double> h(n);
|
||||
for(int i = 0; i < n; ++i)
|
||||
h[i] = (series[i+1].x - series[i].x);
|
||||
|
||||
Buffer<double> alpha(n);
|
||||
for(int i = 1; i < n; ++i)
|
||||
alpha[i] = (3.*(series[i+1].y - series[i].y)/h[i] - 3*(series[i].y - series[i-1].y)/h[i-1]);
|
||||
|
||||
Buffer<double> c(n+1), l(n+1), mu(n+1), z(n+1);
|
||||
l[0] = 1;
|
||||
mu[0] = 0;
|
||||
z[0] = 0;
|
||||
|
||||
for(int i = 1; i < n; ++i) {
|
||||
l[i] = 2.*(series[i+1].x - series[i-1].x) - h[i-1]*mu[i-1];
|
||||
mu[i] = h[i]/l[i];
|
||||
z[i] = (alpha[i] - h[i-1]*z[i-1])/l[i];
|
||||
}
|
||||
|
||||
l[n] = 1.;
|
||||
z[n] = 0;
|
||||
c[n] = 0;
|
||||
|
||||
Buffer<double> b(n), d(n);
|
||||
for(int i = n-1; i >= 0; --i) {
|
||||
c[i] = z[i] - mu[i] * c[i+1];
|
||||
b[i] = (series[i+1].y - series[i].y)/h[i] - h[i]*(c[i+1] + 2*c[i])/3.;
|
||||
d[i] = (c[i+1] - c[i])/3./h[i];
|
||||
}
|
||||
|
||||
ncoeff = n;
|
||||
coeff.Alloc(ncoeff);
|
||||
for(int i = 0; i < n; ++i) {
|
||||
coeff[i].x = series[i].x;
|
||||
coeff[i].a = series[i].y;
|
||||
coeff[i].b = b[i];
|
||||
coeff[i].c = c[i];
|
||||
coeff[i].d = d[i];
|
||||
}
|
||||
return NoError;
|
||||
}
|
||||
|
||||
double SplineEquation::f(double x)
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j < ncoeff; j++) {
|
||||
if(coeff[j].x > x) {
|
||||
if(j == 0)
|
||||
j++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
j--;
|
||||
|
||||
double dx = x - coeff[j].x;
|
||||
return coeff[j].a + coeff[j].b*dx + coeff[j].c*dx*dx + coeff[j].d*dx*dx*dx;
|
||||
}
|
||||
|
||||
INITBLOCK {
|
||||
ExplicitEquation::Register<LinearEquation>("LinearEquation");
|
||||
ExplicitEquation::Register<PolynomialEquation2>("PolynomialEquation2");
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public:
|
|||
ImproperInputParameters = -3,
|
||||
TooManyFunctionEvaluation = -4
|
||||
};
|
||||
FitError Fit(DataSource &series, double &r2);
|
||||
virtual FitError Fit(DataSource &series, double &r2);
|
||||
FitError Fit(DataSource &series) {double dummy; return Fit(series, dummy);}
|
||||
virtual void GuessCoeff(DataSource &series) = 0;
|
||||
|
||||
|
|
@ -225,6 +225,23 @@ public:
|
|||
void SetDegree(int num) {NEVER();}
|
||||
};
|
||||
|
||||
class SplineEquation : public ExplicitEquation {
|
||||
public:
|
||||
SplineEquation() {}
|
||||
double f(double x);
|
||||
virtual String GetName() {return t_("Spline");}
|
||||
void SetDegree(int num) {NEVER();}
|
||||
void GuessCoeff(DataSource &series) {NEVER();}
|
||||
String GetEquation(int) {return t_("Spline");}
|
||||
FitError Fit(DataSource &series, double &r2);
|
||||
FitError Fit(DataSource &series) {double dummy; return Fit(series, dummy);}
|
||||
|
||||
private:
|
||||
struct Coeff{double a, b, c, d, x;};
|
||||
Buffer<Coeff> coeff;
|
||||
int ncoeff;
|
||||
};
|
||||
|
||||
|
||||
class EvalExpr {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -241,18 +241,19 @@ void ScatterDraw::DrawLegend(Draw& w, const Size &size, int scale) const {
|
|||
}
|
||||
Font italic = scaledFont;
|
||||
italic.Italic();
|
||||
scaledFont.Bold();
|
||||
for(int row = 0, start = 0; row <= nrows; row++) {
|
||||
for(int i = start; i < min(start + nlr, nlab); i++) {
|
||||
int lx = rect.left + (i - start)*legendWidth + xWidth;
|
||||
int ly = (rowIncSign >= 0 ? rect.top : rect.bottom) +
|
||||
rowIncSign*int(rowHeight*(row + 0.6) + loclegendRowSpacing*(row + 0.5));
|
||||
Vector <Point> vp;
|
||||
vp << Point(lx, ly) << Point(lx + lineLen, ly);
|
||||
Vector <Point> line;
|
||||
line << Point(lx, ly) << Point(lx + lineLen, ly);
|
||||
if (series[i].opacity > 0 && series[i].seriesPlot)
|
||||
DrawPolylineOpa(w, vp, scale, 1, scale*series[i].thickness, series[i].color, series[i].dash);
|
||||
Point p(lx + scale*7, ly);
|
||||
DrawPolylineOpa(w, line, scale, 1, series[i].thickness, series[i].color, series[i].dash);
|
||||
Point mark_p(lx + scale*7, ly);
|
||||
if (series[i].markWidth >= 1 && series[i].markPlot)
|
||||
series[i].markPlot->Paint(w, scale, p, series[i].markWidth, series[i].markColor,
|
||||
series[i].markPlot->Paint(w, scale, mark_p, series[i].markWidth, series[i].markColor,
|
||||
series[i].markBorderWidth, series[i].markBorderColor);
|
||||
Font &font = series[i].primaryY ? scaledFont : italic;
|
||||
DrawText(w, lx + lineLen + xWidth, ly - scale*6, 0, legends[i], font, series[i].color);
|
||||
|
|
@ -1749,7 +1750,7 @@ void DrawPolylineOpa(Draw& w, const Vector<Point> &p, int scale, double opacity,
|
|||
ASSERT(!p.IsEmpty());
|
||||
Color color = GetOpaqueColor(_color, background, opacity) ;
|
||||
if (dash == LINE_SOLID)
|
||||
w.DrawPolyline(p, fround(thick), color);
|
||||
w.DrawPolyline(p, fround(thick*scale), color);
|
||||
else {
|
||||
Vector <double> &pat = GetDashedArray(dash);
|
||||
if (pat.IsEmpty())
|
||||
|
|
@ -1769,7 +1770,7 @@ void DrawPolylineOpa(Draw& w, const Vector<Point> &p, int scale, double opacity,
|
|||
++i;
|
||||
}
|
||||
if (Even(iPat))
|
||||
w.DrawLine(begin, end, fround(thick), color);
|
||||
w.DrawLine(begin, end, fround(thick*scale), color);
|
||||
if (d >= len) {
|
||||
iPat++;
|
||||
if (iPat == pat.GetCount())
|
||||
|
|
|
|||
|
|
@ -751,6 +751,8 @@ void ScatterDraw::Plot(T& w, const Size &size, int scale)
|
|||
if (drawVGrid) {
|
||||
if (!isPolar) {
|
||||
double x0 = plotW*xMinUnit/xRange;
|
||||
if ((xRange - xMinUnit)/xMajorUnit > 20)
|
||||
xMajorUnit = (xRange - xMinUnit)/20.;
|
||||
for(int i = 0; xMinUnit + i*xMajorUnit < xRange; i++) {
|
||||
int xg = fround(x0 + i*plotW/d1);
|
||||
if (xg > 2*gridWidth && xg < plotW - 2*gridWidth)
|
||||
|
|
@ -767,6 +769,8 @@ void ScatterDraw::Plot(T& w, const Size &size, int scale)
|
|||
if (drawHGrid) {
|
||||
if (!isPolar) {
|
||||
double y0 = -plotH*yMinUnit/yRange + plotH;
|
||||
if ((yRange - yMinUnit)/yMajorUnit > 20)
|
||||
yMajorUnit = (yRange - yMinUnit)/20.;
|
||||
for(int i = 0; yMinUnit + i*yMajorUnit < yRange; i++) {
|
||||
int yg = fround(y0 - i*plotH/d2);
|
||||
if (yg > 2*gridWidth && yg < plotH - 2*gridWidth)
|
||||
|
|
|
|||
|
|
@ -68,3 +68,9 @@ caES("Racional_1")
|
|||
esES("Racional_1")
|
||||
euES("")
|
||||
frFR("")
|
||||
|
||||
T_("Spline")
|
||||
caES("")
|
||||
esES("")
|
||||
euES("")
|
||||
frFR("")
|
||||
|
|
|
|||
|
|
@ -153,4 +153,5 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue