Logo ROOT  
Reference Guide
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
36RDisplayElement::RDisplayElement(const std::string &representation) : fRepresentation(representation)
37{
38 SetPrint();
39}
40
41////////////////////////////////////////////////////////////////////////////
42/// Constructor assuming an empty representation to be printed
44{
45 SetPrint();
46}
47
48////////////////////////////////////////////////////////////////////////////
49/// Flag this cell as to be printed
51{
53}
54
55////////////////////////////////////////////////////////////////////////////
56/// Flag this cell as to be skipped
58{
60}
61
62////////////////////////////////////////////////////////////////////////////
63/// Flag this cell to be replaced by "..."
65{
67}
68
69////////////////////////////////////////////////////////////////////////////
70/// Return if the cell has to be printed
72{
74}
75
76////////////////////////////////////////////////////////////////////////////
77/// Return if the cell has to be skipped
79{
81}
82
83////////////////////////////////////////////////////////////////////////////
84/// Return if the cell has to be replaced by "..."
86{
88}
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
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
119 EnsureCurrentColumnWidth(stringEle.length());
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];
136 auto element = DElement_t(stringEle);
137
138 // Update the width if this element is the biggest found
139 EnsureCurrentColumnWidth(stringEle.length());
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
153 fTable[row][fCurrentColumn] = 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
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
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
222{
223 size_t columnsToPrint = fNColumns;
224 const size_t columnsToShorten = GetNColumnsToShorten();
225 bool allColumnsFit = true;
226 if (fNColumns > 2u && columnsToShorten > 0u){ // Checking 2u, since first column is keeping track of rows
227 if (fNColumns > columnsToShorten + 1) { // Provided that the first column is "Row",
228 // columnsToShorten is guaranteed to be smaller than fNColumns
229 // Need to check if actual first column is being shortened
230 columnsToPrint = fNColumns - columnsToShorten;
231 } else { // Table has many columns and the first column is very wide;
232 // Thus, the first column is only the Row column and the actual first column is printed
233 columnsToPrint = 2;
234 }
235 Info("Print", "Only showing %lu columns out of %lu\n", columnsToPrint, fNColumns);
236 allColumnsFit = false;
237 }
238
240 Info("Print", "No collections shown since fNMaxCollectionElements is %lu\n", fNMaxCollectionElements);
241
242 auto nrRows = fTable.size();
243 std::cout << DashesBetweenLines(columnsToPrint, allColumnsFit); // Print dashes in the top of the table
244 for (size_t rowIndex = 0; rowIndex < nrRows; ++rowIndex) {
245 auto &row = fTable[rowIndex];
246
247 std::stringstream stringRow;
248 bool isRowEmpty = true; // It may happen during compacting that some rows are empty, this happens for example if
249 // collections have different size. Thanks to this flag, these rows are just ignored.
250 if (std::any_of(row[0].GetRepresentation().begin(), row[0].GetRepresentation().end(), ::isdigit)){
251 // Check if the first column (Row) contains a digit to use it as indication for new row/entry
252 std::cout << DashesBetweenLines(columnsToPrint, allColumnsFit);
253 }
254 stringRow << "| ";
255 for (size_t columnIndex = 0; columnIndex < columnsToPrint; ++columnIndex) {
256 const auto &element = row[columnIndex];
257 std::string printedElement = "";
258
259 if (element.IsDot()) {
260 printedElement = "...";
261 } else if (element.IsPrint()) {
262 printedElement = element.GetRepresentation();
263 } else { // IsIgnore
264 // Do nothing, printedElement remains ""
265 }
266 if (!printedElement.empty()) {
267 // Found at least one element, so the row is not empty.
268 isRowEmpty = false;
269 }
270
271 stringRow << std::left << std::setw(fWidths[columnIndex]) << std::setfill(fgSeparator) << printedElement
272 << " | ";
273 }
274 if (!isRowEmpty) {
275 if (!allColumnsFit){ // If there are column(s), that do not fit, a single column of dots is displayed
276 // in the right end of each (non-empty) row.
277 stringRow << "... | ";
278 }
279 std::cout << stringRow.str() << std::endl;
280 }
281 }
282 std::cout << DashesBetweenLines(columnsToPrint, allColumnsFit); // Print dashes in the bottom of the table
283}
284
285std::string RDisplay::AsString() const
286{
287 // This method works as Print() but without any check on collection. It just returns a string with the whole
288 // representation
289 std::stringstream stringRepresentation;
290 auto size = fWidths.size(); // To be used for the number of columns passed to the DashesBetweenLines
291 stringRepresentation << DashesBetweenLines(size, true); // 'true' since no columns are skipped
292 for (auto row : fTable) {
293 if (std::any_of(row[0].GetRepresentation().begin(), row[0].GetRepresentation().end(), ::isdigit)){
294 stringRepresentation << DashesBetweenLines(size, true);
295 }
296 stringRepresentation << "| ";
297 for (size_t i = 0; i < row.size(); ++i) {
298 stringRepresentation << std::left << std::setw(fWidths[i]) << std::setfill(fgSeparator)
299 << row[i].GetRepresentation() << " | ";
300 }
301 stringRepresentation << "\n";
302 }
303 stringRepresentation << DashesBetweenLines(size, true);
304 return stringRepresentation.str();
305}
306
307} // namespace RDF
308} // namespace ROOT
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition: TError.cxx:221
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.
Definition: RDFDisplay.cxx:78
bool IsDot() const
Return if the cell has to be replaced by "...".
Definition: RDFDisplay.cxx:85
const std::string & GetRepresentation() const
Definition: RDFDisplay.cxx:90
bool IsPrint() const
Return if the cell has to be printed.
Definition: RDFDisplay.cxx:71
void SetDots()
Flag this cell to be replaced by "...".
Definition: RDFDisplay.cxx:64
void SetPrint()
Flag this cell as to be printed.
Definition: RDFDisplay.cxx:50
void SetIgnore()
Flag this cell as to be skipped.
Definition: RDFDisplay.cxx:57
RDisplayElement()
Constructor assuming an empty representation to be printed.
Definition: RDFDisplay.cxx:43
void AddCollectionToRow(const VecStr_t &collection)
Adds a collection to the table.
Definition: RDFDisplay.cxx:128
size_t fCurrentColumn
Column that is being filled.
Definition: RDisplay.hxx:88
ROOT::Internal::RDF::RDisplayElement DElement_t
Definition: RDisplay.hxx:69
RDisplay(const VecStr_t &columnNames, const VecStr_t &types, size_t nMaxCollectionElements)
Creates an RDisplay to print the event values.
Definition: RDFDisplay.cxx:178
size_t fNMaxCollectionElements
Definition: RDisplay.hxx:90
std::vector< std::vector< DElement_t > > fTable
String representation of the data to be printed.
Definition: RDisplay.hxx:76
std::string AsString() const
Returns the representation as a string.
Definition: RDFDisplay.cxx:285
void AddToRow(const std::string &stringEle)
Adds a single element to the next slot in the table.
Definition: RDFDisplay.cxx:116
size_t fCurrentRow
Row that is being filled.
Definition: RDisplay.hxx:86
void MovePosition()
Moves to the next cell.
Definition: RDFDisplay.cxx:166
std::vector< unsigned short > fWidths
Tracks the maximum width of each column, based on the largest element.
Definition: RDisplay.hxx:77
static constexpr unsigned fgMaxWidth
Maximum width of the table that Print() displays.
Definition: RDisplay.hxx:71
void EnsureCurrentColumnWidth(size_t w)
Definition: RDFDisplay.cxx:105
size_t fNextRow
Next row to be filled.
Definition: RDisplay.hxx:87
std::string DashesBetweenLines(size_t lastColToPrint, bool allColumnsFit) const
Generate dashes between entries in Print() and AsString() Methods.
Definition: RDFDisplay.cxx:207
std::vector< std::string > VecStr_t
Definition: RDisplay.hxx:68
void Print() const
Prints the representation to the standard output.
Definition: RDFDisplay.cxx:221
size_t GetNColumnsToShorten() const
Get the number of columns that do NOT fit in the characters limit.
Definition: RDFDisplay.cxx:191
static constexpr char fgSeparator
Spacing used to align the table entries.
Definition: RDisplay.hxx:70
size_t fNColumns
Number of columns to be printed.
Definition: RDisplay.hxx:84
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.