mupp: add x-axis error bar support to all plot outputs.
Previously only y-errors were rendered. The IPC data file format now includes x-errors per point (x, xPosErr, xNegErr, y, yPosErr, yNegErr, ...). Both the live canvas (PMuppCanvas) and the ROOT macro exports (GUI and script path) propagate x-errors to TGraphAsymmErrors; x-errors default to 0.0 when the parameter carries none. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1955,8 +1955,9 @@ void PmuppGui::createMacro()
|
||||
fout << " gStyle->SetCanvasColor(TColor::GetColor(255,255,255)); // canvas bkg to white" << Qt::endl;
|
||||
fout << Qt::endl;
|
||||
fout << " Int_t nn=0, i=0;" << Qt::endl;
|
||||
fout << " Double_t null[512];" << Qt::endl;
|
||||
fout << " Double_t xx[512];" << Qt::endl;
|
||||
fout << " Double_t xxPosErr[512];" << Qt::endl;
|
||||
fout << " Double_t xxNegErr[512];" << Qt::endl;
|
||||
fout << " Double_t yy[512];" << Qt::endl;
|
||||
fout << " Double_t yyPosErr[512];" << Qt::endl;
|
||||
fout << " Double_t yyNegErr[512];" << Qt::endl;
|
||||
@@ -1966,7 +1967,7 @@ void PmuppGui::createMacro()
|
||||
QString collName("");
|
||||
QString xLabel(""), yLabel("");
|
||||
char gLabel[128];
|
||||
QVector<double> xx, yy, yyPosErr, yyNegErr;
|
||||
QVector<double> xx, xxPosErr, xxNegErr, yy, yyPosErr, yyNegErr;
|
||||
double xMin=1.0e10, xMax=-1.0e10, yMin=1.0e10, yMax=-1.0e10;
|
||||
bool ok;
|
||||
for (int i=0; i<fXY.size(); i++) {
|
||||
@@ -1976,13 +1977,19 @@ void PmuppGui::createMacro()
|
||||
xLabel = fXY[i].getXlabel();
|
||||
pos = xLabel.indexOf(" (-");
|
||||
xLabel.remove(pos, xLabel.length()-pos);
|
||||
// get x-vector
|
||||
// get x-vector and x-errors (x-errors are optional; use 0.0 if not available)
|
||||
xx = getValues(collName, xLabel, ok);
|
||||
if (!ok) {
|
||||
QString msg = QString("Couldn't get x-axis data from '%1', coll: '%2'").arg(xLabel).arg(collName);
|
||||
QMessageBox::critical(this, "ERROR", msg);
|
||||
return;
|
||||
}
|
||||
xxPosErr = getPosErr(collName, xLabel, ok);
|
||||
if (!ok)
|
||||
xxPosErr = QVector<double>(xx.size(), 0.0);
|
||||
xxNegErr = getNegErr(collName, xLabel, ok);
|
||||
if (!ok)
|
||||
xxNegErr = QVector<double>(xx.size(), 0.0);
|
||||
getMinMax(xx, xMin, xMax);
|
||||
// a couple of x-vector specifics
|
||||
if ((xLabel == "dataT") || (xLabel == "dataE"))
|
||||
@@ -2019,14 +2026,18 @@ void PmuppGui::createMacro()
|
||||
snprintf(gLabel, sizeof(gLabel), "g_%d_%d", i, j);
|
||||
fout << " nn = " << xx.size() << ";" << Qt::endl;
|
||||
fout << Qt::endl;
|
||||
fout << " // null value vector" << Qt::endl;
|
||||
for (int k=0; k<xx.size(); k++) {
|
||||
fout << " null[" << k << "]=0.0;" << Qt::endl;
|
||||
}
|
||||
fout << " // xx" << Qt::endl;
|
||||
for (int k=0; k<xx.size(); k++) {
|
||||
fout << " xx[" << k << "]=" << xx[k] << ";" << Qt::endl;
|
||||
}
|
||||
fout << " // xxPosErr" << Qt::endl;
|
||||
for (int k=0; k<xx.size(); k++) {
|
||||
fout << " xxPosErr[" << k << "]=" << xxPosErr[k] << ";" << Qt::endl;
|
||||
}
|
||||
fout << " // xxNegErr" << Qt::endl;
|
||||
for (int k=0; k<xx.size(); k++) {
|
||||
fout << " xxNegErr[" << k << "]=" << fabs(xxNegErr[k]) << ";" << Qt::endl;
|
||||
}
|
||||
fout << " // yy" << Qt::endl;
|
||||
for (int k=0; k<xx.size(); k++) {
|
||||
fout << " yy[" << k << "]=" << yy[k] << ";" << Qt::endl;
|
||||
@@ -2040,7 +2051,7 @@ void PmuppGui::createMacro()
|
||||
fout << " yyNegErr[" << k << "]=" << fabs(yyNegErr[k]) << ";" << Qt::endl;
|
||||
}
|
||||
fout << Qt::endl;
|
||||
fout << " TGraphAsymmErrors *" << gLabel << " = new TGraphAsymmErrors(nn, xx, yy, null, null, yyNegErr, yyPosErr);" << Qt::endl;
|
||||
fout << " TGraphAsymmErrors *" << gLabel << " = new TGraphAsymmErrors(nn, xx, yy, xxNegErr, xxPosErr, yyNegErr, yyPosErr);" << Qt::endl;
|
||||
}
|
||||
}
|
||||
fout << Qt::endl;
|
||||
@@ -2138,7 +2149,7 @@ void PmuppGui::plot()
|
||||
int collTag = -1, pos;
|
||||
QString collName("");
|
||||
QString xLabel(""), yLabel("");
|
||||
QVector<double> xx, yy, yyPosErr, yyNegErr;
|
||||
QVector<double> xx, xxPosErr, xxNegErr, yy, yyPosErr, yyNegErr;
|
||||
QVector< QVector<double> > yyy, yyyPosErr, yyyNegErr;
|
||||
bool ok;
|
||||
|
||||
@@ -2165,13 +2176,19 @@ void PmuppGui::plot()
|
||||
xLabel = fXY[i].getXlabel();
|
||||
pos = xLabel.indexOf(" (-");
|
||||
xLabel.remove(pos, xLabel.length()-pos);
|
||||
// get x-vector
|
||||
// get x-vector and x-errors (x-errors are optional; use 0.0 if not available)
|
||||
xx = getValues(collName, xLabel, ok);
|
||||
if (!ok) {
|
||||
QString msg = QString("Couldn't get x-axis data from '%1', coll: '%2'").arg(xLabel).arg(collName);
|
||||
QMessageBox::critical(this, "ERROR", msg);
|
||||
return;
|
||||
}
|
||||
xxPosErr = getPosErr(collName, xLabel, ok);
|
||||
if (!ok)
|
||||
xxPosErr = QVector<double>(xx.size(), 0.0);
|
||||
xxNegErr = getNegErr(collName, xLabel, ok);
|
||||
if (!ok)
|
||||
xxNegErr = QVector<double>(xx.size(), 0.0);
|
||||
|
||||
xLabel = substituteDefaultLabels(xLabel);
|
||||
fout << "xLabel: " << xLabel << ", ";
|
||||
@@ -2253,9 +2270,9 @@ void PmuppGui::plot()
|
||||
}
|
||||
}
|
||||
|
||||
// data
|
||||
// data: x, xPosErr, xNegErr, y1, y1PosErr, y1NegErr, ...
|
||||
for (int j=0; j<xx.size(); j++) {
|
||||
fout << xx[j] << ", ";
|
||||
fout << xx[j] << ", " << xxPosErr[j] << ", " << xxNegErr[j] << ", ";
|
||||
for (int k=0; k<yyy.size()-1; k++) {
|
||||
fout << yyy[k][j] << ", " << yyyPosErr[k][j] << ", " << yyyNegErr[k][j] << ", ";
|
||||
}
|
||||
|
||||
@@ -784,15 +784,16 @@ int PmuppScript::macro(const QString str, const QString plotFln)
|
||||
fout << " gStyle->SetCanvasColor(TColor::GetColor(255,255,255)); // canvas bkg to white" << Qt::endl;
|
||||
fout << Qt::endl;
|
||||
fout << " Int_t nn=0, i=0;" << Qt::endl;
|
||||
fout << " Double_t null[512];" << Qt::endl;
|
||||
fout << " Double_t xx[512];" << Qt::endl;
|
||||
fout << " Double_t xxPosErr[512];" << Qt::endl;
|
||||
fout << " Double_t xxNegErr[512];" << Qt::endl;
|
||||
fout << " Double_t yy[512];" << Qt::endl;
|
||||
fout << " Double_t yyPosErr[512];" << Qt::endl;
|
||||
fout << " Double_t yyNegErr[512];" << Qt::endl;
|
||||
fout << Qt::endl;
|
||||
|
||||
// write data
|
||||
QVector<double> xx, yy, yyPosErr, yyNegErr;
|
||||
QVector<double> xx, xxPosErr, xxNegErr, yy, yyPosErr, yyNegErr;
|
||||
QString collName;
|
||||
int count=0;
|
||||
double x_min=0.0, x_max=0.0, x_min_new=0.0, x_max_new=0.0, y_min=0.0, y_max=0.0, y_min_new=0.0, y_max_new=0.0;
|
||||
@@ -812,6 +813,19 @@ int PmuppScript::macro(const QString str, const QString plotFln)
|
||||
std::vector<double> xVal = fVarHandler[idx].getValues();
|
||||
QVector<double> qvec(xVal.begin(), xVal.end());
|
||||
xx = qvec;
|
||||
// use variable errors for x
|
||||
std::vector<double> xErr = fVarHandler[idx].getErrors();
|
||||
QVector<double> qvecE(xErr.begin(), xErr.end());
|
||||
xxPosErr = qvecE;
|
||||
xxNegErr = qvecE;
|
||||
} else {
|
||||
// x-errors from parameter data handler (0.0 if not available)
|
||||
xxPosErr = fParamDataHandler->GetPosErr(collName, fPlotInfo[i].xLabel);
|
||||
if (xxPosErr.size() == 0)
|
||||
xxPosErr = QVector<double>(xx.size(), 0.0);
|
||||
xxNegErr = fParamDataHandler->GetNegErr(collName, fPlotInfo[i].xLabel);
|
||||
if (xxNegErr.size() == 0)
|
||||
xxNegErr = QVector<double>(xx.size(), 0.0);
|
||||
}
|
||||
// get x-axis min/max
|
||||
minMax(xx, x_min, x_max);
|
||||
@@ -858,14 +872,18 @@ int PmuppScript::macro(const QString str, const QString plotFln)
|
||||
}
|
||||
fout << " // " << ++count << ". data set" << Qt::endl;
|
||||
fout << " nn = " << xx.size() << ";" << Qt::endl;
|
||||
fout << " // null-values" << Qt::endl;
|
||||
for (int k=0; k<xx.size(); k++) {
|
||||
fout << " null[" << k << "]=0.0;" << Qt::endl;
|
||||
}
|
||||
fout << " // x-values" << Qt::endl;
|
||||
for (int k=0; k<xx.size(); k++) {
|
||||
fout << " xx[" << k << "]=" << xx[k] << ";" << Qt::endl;
|
||||
}
|
||||
fout << " // xxPosErr-values" << Qt::endl;
|
||||
for (int k=0; k<xxPosErr.size(); k++) {
|
||||
fout << " xxPosErr[" << k << "]=" << fabs(xxPosErr[k]) << ";" << Qt::endl;
|
||||
}
|
||||
fout << " // xxNegErr-values" << Qt::endl;
|
||||
for (int k=0; k<xxNegErr.size(); k++) {
|
||||
fout << " xxNegErr[" << k << "]=" << fabs(xxNegErr[k]) << ";" << Qt::endl;
|
||||
}
|
||||
fout << " // y-values" << Qt::endl;
|
||||
for (int k=0; k<yy.size(); k++) {
|
||||
dval = yy[k];
|
||||
@@ -891,7 +909,7 @@ int PmuppScript::macro(const QString str, const QString plotFln)
|
||||
fout << " yyPosErr[" << k << "]=" << dval << ";" << Qt::endl;
|
||||
}
|
||||
fout << Qt::endl;
|
||||
fout << " TGraphAsymmErrors *g_" << i << "_" << j << " = new TGraphAsymmErrors(nn, xx, yy, null, null, yyNegErr, yyPosErr);" << Qt::endl;
|
||||
fout << " TGraphAsymmErrors *g_" << i << "_" << j << " = new TGraphAsymmErrors(nn, xx, yy, xxNegErr, xxPosErr, yyNegErr, yyPosErr);" << Qt::endl;
|
||||
fout << Qt::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
- Tab-separated values
|
||||
- First line: "PLOT_DATA" header
|
||||
- Collection blocks with name, x-label, y-labels, and data points
|
||||
- Each data point: x-value, y-value, positive error, negative error
|
||||
- Each data point: x-value, x-pos-error, x-neg-error, y-value, y-pos-error, y-neg-error, ...
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
@@ -421,7 +421,7 @@ int PMuppCanvas::ReadPlotData(const Char_t *fln)
|
||||
fin.close();
|
||||
return -4;
|
||||
}
|
||||
if (tok->GetEntries() != (noOfDataTokens-1)*3+1) {
|
||||
if (tok->GetEntries() != noOfDataTokens*3) {
|
||||
std::cerr << "**ERROR** number of token in data line (" << tok->GetEntries() << ") is inconsistent with no of labels (" << noOfDataTokens << ")." << std::endl;
|
||||
fin.close();
|
||||
return -4;
|
||||
@@ -431,7 +431,7 @@ int PMuppCanvas::ReadPlotData(const Char_t *fln)
|
||||
data.yValue.resize(noOfDataTokens-1);
|
||||
|
||||
// raw data point
|
||||
// x-value
|
||||
// x-value (token 0)
|
||||
ostr = dynamic_cast<TObjString*>(tok->At(0));
|
||||
str = ostr->GetString();
|
||||
if (!str.IsFloat()) {
|
||||
@@ -441,9 +441,29 @@ int PMuppCanvas::ReadPlotData(const Char_t *fln)
|
||||
}
|
||||
data.xValue.push_back(str.Atof());
|
||||
|
||||
// y-value(s)
|
||||
// pos x error-value (token 1)
|
||||
ostr = dynamic_cast<TObjString*>(tok->At(1));
|
||||
str = ostr->GetString();
|
||||
if (!str.IsFloat()) {
|
||||
std::cerr << "**ERROR** token found in data line is not a number (" << str << ")." << std::endl;
|
||||
fin.close();
|
||||
return -5;
|
||||
}
|
||||
data.xErrPos.push_back(str.Atof());
|
||||
|
||||
// neg x error-value (token 2)
|
||||
ostr = dynamic_cast<TObjString*>(tok->At(2));
|
||||
str = ostr->GetString();
|
||||
if (!str.IsFloat()) {
|
||||
std::cerr << "**ERROR** token found in data line is not a number (" << str << ")." << std::endl;
|
||||
fin.close();
|
||||
return -5;
|
||||
}
|
||||
data.xErrNeg.push_back(str.Atof());
|
||||
|
||||
// y-value(s): starting at token 3, each group of 3 = y, yposErr, ynegErr
|
||||
Int_t idx=0;
|
||||
for (Int_t i=1; i<tok->GetEntries(); i+=3) {
|
||||
for (Int_t i=3; i<tok->GetEntries(); i+=3) {
|
||||
// y-value
|
||||
ostr = dynamic_cast<TObjString*>(tok->At(i));
|
||||
str = ostr->GetString();
|
||||
@@ -525,6 +545,8 @@ void PMuppCanvas::InitDataCollection(PDataCollection &coll)
|
||||
coll.xLabel = TString("");
|
||||
coll.yLabel.clear();
|
||||
coll.xValue.clear();
|
||||
coll.xErrPos.clear();
|
||||
coll.xErrNeg.clear();
|
||||
coll.yValue.clear();
|
||||
}
|
||||
|
||||
@@ -553,7 +575,8 @@ void PMuppCanvas::UpdateGraphs()
|
||||
gg = new TGraphAsymmErrors(fPlotData[i].xValue.size());
|
||||
for (UInt_t k=0; k<fPlotData[i].yValue[j].size(); k++) {
|
||||
gg->SetPoint(k, fPlotData[i].xValue[k], fPlotData[i].yValue[j][k].y);
|
||||
gg->SetPointError(k, 0.0, 0.0, fabs(fPlotData[i].yValue[j][k].eYneg), fPlotData[i].yValue[j][k].eYpos);
|
||||
gg->SetPointError(k, fabs(fPlotData[i].xErrNeg[k]), fPlotData[i].xErrPos[k],
|
||||
fabs(fPlotData[i].yValue[j][k].eYneg), fPlotData[i].yValue[j][k].eYpos);
|
||||
// set marker style and size
|
||||
if (idxS < fMarkerStyleList.size()) {
|
||||
gg->SetMarkerStyle(fMarkerStyleList[idxS]);
|
||||
@@ -666,12 +689,14 @@ void PMuppCanvas::ExportData()
|
||||
std::ofstream fout(fi.fFilename, std::ios_base::out);
|
||||
// write header
|
||||
for (int i=0; i<fPlotData.size(); i++) {
|
||||
fout << fPlotData[i].xLabel.Strip(TString::kLeading).Data() << ", ";
|
||||
TString xl = fPlotData[i].xLabel.Strip(TString::kLeading);
|
||||
fout << xl.Data() << ", " << xl.Data() << "ErrPos, " << xl.Data() << "ErrNeg, ";
|
||||
for (int j=0; j<fPlotData[i].yLabel.size(); j++) {
|
||||
if ((i == fPlotData.size()-1) && (j == fPlotData[i].yLabel.size()-1))
|
||||
fout << fPlotData[i].yLabel[j].Strip(TString::kLeading).Data() << ", " << fPlotData[i].yLabel[j].Strip(TString::kLeading).Data() << "ErrPos, " << fPlotData[i].yLabel[j].Strip(TString::kLeading).Data() << "ErrNeg";
|
||||
TString yl = fPlotData[i].yLabel[j].Strip(TString::kLeading);
|
||||
if ((i == (int)fPlotData.size()-1) && (j == (int)fPlotData[i].yLabel.size()-1))
|
||||
fout << yl.Data() << ", " << yl.Data() << "ErrPos, " << yl.Data() << "ErrNeg";
|
||||
else
|
||||
fout << fPlotData[i].yLabel[j].Strip(TString::kLeading).Data() << ", " << fPlotData[i].yLabel[j].Strip(TString::kLeading).Data() << "ErrPos, " << fPlotData[i].yLabel[j].Strip(TString::kLeading).Data() << "ErrNeg, ";
|
||||
fout << yl.Data() << ", " << yl.Data() << "ErrPos, " << yl.Data() << "ErrNeg, ";
|
||||
}
|
||||
}
|
||||
fout << std::endl;
|
||||
@@ -679,21 +704,21 @@ void PMuppCanvas::ExportData()
|
||||
// search the longest data set
|
||||
Int_t maxLength=0;
|
||||
for (int i=0; i<fPlotData.size(); i++) {
|
||||
if (maxLength < fPlotData[i].xValue.size())
|
||||
if (maxLength < (Int_t)fPlotData[i].xValue.size())
|
||||
maxLength = fPlotData[i].xValue.size();
|
||||
}
|
||||
// write data
|
||||
for (int i=0; i<maxLength; i++) { // maximal data set length
|
||||
for (int j=0; j<fPlotData.size(); j++) { // number of x-data sets
|
||||
// write x-value
|
||||
if (i < fPlotData[j].xValue.size()) // make sure that the entry exists
|
||||
fout << fPlotData[j].xValue[i] << ", ";
|
||||
// write x-value and x-errors
|
||||
if (i < (int)fPlotData[j].xValue.size())
|
||||
fout << fPlotData[j].xValue[i] << ", " << fPlotData[j].xErrPos[i] << ", " << fPlotData[j].xErrNeg[i] << ", ";
|
||||
else
|
||||
fout << " , ";
|
||||
fout << " , , , ";
|
||||
// write y-value and y-value error
|
||||
for (int k=0; k<fPlotData[j].yValue.size(); k++) { // number of y-data sets
|
||||
if ((j == fPlotData.size()-1) && (k == fPlotData[j].yValue.size()-1))
|
||||
if (i < fPlotData[j].yValue[k].size())
|
||||
if ((j == (int)fPlotData.size()-1) && (k == (int)fPlotData[j].yValue.size()-1))
|
||||
if (i < (int)fPlotData[j].yValue[k].size())
|
||||
fout << fPlotData[j].yValue[k][i].y << ", " << fPlotData[j].yValue[k][i].eYpos << ", " << fPlotData[j].yValue[k][i].eYneg;
|
||||
else
|
||||
fout << ", , , ";
|
||||
|
||||
@@ -93,6 +93,8 @@ struct PDataCollection {
|
||||
TString xLabel; ///< label for the x-axis
|
||||
PStringVector yLabel; ///< labels for each y-dataset
|
||||
PDoubleVector xValue; ///< x-values (common to all y-datasets)
|
||||
PDoubleVector xErrPos; ///< positive x-errors (upward)
|
||||
PDoubleVector xErrNeg; ///< negative x-errors (downward)
|
||||
std::vector< std::vector<PDataPoint> > yValue; ///< y-values with errors for each dataset
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user