📄 plotobs.cpp
字号:
Bounds.Xmin = Bounds.Ymin = HUGE_VAL;
Bounds.Xmax = Bounds.Ymax = -HUGE_VAL;
}
else{
if(parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH &&
Bounds.Xmax > Bounds.Xmin && Bounds.Ymax > Bounds.Ymin) {
((Plot*)parent)->CheckBounds(Bounds.Xmin, Bounds.Ymin);
((Plot*)parent)->CheckBounds(Bounds.Xmax, Bounds.Ymax);
return true;
}
}
dirty = false;
case CMD_UPDATE:
if(cmd == CMD_UPDATE){
if (Symbols) SavVarObs((GraphObj **)Symbols, nPoints, UNDO_CONTINUE);
if (Bars) SavVarObs((GraphObj **)Bars, nPoints, UNDO_CONTINUE);
if (Errors) SavVarObs((GraphObj **)Errors, nPoints, UNDO_CONTINUE);
if (Arrows) SavVarObs((GraphObj **)Arrows, nPoints, UNDO_CONTINUE);
if (DropLines) SavVarObs((GraphObj **)DropLines, nPoints, UNDO_CONTINUE);
if (Labels) SavVarObs((GraphObj **)Labels, nPoints, UNDO_CONTINUE);
dirty = true;
}
case CMD_SET_DATAOBJ:
if(cmd == CMD_SET_DATAOBJ) {
Id = GO_PLOTSCATT;
if(data && data == (DataObj *) tmpl) return true;
data = (DataObj *)tmpl;
}
ForEach(cmd, tmpl, o);
if(cmd == CMD_AUTOSCALE && parent && parent->Id >= GO_PLOT && parent->Id < GO_GRAPH
&& Bounds.Xmax > Bounds.Xmin && Bounds.Ymax > Bounds.Ymin) {
((Plot*)parent)->CheckBounds(Bounds.Xmin, Bounds.Ymin);
((Plot*)parent)->CheckBounds(Bounds.Xmax, Bounds.Ymax);
}
return true;
case CMD_HIDE_MARK:
return ForEach(cmd, tmpl, o);
case CMD_MUTATE: case CMD_REPL_GO:
dirty = true;
return ForEach(cmd == CMD_REPL_GO ? FE_REPLGO : FE_MUTATE, tmpl, o);
case CMD_SYMTEXT: case CMD_SYMTEXT_UNDO: case CMD_SYM_RANGETEXT:
case CMD_SYMTEXTDEF: case CMD_SYM_TYPE:
if(Symbols) for(i = 0; i < nPoints; i++)
if(Symbols[i]) Symbols[i]->Command(cmd, tmpl, o);
return true;
case CMD_SETTEXTDEF:
if(Labels) for(i = 0; i < nPoints; i++)
if(Labels[i]) Labels[i]->Command(cmd, tmpl, o);
return true;
case CMD_DL_LINE: case CMD_DL_TYPE:
if(DropLines) for(i = 0; i < nPoints; i++)
if(DropLines[i]) DropLines[i]->Command(cmd, tmpl, o);
return true;
case CMD_ERR_TYPE: case CMD_WHISKER_STYLE:
if(Errors) for(i = 0; i < nPoints; i++) {
if(Errors[i]) Errors[i]->Command(cmd, tmpl, o);
}
case CMD_BAR_TYPE: case CMD_BAR_FILL:
if(Bars) for(i = 0; i < nPoints; i++) {
if(Bars[i]) Bars[i]->Command(cmd, tmpl, o);
}
return true;
case CMD_ARROW_TYPE: case CMD_ARROW_ORG:
if(Arrows) for(i = 0; i < nPoints; i++) {
if(Arrows[i]) Arrows[i]->Command(cmd, tmpl, o);
}
return true;
case CMD_DELOBJ:
dirty = true;
if(parent && tmpl && o) return ForEach(FE_DELOBJ, tmpl, o);
break;
case CMD_SAVE_SYMBOLS:
return SavVarObs((GraphObj **)Symbols, nPoints, 0L);
case CMD_SAVE_BARS:
return SavVarObs((GraphObj **)Bars, nPoints, 0L);
case CMD_SAVE_ERRS:
return SavVarObs((GraphObj **)Errors, nPoints, 0L);
case CMD_SAVE_ARROWS:
return SavVarObs((GraphObj **)Arrows, nPoints, 0L);
case CMD_SAVE_DROPLINES:
return SavVarObs((GraphObj **)DropLines, nPoints, 0L);
case CMD_SAVE_LABELS:
return SavVarObs((GraphObj **)Labels, nPoints, 0L);
}
return false;
}
bool
PlotScatt::ForEach(int cmd, void *tmp, anyOutput *o)
{
int i, j;
GraphObj **obs[] = {(GraphObj**)Symbols, (GraphObj**)Errors, (GraphObj**)Arrows,
(GraphObj**)DropLines, (GraphObj**)Labels, (GraphObj**)Bars};
GraphObj ***go = 0L;
GraphObj **tmpPlots;
bool bRedraw, bFound;
switch(cmd) {
case FE_MUTATE:
case FE_REPLGO:
if((tmpPlots = (GraphObj **)tmp) && tmpPlots[0] && tmpPlots[1]) {
for(j = 0; j < 6; j++){
if(obs[j]) for(i = 0; i < nPoints; i++){
if(obs[j][i] && obs[j][i] == tmpPlots[0]) {
if(cmd == FE_REPLGO) return ReplaceGO(&obs[j][i], tmpPlots);
else {
Undo.MutateGO(&obs[j][i], tmpPlots[1], 0L, o);
return true;
}
}
}
}
if(TheLine == tmpPlots[0]){
if(cmd == FE_REPLGO) return ReplaceGO((GraphObj**)&TheLine, tmpPlots);
else {
Undo.MutateGO((GraphObj**)&TheLine, tmpPlots[1], 0L, o);
return true;
}
}
}
return false;
case FE_PARENT:
for(j = 0; j < 6; j++){
if(obs[j]) for(i = 0; i < nPoints; i++){
if(obs[j][i]) obs[j][i]->parent = this;
}
}
if(TheLine) TheLine->parent = this;
return true;
case CMD_UPDATE:
case CMD_SET_DATAOBJ:
case CMD_AUTOSCALE:
for(j = 0; j < 6; j++){
if(obs[j]) for(i = 0; i < nPoints; i++){
if(obs[j][i]) obs[j][i]->Command(cmd, tmp, o);
}
}
if(TheLine) TheLine->Command(cmd, tmp, o);
return true;
case FE_PLOT:
if(TheLine) TheLine->DoPlot(o);
for(j = 5; j >= 0; j--){
if(obs[j]) for(i = 0; i < nPoints; i++){
if(obs[j][i]) obs[j][i]->DoPlot(o);
}
}
return true;
case FE_FLUSH:
for(j = 0; j < 6; j++){
if(obs[j]) {
for(i = 0; i < nPoints; i++) if(obs[j][i]) DeleteGO(obs[j][i]);
free(obs[j]); obs[j] = 0L;
}
}
if(ErrRange) free(ErrRange); if(yRange) free(yRange);
if(xRange) free(xRange); if(LbRange) free(LbRange);
ErrRange = yRange = xRange = LbRange = 0L;
if(TheLine) DeleteGO(TheLine);
Bars = 0L; Symbols = 0L; Errors = 0L;
Arrows = 0L; DropLines = 0L; Labels = 0L; TheLine = 0L;
return true;
case FE_DELOBJ:
if(!o) return false;
for(j = 0, bRedraw = false, go = 0L; j < 6 && !bRedraw; j++) {
if(obs[j]) for(i = 0; i < nPoints; i++){
if(obs[j][i]){
if(tmp == (void*)obs[j][i]) {
o->MrkMode = MRK_NONE;
o->MouseCursor(MC_WAIT, true);
Undo.DeleteGO(&obs[j][i], 0L, o);
switch(j) {
case 0: go = (GraphObj***)&Symbols; break;
case 1: go = (GraphObj***)&Errors; break;
case 2: go = (GraphObj***)&Arrows; break;
case 3: go = (GraphObj***)&DropLines; break;
case 4: go = (GraphObj***)&Labels; break;
case 5: go = (GraphObj***)&Bars; break;
}
bRedraw = true;
break;
}
}
}
}
if(!bRedraw && TheLine && tmp == (void *) TheLine) {
o->MrkMode = MRK_NONE;
Undo.DeleteGO((GraphObj**)(&TheLine), 0L, o);
bRedraw = true;
}
if(bRedraw && go) for(i = j = 0; i < nPoints; i++) if(go[0][i]) j++;
if(!j) Undo.DropMemory(this, (void**)go, UNDO_CONTINUE);
if(bRedraw && dirty) Command(CMD_AUTOSCALE, 0L, o);
if(!Bars && !Symbols && !Errors && !Arrows && !TheLine && !DropLines
&& !Labels) parent->Command(CMD_DELOBJ_CONT, this, o);
else if(bRedraw) parent->Command(CMD_REDRAW, NULL, o);
return bRedraw;
case CMD_HIDE_MARK:
if(!o || !tmp) return false;
if(bFound =(tmp == (void*)TheLine)) TheLine->DoMark(o, false);
else for(j = 5; j >= 0 && !bFound; j--){
if(obs[j]) for(i = 0; i < nPoints && !bFound; i++){
if(bFound = (tmp == (void*)obs[j][i])) obs[j][i]->DoMark(o, false);
else if(obs[j][i] && obs[j][i]->Id == GO_MLABEL &&
obs[j][i]->Command(cmd, tmp, o)) return true;
}
}
return bFound;
default: //pass command to all objects
for(j = 0; j < 6; j++){
if(obs[j]) for(i = 0; i < nPoints; i++){
if(obs[j][i]) if(obs[j][i]->Command(cmd, tmp, o)) return true;
}
}
if(TheLine) return (TheLine->Command(cmd, tmp, o));
return false;
}
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// xyStat is based on scatterplot
xyStat::xyStat(GraphObj *par, DataObj *d):PlotScatt(par, d, 0L)
{
FileIO(INIT_VARS);
Id = GO_XYSTAT;
}
xyStat::xyStat(int src):PlotScatt(0)
{
FileIO(INIT_VARS);
if(src == FILE_READ) {
FileIO(FILE_READ);
}
}
xyStat::~xyStat()
{
ForEach(FE_FLUSH, 0L, 0L);
if(curr_data) delete curr_data; curr_data = 0L;
if(case_prefix) free(case_prefix); case_prefix = 0L;
if(yRange) free(yRange); yRange = 0L;
if(xRange) free(xRange); xRange = 0L;
if(name) free(name); name=0L;
Undo.InvalidGO(this);
}
bool
xyStat::Command(int cmd, void *tmpl, anyOutput *o)
{
switch (cmd) {
case CMD_UPDATE:
if (Symbols) SavVarObs((GraphObj **)Symbols, nPoints, UNDO_CONTINUE);
if (Bars) SavVarObs((GraphObj **)Bars, nPoints, UNDO_CONTINUE);
if (Errors) SavVarObs((GraphObj **)Errors, nPoints, UNDO_CONTINUE);
if (Labels) SavVarObs((GraphObj **)Labels, nPoints, UNDO_CONTINUE);
CreateData();
ForEach(CMD_SET_DATAOBJ, curr_data, o);
ForEach(CMD_UPDATE, tmpl, o);
return dirty = true;
case CMD_SET_DATAOBJ:
if(cmd == CMD_SET_DATAOBJ) {
Id = GO_XYSTAT;
if(data && data == (DataObj *) tmpl) return true;
if(curr_data) delete curr_data; curr_data = 0L;
data = (DataObj *)tmpl;
if(data && !curr_data) CreateData();
tmpl = curr_data;
}
ForEach(cmd, tmpl, o);
return true;
default:
return PlotScatt::Command(cmd, tmpl, o);
}
return false;
}
void
xyStat::CreateData()
{
int i, j, k, l, m, n, *ny;
double x, y, ss, d, lo, hi, **ay, *ax, *tay, *q1, *q2, *q3;
lfPOINT *xy;
AccRange *rX, *rY;
if(curr_data) delete curr_data; curr_data = 0L;
if(!data || !xRange || !yRange || !xRange[0] || !yRange[0]) return;
if(!(rX = new AccRange(xRange)) || !(rY = new AccRange(yRange))) return;
m = rX->CountItems(); n = 0;
if(m < 2 || !(xy = (lfPOINT*) malloc(m * sizeof(lfPOINT)))) {
delete rX; delete rY;
return;
}
ny = (int*) calloc(m, sizeof(int));
ay = (double**) calloc(m, sizeof(double*));
ax = (double*) calloc(m, sizeof(double));
tay = (double*)malloc(m * sizeof(double));
if(!ny || !ay || !ax || !tay) {
if(ny) free(ny); if(ay) free(ay);
if(ax) free(ax); if(tay) free(tay);
delete rX; delete rY;
return;
}
rX->GetFirst(&i, &j); rY->GetFirst(&k, &l);
rX->GetNext(&i, &j); rY->GetNext(&k, &l); n=0;
do {
if(data->GetValue(j, i, &x) && data->GetValue(l, k, &y)){
xy[n].fx = x; xy[n].fy = y;
n++;
}
}while(rX->GetNext(&i, &j) && rY->GetNext(&k, &l));
delete rX; delete rY;
if(!n) {
if(ny) free(ny); if(ay) free(ay);
if(ax) free(ax); if(tay) free(tay);
return;
}
SortFpArray(n, xy);
for(i = j = 0; i < (n-1); i++, j++) {
ax[j] = xy[i].fx; tay[0] = xy[i].fy;
ny[j] = 1;
for(k = 1; xy[i+1].fx == xy[i].fx; k++) {
tay[k] = xy[i+1].fy;
i++; ny[j]++;
}
ay[j] = (double*)memdup(tay, k * sizeof(double), 0);
}
if(xy[i].fx > xy[i-1].fx) {
ax[j] = xy[i].fx; tay[0] = xy[i].fy;
ny[j] = 1;
ay[j++] = (double*)memdup(tay, sizeof(double), 0);
}
if(type & 0x0480) { //medians and/or percentiles required
q1 = (double *)malloc(j * sizeof(double));
q2 = (double *)malloc(j * sizeof(double));
q3 = (double *)malloc(j * sizeof(double));
if(q1 && q2 && q3) {
for(i = 0; i < j; i++) {
if(ny[i] > 1) d_quartile(ny[i], ay[i], q1+i, q2+i, q3+i);
else q1[i] = q2[i] = q3[i] = *ay[i];
}
}
else type &= (~0x0480);
}
else q1 = q2 = q3 = 0L;
if((curr_data = new DataObj()) && curr_data->Init(j, 6)) {
for(i = 0; i < j; i++) curr_data->SetValue(i,0,ax[i]); // set x-values
for(i = 0; i < j; i++) { // set y-values
if(ny[i] > 1) switch(type & 0x00f0) {
case 0x0010: default:
curr_data->SetValue(i, 1, y=d_amean(ny[i], ay[i]));
break;
case 0x0020:
curr_data->SetValue(i, 1, y=d_gmean(ny[i], ay[i]));
break;
case 0x0040:
curr_data->SetValue(i, 1, y=d_hmean(ny[i], ay[i]));
break;
case 0x0080:
curr_data->SetValue(i, 1, y=q2[i]);
break;
}
else curr_data->SetValue(i, 1, y= *ay[i]);
curr_data->SetValue(i, 4, y);
}
for(i = 0; i < j; i++) { // set errors
switch(type & 0x1f00) {
case 0x0100: case 0x0200: case 0x1000: //SD, SEM, conf. int.
if(ny[i] > 1) {
y = d_amean(ny[i], ay[i]);
for(k = 0, ss = 0.0; k < (ny[i]); k++) {
ss += ((d=ay[i][k]-y)*d);
ny[i] = ny[i];
}
ss = ss/(double)(ny[i]-1);
switch(type & 0x1f00) {
case 0x0100:
curr_data->SetValue(i, 2, sqrt(ss));
break;
case 0x0200:
curr_data->SetValue(i, 2, sqrt(ss)/sqrt(ny[i]));
break;
case 0x1000:
d = distinv(t_dist, ny[i]-1, 1, 1.0-(ci/100.0), 2.0);
curr_data->SetValue(i, 2, d * sqrt(ss)/sqrt(ny[i]));
break;
}
}
else curr_data->SetValue(i, 2, 0.0);
if(curr_data->GetValue(i, 1, &y) && curr_data->GetValue(i, 2, &hi))
curr_data->SetValue(i, 4, hi+y);
break;
case 0x0400: //percentiles
curr_data->SetValue(i, 2, q1[i]); curr_data->SetValue(i, 3, q3[i]);
curr_data->SetValue(i, 4, q3[i]);
break;
case 0x0800: //min-max
lo = hi = *ay[i];
for(k = 1; k < ny[i]; k++) {
if(ay[i][k] < lo) lo = ay[i][k];
if(ay[i][k] > hi) hi = ay[i][k];
}
curr_data->SetValue(i, 2, lo); curr_data->SetValue(i, 3, hi);
curr_data->SetValue(i, 4, hi);
break;
}
}
if(type & 0x6000) for(i = 0; i < j; i++) { // number of cases
sprintf(TmpTxt, "%s%d", case_prefix ? case_prefix : "", ny[i]);
curr_data->SetText(i, 5, TmpTxt);
}
}
else {
if(curr_data) delete curr_data;
curr_data = 0L;
}
if(q1) free(q1); if(q2) free(q2); if(q3) free(q3);
for(i = 0; i < m; i++) if(ay[i]) free(ay[i]);
free(tay); free(ay); free(ax); free(ny); free(xy);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// BarChart is based on scatterplot
BarChart::BarChart(GraphObj *par, DataObj *d):PlotScatt(par, d, 0L)
{
Id = GO_BARCHART;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Frequenc distribution: bar chart with function
FreqDist::FreqDist(GraphObj *par, DataObj *d):Plot(par, d)
{
FileIO(INIT_VARS);
Id = GO_FREQDIST;
}
FreqDist::FreqDist(int src):Plot(0L, 0L)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -