Skip to content

Commit 6586367

Browse files
authored
[QC-347] Error bars for graphs drawn by TrendingTask (#453)
* [QC-347] Error bars for graphs drawn by TrendingTask * more comments, fixing the existing ones * add documentation
1 parent b9bc09a commit 6586367

4 files changed

Lines changed: 35 additions & 8 deletions

File tree

Framework/include/QualityControl/TrendingTaskConfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct TrendingTaskConfig : PostProcessingConfig {
3636
std::string varexp;
3737
std::string selection;
3838
std::string option;
39+
std::string graphErrors;
3940
};
4041

4142
struct DataSource {

Framework/src/TrendingTask.cxx

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <TH1.h>
2424
#include <TCanvas.h>
2525
#include <TPaveText.h>
26+
#include "TGraphErrors.h"
2627

2728
using namespace o2::quality_control;
2829
using namespace o2::quality_control::core;
@@ -113,15 +114,34 @@ void TrendingTask::storePlots()
113114
// why generate and store plots in the same function? because it is easier to handle the lifetime of pointers to the ROOT objects
114115
for (const auto& plot : mConfig.plots) {
115116

117+
// we determine the order of the plot, i.e. if it is a histogram (1), graph (2), or any higher dimension.
118+
const size_t plotOrder = std::count(plot.varexp.begin(), plot.varexp.end(), ':') + 1;
119+
// we have to delete the graph errors after the plot is saved, unfortunately the canvas does not take its ownership
120+
TGraphErrors* graphErrors = nullptr;
121+
116122
TCanvas* c = new TCanvas();
117123

118124
mTrend->Draw(plot.varexp.c_str(), plot.selection.c_str(), plot.option.c_str());
119125

120126
c->SetName(plot.name.c_str());
121127
c->SetTitle(plot.title.c_str());
122128

129+
// For graphs we allow to draw errors if they are specified.
130+
if (!plot.graphErrors.empty()) {
131+
if (plotOrder != 2) {
132+
ILOG(Error) << "Non empty graphErrors seen for the plot '" << plot.name << "', which is not a graph, ignoring." << ENDM;
133+
} else {
134+
// We generate some 4-D points, where 2 dimensions represent graph points and 2 others are the error bars
135+
std::string varexpWithErrors(plot.varexp + ":" + plot.graphErrors);
136+
mTrend->Draw(varexpWithErrors.c_str(), plot.selection.c_str(), "goff");
137+
graphErrors = new TGraphErrors(mTrend->GetSelectedRows(), mTrend->GetVal(1), mTrend->GetVal(0), mTrend->GetVal(2), mTrend->GetVal(3));
138+
// We draw on the same plot as the main graph, but only error bars
139+
graphErrors->Draw("SAME E");
140+
}
141+
}
142+
123143
// Postprocessing the plot - adding specified titles, configuring time-based plots, flushing buffers.
124-
// Notice that axes and title is drawn using a histogram, even in the case of graphs.
144+
// Notice that axes and title are drawn using a histogram, even in the case of graphs.
125145
if (auto histo = dynamic_cast<TH1*>(c->GetPrimitive("htemp"))) {
126146
// The title of histogram is printed, not the title of canvas => we set it as well.
127147
histo->SetTitle(plot.title.c_str());
@@ -134,7 +154,7 @@ void TrendingTask::storePlots()
134154
// It will have an effect only after invoking Draw again.
135155
title->Draw();
136156
} else {
137-
ILOG(Info) << "Could not get the title TPaveText of the plot '" << plot.name << "'." << ENDM;
157+
ILOG(Error) << "Could not get the title TPaveText of the plot '" << plot.name << "'." << ENDM;
138158
}
139159

140160
// We have to explicitly configure showing time on x axis.
@@ -151,7 +171,7 @@ void TrendingTask::storePlots()
151171
// so we have to do it here.
152172
histo->BufferEmpty();
153173
} else {
154-
ILOG(Info) << "Could not get the htemp histogram of the plot '" << plot.name << "'." << ENDM;
174+
ILOG(Error) << "Could not get the htemp histogram of the plot '" << plot.name << "'." << ENDM;
155175
}
156176

157177
auto mo = std::make_shared<MonitorObject>(c, mConfig.taskName, mConfig.detectorName);
@@ -160,5 +180,7 @@ void TrendingTask::storePlots()
160180

161181
// It should delete everything inside. Confirmed by trying to delete histo after and getting a segfault.
162182
delete c;
183+
// ...but it does not delete graphErrors
184+
delete graphErrors;
163185
}
164186
}

Framework/src/TrendingTaskConfig.cxx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ TrendingTaskConfig::TrendingTaskConfig(std::string name, const boost::property_t
2727
plotConfig.second.get<std::string>("title", ""),
2828
plotConfig.second.get<std::string>("varexp"),
2929
plotConfig.second.get<std::string>("selection", ""),
30-
plotConfig.second.get<std::string>("option", "") });
30+
plotConfig.second.get<std::string>("option", ""),
31+
plotConfig.second.get<std::string>("graphErrors", "") });
3132
}
3233
for (const auto& dataSourceConfig : config.get_child("qc.postprocessing." + name + ".dataSources")) {
3334
if (const auto& sourceNames = dataSourceConfig.second.get_child_optional("names"); sourceNames.has_value()) {
@@ -51,4 +52,4 @@ TrendingTaskConfig::TrendingTaskConfig(std::string name, const boost::property_t
5152
}
5253
}
5354

54-
} // namespace o2::quality_control::postprocessing
55+
} // namespace o2::quality_control::postprocessing

doc/PostProcessing.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,10 @@ Data sources are defined by filling the corresponding structure, as in the examp
192192
}
193193
```
194194

195-
Similarly, plots are defined by adding proper structures to the `"plots"` list, as shown below. The plot will be stored under the `"name"` value and it will have the `"title"` value shown on the top. The `"varexp"`, `"selection"` and `"option"` fields correspond to the arguments of the [`TTree::Draw`](https://root.cern/doc/master/classTTree.html#a73450649dc6e54b5b94516c468523e45) method.
196-
195+
Similarly, plots are defined by adding proper structures to the `"plots"` list, as shown below. The plot will be
196+
stored under the `"name"` value and it will have the `"title"` value shown on the top. The `"varexp"`, `"selection"` and `"option"` fields correspond to the arguments of the [`TTree::Draw`](https://root.cern/doc/master/classTTree.html#a73450649dc6e54b5b94516c468523e45) method.
197+
Optionally, one can use `"graphError"` to add x and y error bars to a graph, as in the first plot example.
198+
The `"name"` and `"varexp"` are the only compulsory arguments, others can be omitted to reduce configuration files size.
197199
``` json
198200
{
199201
...
@@ -203,7 +205,8 @@ Similarly, plots are defined by adding proper structures to the `"plots"` list,
203205
"title": "Mean trend of the example histogram",
204206
"varexp": "example.mean:time",
205207
"selection": "",
206-
"option": "*L"
208+
"option": "*L",
209+
"graphErrors": "5:example.stddev"
207210
},
208211
{
209212
"name": "histogram_of_means",

0 commit comments

Comments
 (0)