diff --git a/hist/hist/src/TGraph.cxx b/hist/hist/src/TGraph.cxx index 9d8ee9ff1fbe9..2d5b362d58d88 100644 --- a/hist/hist/src/TGraph.cxx +++ b/hist/hist/src/TGraph.cxx @@ -358,12 +358,13 @@ TGraph::TGraph(const TH1 *h) Error("TGraph", "Histogram must be 1-D; h %s is %d-D", h->GetName(), h->GetDimension()); fNpoints = 0; } else { - fNpoints = ((TH1*)h)->GetXaxis()->GetNbins(); + fNpoints = h->GetXaxis()->GetNbins(); } - if (!CtorAllocate()) return; + if (!CtorAllocate()) + return; - TAxis *xaxis = ((TH1*)h)->GetXaxis(); + auto xaxis = h->GetXaxis(); for (Int_t i = 0; i < fNpoints; i++) { fX[i] = xaxis->GetBinCenter(i + 1); fY[i] = h->GetBinContent(i + 1); @@ -440,6 +441,7 @@ TGraph::TGraph(const TF1 *f, Option_t *option) /// The string format is by default `"%lg %lg"`. /// This is a standard c formatting for `scanf()`. /// For example, set format to `"%lg,%lg"` for a comma-separated file. +/// If format string is empty, suitable value will be provided based on file extension /// /// If columns of numbers should be skipped, a `"%*lg"` or `"%*s"` for each column /// can be added, e.g. `"%lg %*lg %lg"` would read x-values from the first and @@ -473,11 +475,21 @@ TGraph::TGraph(const char *filename, const char *format, Option_t *option) std::string line; Int_t np = 0; - // No delimiters specified (standard constructor). - if (strcmp(option, "") == 0) { + TString format_ = format; + + if (!option || !*option) { // No delimiters specified (standard constructor). + // is empty format string specified - try to guess format from the file extension + if (format_.IsNull()) { + if (fname.EndsWith(".txt", TString::kIgnoreCase)) + format_ = "%lg %lg"; + else if (fname.EndsWith(".tsv", TString::kIgnoreCase)) + format_ = "%lg\t%lg"; + else + format_ = "%lg,%lg"; + } while (std::getline(infile, line, '\n')) { - if (2 != sscanf(line.c_str(), format, &x, &y)) { + if (2 != sscanf(line.c_str(), format_.Data(), &x, &y)) { continue; //skip empty and ill-formed lines } SetPoint(np, x, y); @@ -489,7 +501,6 @@ TGraph::TGraph(const char *filename, const char *format, Option_t *option) } else { // Checking format and creating its boolean counterpart - TString format_ = TString(format) ; format_.ReplaceAll(" ", "") ; format_.ReplaceAll("\t", "") ; format_.ReplaceAll("lg", "") ; diff --git a/hist/hist/src/TGraphAsymmErrors.cxx b/hist/hist/src/TGraphAsymmErrors.cxx index f7563d7984689..da28524750736 100644 --- a/hist/hist/src/TGraphAsymmErrors.cxx +++ b/hist/hist/src/TGraphAsymmErrors.cxx @@ -289,6 +289,8 @@ TGraphAsymmErrors::TGraphAsymmErrors(const TH1* pass, const TH1* total, Option_t /// - format = `"%lg %lg %lg %lg"` read only 4 first columns into X, Y, EYL, EYH /// - format = `"%lg %lg %lg %lg %lg %lg"` read only 6 first columns into X, Y, EXL, EXH, EYL, EYH /// +/// If format string is empty, suitable value will be provided based on file extension +/// /// For files separated by a specific delimiter different from ' ' and `\\t` (e.g. `;` in csv files) /// you can avoid using `%*s` to bypass this delimiter by explicitly specify the `option` argument, /// e.g. `option=" \\t,;"` for columns of figures separated by any of these characters (`' ', '\\t', ',', ';'`) @@ -314,18 +316,30 @@ TGraphAsymmErrors::TGraphAsymmErrors(const char *filename, const char *format, O std::string line; Int_t np = 0; - if (strcmp(option, "") == 0) { // No delimiters specified (standard constructor). + TString format_ = format; + + if (!option || !*option) { // No delimiters specified (standard constructor). + + Int_t ncol = 6; + if (format_.IsNull()) { + if (fname.EndsWith(".txt", TString::kIgnoreCase)) + format_ = "%lg %lg %lg %lg %lg %lg"; + else if (fname.EndsWith(".tsv", TString::kIgnoreCase)) + format_ = "%lg\t%lg\t%lg\t%lg\t%lg\t%lg"; + else + format_ = "%lg,%lg,%lg,%lg,%lg,%lg"; + } else + ncol = TGraphErrors::CalculateScanfFields(format); //count number of columns in format - Int_t ncol = TGraphErrors::CalculateScanfFields(format); //count number of columns in format Int_t res; while (std::getline(infile, line, '\n')) { exl = exh = eyl = eyh = 0.; if (ncol < 3) { - res = sscanf(line.c_str(), format, &x, &y); + res = sscanf(line.c_str(), format_.Data(), &x, &y); } else if (ncol < 5) { - res = sscanf(line.c_str(), format, &x, &y, &eyl, &eyh); + res = sscanf(line.c_str(), format_.Data(), &x, &y, &eyl, &eyh); } else { - res = sscanf(line.c_str(), format, &x, &y, &exl, &exh, &eyl, &eyh); + res = sscanf(line.c_str(), format_.Data(), &x, &y, &exl, &exh, &eyl, &eyh); } if (res < 2) { continue; //skip empty and ill-formed lines @@ -339,7 +353,6 @@ TGraphAsymmErrors::TGraphAsymmErrors(const char *filename, const char *format, O } else { // A delimiter has been specified in "option" // Checking format and creating its boolean equivalent - TString format_ = TString(format) ; format_.ReplaceAll(" ", "") ; format_.ReplaceAll("\t", "") ; format_.ReplaceAll("lg", "") ; diff --git a/hist/hist/src/TGraphErrors.cxx b/hist/hist/src/TGraphErrors.cxx index c8b257b360b6f..f9f3047a6489c 100644 --- a/hist/hist/src/TGraphErrors.cxx +++ b/hist/hist/src/TGraphErrors.cxx @@ -223,6 +223,8 @@ TGraphErrors::TGraphErrors(const TH1 *h) /// - format = `"%lg %lg %lg"` read only 3 first columns into X,Y and EY /// - format = `"%lg %lg %lg %lg"` read only 4 first columns into X,Y,EX,EY. /// +/// If format string is empty, suitable value will be provided based on file extension +/// /// For files separated by a specific delimiter different from ' ' and `\\t` (e.g. `;` in csv files) /// you can avoid using `%*s` to bypass this delimiter by explicitly specify the `option` argument, /// e.g. `option=" \\t,;"` for columns of figures separated by any of these characters (`' ', '\\t', ',', ';'`) @@ -248,18 +250,30 @@ TGraphErrors::TGraphErrors(const char *filename, const char *format, Option_t *o std::string line; Int_t np = 0; - if (strcmp(option, "") == 0) { // No delimiters specified (standard constructor). + TString format_ = format; + + if (!option || !*option) { // No delimiters specified (standard constructor). + + Int_t ncol = 4; + if (format_.IsNull()) { + if (fname.EndsWith(".txt", TString::kIgnoreCase)) + format_ = "%lg %lg %lg %lg"; + else if (fname.EndsWith(".tsv", TString::kIgnoreCase)) + format_ = "%lg\t%lg\t%lg\t%lg"; + else + format_ = "%lg,%lg,%lg,%lg"; + } else + ncol = CalculateScanfFields(format); //count number of columns in format - Int_t ncol = CalculateScanfFields(format); //count number of columns in format Int_t res; while (std::getline(infile, line, '\n')) { ex = ey = 0; if (ncol < 3) { - res = sscanf(line.c_str(), format, &x, &y); + res = sscanf(line.c_str(), format_.Data(), &x, &y); } else if (ncol < 4) { - res = sscanf(line.c_str(), format, &x, &y, &ey); + res = sscanf(line.c_str(), format_.Data(), &x, &y, &ey); } else { - res = sscanf(line.c_str(), format, &x, &y, &ex, &ey); + res = sscanf(line.c_str(), format_.Data(), &x, &y, &ex, &ey); } if (res < 2) { continue; //skip empty and ill-formed lines @@ -273,7 +287,6 @@ TGraphErrors::TGraphErrors(const char *filename, const char *format, Option_t *o } else { // A delimiter has been specified in "option" // Checking format and creating its boolean equivalent - TString format_ = TString(format) ; format_.ReplaceAll(" ", "") ; format_.ReplaceAll("\t", "") ; format_.ReplaceAll("lg", "") ; diff --git a/hist/hist/test/test_TGraph_SaveAs.cxx b/hist/hist/test/test_TGraph_SaveAs.cxx index 62386bb0c664e..8b56208ae8358 100644 --- a/hist/hist/test/test_TGraph_SaveAs.cxx +++ b/hist/hist/test/test_TGraph_SaveAs.cxx @@ -26,7 +26,7 @@ TEST(TGraphsa, SaveGraphAsCSV) gr.SaveAs("graph.csv"); - auto gr1 = new TGraph("graph.csv", "%lg,%lg"); + auto gr1 = new TGraph("graph.csv", ""); EXPECT_EQ(gr1->GetN(), NP); for (int n = 0; n < NP; ++n) { @@ -42,7 +42,7 @@ TEST(TGraphsa, SaveGraphAsTSV) gr.SaveAs("graph.tsv"); - auto gr1 = new TGraph("graph.tsv", "%lg\t%lg"); + auto gr1 = new TGraph("graph.tsv", ""); EXPECT_EQ(gr1->GetN(), NP); for (int n = 0; n < NP; ++n) { @@ -57,7 +57,7 @@ TEST(TGraphsa, SaveGraphAsTXT) gr.SaveAs("graph.txt"); - auto gr1 = new TGraph("graph.txt", "%lg %lg"); + auto gr1 = new TGraph("graph.txt", ""); EXPECT_EQ(gr1->GetN(), NP); for (int n = 0; n < NP; ++n) { @@ -72,7 +72,7 @@ TEST(TGraphsa, SaveGraphErrorsAsCSV) gr.SaveAs("grapherrors.csv", "asroot"); // << asroot important for order of values - auto gr1 = new TGraphErrors("grapherrors.csv", "%lg,%lg,%lg,%lg"); + auto gr1 = new TGraphErrors("grapherrors.csv", ""); EXPECT_EQ(gr1->GetN(), NP); for (int n = 0; n < NP; ++n) { @@ -90,7 +90,7 @@ TEST(TGraphsa, SaveGraphErrorsAsTSV) gr.SaveAs("grapherrors.tsv", "asroot"); // << asroot important for order of values - auto gr1 = new TGraphErrors("grapherrors.tsv", "%lg\t%lg\t%lg\t%lg"); + auto gr1 = new TGraphErrors("grapherrors.tsv", ""); EXPECT_EQ(gr1->GetN(), NP); for (int n = 0; n < NP; ++n) { @@ -107,7 +107,7 @@ TEST(TGraphsa, SaveGraphErrorsAsTXT) gr.SaveAs("grapherrors.txt", "asroot"); // << asroot important for order of values - auto gr1 = new TGraphErrors("grapherrors.txt", "%lg %lg %lg %lg"); + auto gr1 = new TGraphErrors("grapherrors.txt", ""); EXPECT_EQ(gr1->GetN(), NP); for (int n = 0; n < NP; ++n) { @@ -125,7 +125,7 @@ TEST(TGraphsa, SaveGraphAsymmErrorsAsCSV) gr.SaveAs("graphasymmrrors.csv", "asroot"); // << asroot important for order of values - auto gr1 = new TGraphAsymmErrors("graphasymmrrors.csv", "%lg,%lg,%lg,%lg,%lg,%lg"); + auto gr1 = new TGraphAsymmErrors("graphasymmrrors.csv", ""); EXPECT_EQ(gr1->GetN(), NP); for (int n = 0; n < NP; ++n) { @@ -145,7 +145,7 @@ TEST(TGraphsa, SaveGraphAsymmErrorsAsTSV) gr.SaveAs("graphasymmrrors.tsv", "asroot"); // << asroot important for order of values - auto gr1 = new TGraphAsymmErrors("graphasymmrrors.tsv", "%lg\t%lg\t%lg\t%lg\t%lg\t%lg"); + auto gr1 = new TGraphAsymmErrors("graphasymmrrors.tsv", ""); EXPECT_EQ(gr1->GetN(), NP); for (int n = 0; n < NP; ++n) { @@ -164,7 +164,7 @@ TEST(TGraphsa, SaveGraphAsymmErrorsAsTXT) gr.SaveAs("graphasymmrrors.txt", "asroot"); // << asroot important for order of values - auto gr1 = new TGraphAsymmErrors("graphasymmrrors.txt", "%lg %lg %lg %lg %lg %lg"); + auto gr1 = new TGraphAsymmErrors("graphasymmrrors.txt", ""); EXPECT_EQ(gr1->GetN(), NP); for (int n = 0; n < NP; ++n) { @@ -183,7 +183,7 @@ TEST(TGraphsa, SaveGraphAsymmErrorsAsOnlyErrorsCSV) gr.SaveAs("graphasymmrrors_reduce.csv", "asroot errors"); // << asroot important for order of values - auto gr1 = new TGraphErrors("graphasymmrrors_reduce.csv", "%lg,%lg,%lg,%lg"); + auto gr1 = new TGraphErrors("graphasymmrrors_reduce.csv", ""); EXPECT_EQ(gr1->GetN(), NP); for (int n = 0; n < NP; ++n) {