ScatterDraw: Added histogram

git-svn-id: svn://ultimatepp.org/upp/trunk@13746 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
koldo 2019-12-09 11:32:39 +00:00
parent 88d829fb77
commit ebd3e1c303
8 changed files with 350 additions and 4 deletions

View file

@ -47,7 +47,8 @@ public:
double AvgY() {return Avg(&DataSource::y);}
double AvgX() {return Avg(&DataSource::x);}
double RMSY() {return RMS(&DataSource::y);}
double StdDevY(double avg = Null) {return StdDev(&DataSource::y, avg);}
double StdDevY(double avg = Null) {return StdDev(&DataSource::y, avg);}
double StdDevX(double avg = Null) {return StdDev(&DataSource::x, avg);}
double VarianceY(double avg = Null) {return Variance(&DataSource::y, avg);}
Vector<int64> UpperEnvelopeY(double width) {return UpperEnvelope(&DataSource::y, &DataSource::x, width);}
Vector<int64> LowerEnvelopeY(double width) {return LowerEnvelope(&DataSource::y, &DataSource::x, width);}

View file

@ -624,6 +624,7 @@ INITBLOCK {
ExplicitEquation::Register<FourierEquation4>("FourierEquation4");
ExplicitEquation::Register<WeibullEquation>("WeibullEquation");
ExplicitEquation::Register<WeibullCumulativeEquation>("WeibullCumulativeEquation");
ExplicitEquation::Register<NormalEquation>("NormalEquation");
}
}

View file

