Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RDFDisplay.cxx
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. *
3 * All rights reserved. *
4 * *
5 * For the licensing terms see $ROOTSYS/LICENSE. *
6 * For the list of contributors see $ROOTSYS/README/CREDITS. *
7 *************************************************************************/
8
10
11#include <iomanip>
12#include <iostream>
13#include <limits>
14#include <sstream>
15#include <string>
16#include <vector>
17
18namespace ROOT {
19namespace Internal {
20namespace RDF {
21
22
23/**
24 * \class ROOT::Internal::RDF::RDisplayElement
25 * \ingroup dataframe
26 * Helper class to let Display print compact tabular representations of the events
27 *
28 * This class is internal and not meant to be explicitly instantiated by the user.
29 * It is needed during printing to understand if a value can be
30 * skipped or must be printed. Each RDisplayElement represents a cell.
31 */
32
33////////////////////////////////////////////////////////////////////////////
34/// Constructor
35/// \param[in] representation The representation string
37{
38 SetPrint();
39}
40
41////////////////////////////////////////////////////////////////////////////
42/// Constructor assuming an empty representation to be printed
47
48////////////////////////////////////////////////////////////////////////////
49/// Flag this cell as to be printed
54
55////////////////////////////////////////////////////////////////////////////
56/// Flag this cell as to be skipped
61
62////////////////////////////////////////////////////////////////////////////
63/// Flag this cell to be replaced by "..."
68
69////////////////////////////////////////////////////////////////////////////
70/// Return if the cell has to be printed
75
76////////////////////////////////////////////////////////////////////////////
77/// Return if the cell has to be skipped
82
83////////////////////////////////////////////////////////////////////////////
84/// Return if the cell has to be replaced by "..."
89
90const std::string &RDisplayElement::GetRepresentation() const
91{
92 return fRepresentation;
93}
94
96{
97 return fRepresentation.empty();
98}
99
100} // namespace RDF
101} // namespace Internal
102
103namespace RDF {
104
105void RDisplay::EnsureCurrentColumnWidth(size_t w)
106{
107 // If the current element is wider than the widest element found, update the width
108 if (fWidths[fCurrentColumn] < w) {
109 if (w > std::numeric_limits<unsigned short>::max()) {
110 w = std::numeric_limits<unsigned short>::max();
111 }
112 fWidths[fCurrentColumn] = (unsigned short) w;
113 }
114}
115
116void RDisplay::AddToRow(const std::string &stringEle)
117{
118 // If the current element is wider than the widest element found, update the width
120
121 // Save the element...
123
124 // ...and move to the next
125 MovePosition();
126}
127
128void RDisplay::AddCollectionToRow(const std::vector<std::string> &collection)
129{
130 auto row = fCurrentRow;
131 // For each element of the collection, save it. The first element will be in the current row, next ones will have
132 // their own row.
133 size_t collectionSize = collection.size();
134 for (size_t index = 0; index < collectionSize; ++index) {
135 auto stringEle = collection[index];
137
138 // Update the width if this element is the biggest found
140
142 // Do nothing, by default DisplayElement is printed
143 } else if (index == fNMaxCollectionElements) {
144 element.SetDots();
145 // Be sure the "..." fit
147 } else {
148 // In the Print(), after the dots, all element will just be ignored.
149 element.SetIgnore();
150 }
151
152 // Save the element
154 ++row;
155
156 if (index != collectionSize - 1 && fTable.size() <= row) {
157 // This is not the last element, prepare the next row for the next element, if not already done by another
158 // collection
159 fTable.push_back(std::vector<DElement_t>(fNColumns));
160 }
161 }
162 fNextRow = (fNextRow > row) ? fNextRow : row;
163 MovePosition();
164}
165
166void RDisplay::MovePosition()
167{
168 // Go to the next element. If it is outside the row, just go the first element of the next row.
170 if (fCurrentColumn == fNColumns) {
172 fCurrentColumn = 0;
173 fNextRow = fCurrentRow + 1;
174 fTable.push_back(std::vector<DElement_t>(fNColumns));
175 }
176}
177
178RDisplay::RDisplay(const VecStr_t &columnNames, const VecStr_t &types, size_t nMaxCollectionElements)
179 : fTypes(types), fWidths(columnNames.size(), 0), fRepresentations(columnNames.size()),
180 fCollectionsRepresentations(columnNames.size()), fNColumns(columnNames.size()),
181 fNMaxCollectionElements(nMaxCollectionElements)
182{
183 // Add the first row with the names of the columns
184 fTable.push_back(std::vector<DElement_t>(columnNames.size()));
185 AddToRow("Row"); // Change the name of the first column from rdfentry_ to Row
186 for (auto name = columnNames.begin() + 1; name != columnNames.end(); ++name) {
187 AddToRow(*name);
188 }
189}
190
191size_t RDisplay::GetNColumnsToShorten() const
192{
193 size_t totalWidth = 0;
194
195 auto size = fWidths.size();
196 for (size_t i = 0; i < size; ++i) {
197 // The total width of the printed table also includes two spaces and a |,
198 // which are 3 extra characters per entry on the table.
199 totalWidth += fWidths[i] + 3;
200 if (totalWidth > fgMaxWidth) {
201 return size - i;
202 }
203 }
204 return 0;
205}
206
207std::string RDisplay::DashesBetweenLines(size_t lastColToPrint, bool allColumnsFit) const
208{
209 std::string DashesStr = "+";
210 for (size_t i = 0; i < lastColToPrint; ++i){
211 DashesStr += std::string(fWidths[i] + 2, '-'); // Need to add 2, because of the spaces, when printing
212 DashesStr += "+";
213 }
214 if (!allColumnsFit){ // The Print method has ... in case of long columns, which need to be surrounded by dashes
215 DashesStr += "-----+";
216 }
217 DashesStr += "\n";
218 return DashesStr;
219}
220
221void RDisplay::Print(const RPrintOptions &options) const
222{
223 auto ret = AsStringInternal(true, options);
224 std::cout << ret;
225}
226
227std::string RDisplay::AsString(const RPrintOptions &options) const
228{
229 return AsStringInternal(false, options);
230}
231
232std::string RDisplay::AsStringInternal(bool considerDots, const RPrintOptions &options) const
233{
234 switch (options.fFormat) {
236 case EPrintFormat::kHtml: return AsStringHtml();
237 default: R__ASSERT(false);
238 }
239 return {};
240}
241
242std::string RDisplay::AsStringHtml() const
243{
244 std::stringstream ss;
245
246 ss << "<table style=\"border: 1px solid black; border-collapse: collapse;\">\n";
247 auto nrRows = fTable.size();
248 std::string elemType = "th";
249 int bgColorIdx = 0;
250 for (size_t rowIndex = 0; rowIndex < nrRows; ++rowIndex) {
251 const auto &row = fTable[rowIndex];
252
253 bool isRowSeparator =
254 std::any_of(row[0].GetRepresentation().begin(), row[0].GetRepresentation().end(), ::isdigit);
255
256 // Alternate rows' background color
257 static const char *bgColors[2] = {"#fff", "#eee"};
259 std::string bgColor = bgColors[bgColorIdx];
260
261 if (isRowSeparator) {
262 ss << " <tr style=\"border-top: 1px dotted; background: " + bgColor + "\">\n";
263 } else {
264 ss << " <tr style=\"background: " + bgColor + "\">\n";
265 }
266
267 for (const auto &element : row) {
268 ss << " <" + elemType + " style=\"padding: 1px 4px; border-right: 1px solid\">"
269 << element.GetRepresentation() << "</" + elemType + ">\n";
270 }
271 ss << " </tr>\n";
272
273 elemType = "td";
274 }
275 ss << "</table>";
276
277 return ss.str();
278}
279
280std::string RDisplay::AsStringMarkdown(bool considerDots) const
281{
282 std::stringstream ss;
283
284 size_t columnsToPrint = fNColumns;
285 const size_t columnsToShorten = GetNColumnsToShorten();
286 bool allColumnsFit = true;
287 if (fNColumns > 2u && columnsToShorten > 0u){ // Checking 2u, since first column is keeping track of rows
288 if (fNColumns > columnsToShorten + 1) { // Provided that the first column is "Row",
289 // columnsToShorten is guaranteed to be smaller than fNColumns
290 // Need to check if actual first column is being shortened
292 } else { // Table has many columns and the first column is very wide;
293 // Thus, the first column is only the Row column and the actual first column is printed
294 columnsToPrint = 2;
295 }
296 if (considerDots)
297 Info("Print", "Only showing %zu columns out of %zu\n", columnsToPrint, fNColumns);
298
299 allColumnsFit = false;
300 }
301
303 Info("Print", "No collections shown since fNMaxCollectionElements is 0\n");
304
305 auto nrRows = fTable.size();
306 ss << DashesBetweenLines(columnsToPrint, allColumnsFit); // Print dashes in the top of the table
307 for (size_t rowIndex = 0; rowIndex < nrRows; ++rowIndex) {
308 const auto &row = fTable[rowIndex];
309
310 std::stringstream stringRow;
311 bool isRowEmpty = true; // It may happen during compacting that some rows are empty, this happens for example if
312 // collections have different size. Thanks to this flag, these rows are just ignored.
313 if (std::any_of(row[0].GetRepresentation().begin(), row[0].GetRepresentation().end(), ::isdigit)) {
314 // Check if the first column (Row) contains a digit to use it as indication for new row/entry
316 }
317 stringRow << "| ";
318 for (size_t columnIndex = 0; columnIndex < columnsToPrint; ++columnIndex) {
319 const auto &element = row[columnIndex];
320 std::string printedElement = "";
321
322 // TODO: add a function option to avoid this behavior
323 if (considerDots && element.IsDot()) {
324 printedElement = "...";
325 } else if (!considerDots || element.IsPrint()) {
326 printedElement = element.GetRepresentation();
327 } else { // IsIgnore
328 // Do nothing, printedElement remains ""
329 }
330 if (!printedElement.empty()) {
331 // Found at least one element, so the row is not empty.
332 isRowEmpty = false;
333 }
334
335 stringRow << std::left << std::setw(fWidths[columnIndex]) << std::setfill(fgSeparator) << printedElement
336 << " | ";
337 }
338 if (!isRowEmpty) {
339 if (!allColumnsFit) { // If there are column(s), that do not fit, a single column of dots is displayed
340 // in the right end of each (non-empty) row.
341 stringRow << "... | ";
342 }
343 ss << stringRow.str() << "\n";
344 }
345 }
346 ss << DashesBetweenLines(columnsToPrint, allColumnsFit); // Print dashes in the bottom of the table
347
348 return ss.str();
349}
350
351} // namespace RDF
352} // namespace ROOT
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
char name[80]
Definition TGX11.cxx:110
bool IsIgnore() const
Return if the cell has to be skipped.
bool IsDot() const
Return if the cell has to be replaced by "...".
const std::string & GetRepresentation() const
bool IsPrint() const
Return if the cell has to be printed.
void SetDots()
Flag this cell to be replaced by "...".
void SetPrint()
Flag this cell as to be printed.
void SetIgnore()
Flag this cell as to be skipped.
RDisplayElement()
Constructor assuming an empty representation to be printed.
size_t fCurrentColumn
Column that is being filled.
Definition RDisplay.hxx:100
ROOT::Internal::RDF::RDisplayElement DElement_t
Definition RDisplay.hxx:81
size_t fNMaxCollectionElements
Definition RDisplay.hxx:102
std::vector< std::vector< DElement_t > > fTable
String representation of the data to be printed.
Definition RDisplay.hxx:88
std::string AsStringHtml() const
void AddToRow(const std::string &stringEle)
Adds a single element to the next slot in the table.
size_t fCurrentRow
Row that is being filled.
Definition RDisplay.hxx:98
std::string AsStringMarkdown(bool considerDots) const
void MovePosition()
Moves to the next cell.
std::vector< unsigned short > fWidths
Tracks the maximum width of each column, based on the largest element.
Definition RDisplay.hxx:89
static constexpr unsigned fgMaxWidth
Maximum width of the table that Print() displays.
Definition RDisplay.hxx:83
void EnsureCurrentColumnWidth(size_t w)
size_t fNextRow
Next row to be filled.
Definition RDisplay.hxx:99
std::string DashesBetweenLines(size_t lastColToPrint, bool allColumnsFit) const
Generate dashes between entries in Print() and AsString() Methods.
std::string AsStringInternal(bool considerDots, const RPrintOptions &options={EPrintFormat::kMarkdown}) const
std::vector< std::string > VecStr_t
Definition RDisplay.hxx:80
size_t GetNColumnsToShorten() const
Get the number of columns that do NOT fit in the characters limit.
static constexpr char fgSeparator
Spacing used to align the table entries.
Definition RDisplay.hxx:82
size_t fNColumns
Number of columns to be printed.
Definition RDisplay.hxx:96
const_iterator begin() const
const_iterator end() const
std::ostream & Info()
Definition hadd.cxx:163
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...