@ -366,6 +366,40 @@ private:
double factor;
};
class NormalEquation : public ExplicitEquation {
public:
NormalEquation() {SetCoeff(1, 1, 1);}
NormalEquation(double c, double mean, double std) {SetCoeff(c, mean, std);}
double f(double x) {
double c = coeff[0];
double mean = coeff[1];
double std = coeff[2];
return c*exp(-0.5*sqr((x - mean)/std))/(std*sqrt(2*M_PI));
}
virtual String GetName() {return t_("Normal");}
virtual String GetEquation(int numDigits = 3) {
String c = FormatCoeff(0, numDigits);
String mean = FormatCoeff(1, numDigits);
String std = FormatCoeff(2, numDigits);
String ret = Format("%s/(%s*sqrt(2*PI))*e^(-1/2((x-%s)/%s))", c, std, mean, std);
ret.Replace("+ -", "- ");
return ret;
}
virtual void GuessCoeff(DataSource &) {}
virtual void _GuessCoeff(DataSource &series) {
double mean = series.AvgX();
double std = series.StdDevX();
double c = series.MaxY()*std*sqrt(2*M_PI);
SetCoeff(c, mean, std);
}
FitError Fit(DataSource &series, double &r2) {
_GuessCoeff(series);
return ExplicitEquation::Fit(series, r2);
}
FitError Fit(DataSource &series) {double dummy; return Fit(series, dummy);}
void SetDegree(int ) {NEVER();}
};
class Rational1Equation : public ExplicitEquation {
public:
Rational1Equation() {SetCoeff(1, 0, 0);}

View file

@ -0,0 +1,148 @@
#include <Core/Core.h>
#include <ScatterDraw/DataSource.h>
#include <plugin/Eigen/Eigen.h>
#include <ScatterDraw/Histogram.h>
namespace Upp {
Histogram::Histogram() {
Clear();
}
Histogram::Histogram(const Histogram &hist) {
*this = hist;
}
Histogram &Histogram::operator=(const Histogram &hist) {
totalVals = hist.totalVals;
values = hist.values;
ranges <<= hist.ranges;
return *this;
}
void Histogram::Clear() {
ranges.Clear();
values.resize(0);
}
Histogram &Histogram::Create2D(Vector<Vector<double> > &_ranges, Vector<double> &data, double total) {
Clear();
int numAxis = 2;
int numVals = 1;
for (int ix = 0; ix < numAxis; ++ix)
numVals *= _ranges[ix].GetCount();
valuesIdx.SetNumAxis(numAxis);
for (int ix = 0; ix < numAxis; ++ix)
valuesIdx.SetAxisDim(ix, _ranges[ix].GetCount());
values.resize(numVals);
values.setZero();
ranges.SetCount(numAxis);
for (int ix = 0; ix < numAxis; ++ix) {
ranges[ix].SetCount(_ranges[ix].GetCount());
for (int d = 0; d < _ranges[ix].GetCount(); ++d)
ranges[ix][d] = _ranges[ix][d];
}
totalVals = total;
for (int i = 0; i < data.GetCount(); ++i)
values(ptrdiff_t(i)) = data[i];
return *this;
}
Histogram &Histogram::Create(Upp::Array<HistogramDataAxis> &dataAxis, bool isY) {
Clear();
int numAxis = dataAxis.GetCount();
int numVals = 1;
for (int ix = 0; ix < numAxis; ++ix)
numVals *= dataAxis[ix].numVals;
valuesIdx.SetNumAxis(numAxis);
for (int ix = 0; ix < numAxis; ++ix)
valuesIdx.SetAxisDim(ix, dataAxis[ix].numVals);
values.resize(numVals);
values.setZero();
ranges.SetCount(numAxis);
Vector<double> delta;
delta.SetCount(numAxis);
for (int ix = 0; ix < numAxis; ++ix) {
ranges[ix].SetCount(dataAxis[ix].numVals);
delta[ix] = (dataAxis[ix].max - dataAxis[ix].min + 1)/dataAxis[ix].numVals;
for (int d = 0; d < dataAxis[ix].numVals; ++d)
ranges[ix][d] = (d + 1)*delta[ix];
}
totalVals = double(dataAxis[0].data.GetCount());
Vector<int> index;
index.SetCount(numAxis);
for (int64 i = 0; i < totalVals; ++i) {
for (int ix = 0; ix < numAxis; ++ix) {
double d = isY ? dataAxis[ix].data.y(i) : dataAxis[ix].data.x(i);
if (!IsNull(d)) {
double val = d - dataAxis[ix].min;
val = val/delta[ix];
if (val >= dataAxis[ix].numVals)
val = dataAxis[ix].numVals - 1;
else if (val < 0)
val = 0;
ASSERT(int(val) >= 0 && int(val) < dataAxis[ix].numVals);
index[ix] = int(val);
} else
index[ix] = Null;
}
if (!IsNull(index[0]))
values(valuesIdx.GetIndex(index))++;
}
return *this;
}
Histogram &Histogram::Create(DataSource &data, double min, double max, int numVals, bool isY) {
Clear();
values.resize(numVals);
values.setZero();
ranges.SetCount(1);
ranges[0].SetCount(numVals);
double delta = (max - min)/numVals;
for (int ii = 0; ii < numVals; ++ii)
ranges[0][ii] = (ii + 1)*delta;
int64 total = data.GetCount();
totalVals = 0;
for (int64 i = 0; i < total; ++i) {
double d = isY ? data.y(i) : data.x(i);
if (!IsNull(d)) {
double val = (d - min)/delta;
if (val >= numVals)
val = numVals - 1;
else if (val < 0)
val = 0;
values(int(val))++;
totalVals++;
}
}
return *this;
}
Histogram &Histogram::Normalize(double val) {
if (totalVals == val)
return *this;
if (totalVals > 0)
values *= val/totalVals;
totalVals = val;
return *this;
}
double Histogram::Compare(const Histogram &hist) {
ASSERT(hist.values.size() == values.size());
double res = 0;
ptrdiff_t size = values.size();
for(ptrdiff_t i = 0; i < size; i++)
res += min(values[i], hist.values[i]);
res /= totalVals;
return res;
}
}

View file

@ -0,0 +1,159 @@
#ifndef _Mathlib_Histogram_h_
#define _Mathlib_Histogram_h_
namespace Upp {
class MultiDimMatrixIndex {
public:
MultiDimMatrixIndex() {};
MultiDimMatrixIndex(int numAxis) {axisDim.SetCount(numAxis);};
void SetNumAxis(int numAxis) {axisDim.SetCount(numAxis);};
void SetAxisDim(int axis, int dim) {
ASSERT(axis >= 0 && axis < axisDim.GetCount() && dim > 0);
axisDim[axis] = dim;
}
void SetAxis1D(int dimX) {
ASSERT(dimX > 0);
axisDim.SetCount(1);
axisDim[0] = dimX;
}
void SetAxis2D(int dimX, int dimY) {
ASSERT(dimX > 0 && dimY > 0);
axisDim.SetCount(2);
axisDim[0] = dimX;
axisDim[1] = dimY;
}
const Upp::Vector<int> &GetAxisDim() {return axisDim;};
int GetIndex(Vector<int> &index) {
ASSERT_(index[0] >= 0 && index[0] < axisDim[0], Format("index[0]=%d", index[0]));
int ret = index[0];
int factor = 1;
for (int ix = 1; ix <= axisDim.GetCount()-1; ++ix) {
ASSERT(index[ix] >= 0 && index[ix] < axisDim[ix]);
factor *= axisDim[ix-1];
ret += factor*index[ix];
}
return ret;
}
template<typename T, typename... Args>
int GetIndex(T t, Args... args) {
Vector<int> index;
index << t;
AddIndex(index, args...);
return GetIndex(index);
}
inline int GetIndex(int x, int y) {
ASSERT(IsValid(x, y));
return x + axisDim[0]*y;
}
inline bool IsValid(int x, int y) {
return x >= 0 && x < axisDim[0] && y >= 0 && y < axisDim[1];
}
inline int GetNumAxis() {return axisDim.GetCount();}
void Xmlize(XmlIO xml) {
xml
("axisDim", axisDim)
;
}
void Jsonize(JsonIO& json) {
json
("axisDim", axisDim)
;
}
private:
Vector<int> axisDim;
template<typename T>
void AddIndex(Vector<int> &index, T t) {
index << t;
}
template<typename T, typename... Args>
void AddIndex(Vector<int> &index, T t, Args... args) {
index << t;
AddIndex(index, args...);
}
};
struct HistogramDataAxis : Moveable<HistogramDataAxis> {
HistogramDataAxis(DataSource &data, double min, double max, int numVals) : data(data), min(min), max(max), numVals(numVals) {}
DataSource &data;
double min, max;
int numVals;
};
class Histogram : public DataSource, public Moveable<Histogram> {
public:
Histogram();
Histogram(const Histogram &hist);
Histogram(const Nuller&) {SetNull();}
void SetNull() {Clear();}
bool IsNullInstance() const {return ranges.IsEmpty();}
virtual Histogram &operator=(const Histogram &hist);
void Clear();
Histogram &Create(DataSource &data, double min, double max, int numVals, bool isY);
Histogram &Create(Upp::Array<HistogramDataAxis> &dataAxis, bool isY);
Histogram &Create2D(Vector<Vector<double> > &_ranges, Vector<double> &data, double total);
Histogram &Normalize(double val = 1);
Histogram &Accumulative(bool _accum = true) {accumulative = _accum; return *this;}
double Compare(const Histogram &hist);
inline double &GetRange(int dim, int i) {return ranges[dim][i];};
inline int64 GetCount(int dim) const {return ranges[dim].GetCount();}
inline double GetValue(int index) {return y(index);}
inline double GetValue(int c, int r) {return y(valuesIdx.GetIndex(c, r));}
inline bool IsValid(int c, int r) {return valuesIdx.IsValid(c, r);}
inline double y(int64 id) {
ASSERT(values.size());
if (!accumulative)
return values(ptrdiff_t(id));
else {
double ret = 0;
for (ptrdiff_t i = 0; i <= ptrdiff_t(id); ++i)
ret += values(i);
return ret;
}
}
inline double x(int64 id) {
ASSERT(values.size());
return id == 0 ? ranges[0][0]/2 : (ranges[0][int(id)] + ranges[0][int(id)-1])/2.;
}
inline virtual int64 GetCount() const {return !values.size() ? 0 : values.size();};
void Xmlize(XmlIO xml) {
xml
("totalVals", totalVals)
("valuesIdx", valuesIdx)
("ranges", ranges)
;
Upp::Xmlize(xml, values);
}
void Jsonize(JsonIO& json) {
json
("totalVals", totalVals)
("valuesIdx", valuesIdx)
("ranges", ranges)
;
Upp::Jsonize(json, values);
}
protected:
double totalVals;
bool accumulative = false;
MultiDimMatrixIndex valuesIdx;
Eigen::VectorXd values;
Vector<Vector<double> > ranges;
};
}
#endif

View file

@ -477,9 +477,9 @@ String ScatterDraw::VariableFormat(double range, double d) {
Color ScatterDraw::GetNewColor(int index, int version) {
Color old[20] = {LtBlue(), LtRed(), LtGreen(), Black(), LtGray(), Brown(), Blue(), Red(), Green(), Gray(),
LtBlue(), LtRed(), LtGreen(), Black(), LtGray(), Brown(), Blue(), Red(), Green(), Gray()};
// Colors from http://tools.medialab.sciences-po.fr/iwanthue/
// Colours from http://tools.medialab.sciences-po.fr/iwanthue/
Color nwc[20] = {Color(197,127,117), Color(115,214,74), Color(205,80,212), Color(124,193,215), Color(85,82,139),
Color(63,72,41), Color(109,212,161), Color(207,72,48), Color(209,206,59), Color(194,134,55),
Color(109,212,161), Color(207,72,48), Color(209,206,59), Color(194,134,55), Color(63,72,41),
Color(201,63,109), Color(193,192,158), Color(91,134,56), Color(105,48,38), Color(201,170,200),
Color(86,117,119), Color(188,91,165), Color(124,120,216), Color(195,208,119), Color(79,46,75)};
if (index < 20) {
@ -1145,6 +1145,7 @@ void ScatterDraw::Show(int index, bool show) {
ASSERT(!series[index].IsDeleted());
series[index].opacity = show ? 1 : 0;
labelsChanged = true;
Refresh();
}

View file

@ -1290,7 +1290,7 @@ bool ScatterDraw::PlotTexts(T& w, const bool boldX, bool boldY) {
Upp::Index<String> xUnits, yUnits, yUnits2;
for (int i = 0; i < series.GetCount(); ++i) {
const ScatterSeries &serie = series[i];
if (serie.IsDeleted())
if (serie.IsDeleted() || serie.opacity == 0)
continue;
if (serie.primaryY) {
if (yLabel.IsEmpty()) {

View file

@ -16,6 +16,8 @@ file
DrawingFunctions.cpp,
DrawingFunctions.h,
SeriesPlot.h,
Histogram.cpp,
Histogram.h,
MarkPlot.h,
Legend.cpp,
Surf.cpp,