Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion tree/dataframe/inc/ROOT/RDF/RDisplay.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ private:

size_t fEntries; ///< Number of events to process for each column (i.e. number of rows).

size_t fNMaxCollectionElements = 10; // threshold on number of elements in collections to be Print()

////////////////////////////////////////////////////////////////////////////
/// Appends a cling::printValue call to the stringstream.
/// \tparam T the type of the event to convert
Expand Down Expand Up @@ -234,7 +236,7 @@ public:
/// \param[in] columnNames Columns to print
/// \param[in] types The type of each column
/// \param[in] entries How many events per column (row) must be processed.
RDisplay(const VecStr_t &columnNames, const VecStr_t &types, int entries);
RDisplay(const VecStr_t &columnNames, const VecStr_t &types, int entries, size_t nMaxCollectionElements);

////////////////////////////////////////////////////////////////////////////
/// Prints the representation to the standard output
Expand Down
19 changes: 11 additions & 8 deletions tree/dataframe/inc/ROOT/RDF/RInterface.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -2566,6 +2566,7 @@ public:
/// \tparam ColumnTypes variadic list of branch/column types.
/// \param[in] columnList Names of the columns to be displayed.
/// \param[in] nRows Number of events for each column to be displayed.
/// \param[in] nMaxCollectionElements Number of columns to be later Print().
/// \return the `RDisplay` instance wrapped in a RResultPtr.
///
/// This function returns a RResultPtr<RDisplay>` containing all the entries to be displayed, organized in a tabular
Expand All @@ -2585,26 +2586,27 @@ public:
/// d2->Print();
/// ~~~
template <typename... ColumnTypes>
RResultPtr<RDisplay> Display(const ColumnNames_t &columnList, const int &nRows = 5)
RResultPtr<RDisplay> Display(const ColumnNames_t &columnList, const int &nRows = 5, const size_t &nMaxCollectionElements = 10)
{
CheckIMTDisabled("Display");

auto displayer = std::make_shared<RDFInternal::RDisplay>(columnList, GetColumnTypeNamesList(columnList), nRows);
auto displayer = std::make_shared<RDFInternal::RDisplay>(columnList, GetColumnTypeNamesList(columnList), nRows, nMaxCollectionElements);
return CreateAction<RDFInternal::ActionTags::Display, ColumnTypes...>(columnList, displayer, displayer);
}

////////////////////////////////////////////////////////////////////////////
/// \brief Provides a representation of the columns in the dataset.
/// \param[in] columnList Names of the columns to be displayed.
/// \param[in] nRows Number of events for each column to be displayed.
/// \param[in] nMaxCollectionElements Number of columns to be later Print().
/// \return the `RDisplay` instance wrapped in a RResultPtr.
///
/// This overload automatically infers the column types.
/// See the previous overloads for further details.
RResultPtr<RDisplay> Display(const ColumnNames_t &columnList, const int &nRows = 5)
RResultPtr<RDisplay> Display(const ColumnNames_t &columnList, const int &nRows = 5, const size_t &nMaxCollectionElements = 10)
{
CheckIMTDisabled("Display");
auto displayer = std::make_shared<RDFInternal::RDisplay>(columnList, GetColumnTypeNamesList(columnList), nRows);
auto displayer = std::make_shared<RDFInternal::RDisplay>(columnList, GetColumnTypeNamesList(columnList), nRows, nMaxCollectionElements);
return CreateAction<RDFInternal::ActionTags::Display, RDFDetail::RInferredType>(columnList, displayer, displayer,
columnList.size());
}
Expand All @@ -2613,16 +2615,17 @@ public:
/// \brief Provides a representation of the columns in the dataset.
/// \param[in] columnNameRegexp A regular expression to select the columns.
/// \param[in] nRows Number of events for each column to be displayed.
/// \param[in] nMaxCollectionElements Number of columns to be later Print().
/// \return the `RDisplay` instance wrapped in a RResultPtr.
///
/// The existing columns are matched against the regular expression. If the string provided
/// is empty, all columns are selected.
/// See the previous overloads for further details.
RResultPtr<RDisplay> Display(std::string_view columnNameRegexp = "", const int &nRows = 5)
RResultPtr<RDisplay> Display(std::string_view columnNameRegexp = "", const int &nRows = 5, const size_t &nMaxCollectionElements = 10)
{
const auto columnNames = GetColumnNames();
const auto selectedColumns = RDFInternal::ConvertRegexToColumns(columnNames, columnNameRegexp, "Display");
return Display(selectedColumns, nRows);
return Display(selectedColumns, nRows, nMaxCollectionElements);
}

////////////////////////////////////////////////////////////////////////////
Expand All @@ -2632,10 +2635,10 @@ public:
/// \return the `RDisplay` instance wrapped in a RResultPtr.
///
/// See the previous overloads for further details.
RResultPtr<RDisplay> Display(std::initializer_list<std::string> columnList, const int &nRows = 5)
RResultPtr<RDisplay> Display(std::initializer_list<std::string> columnList, const int &nRows = 5, const size_t &nMaxCollectionElements = 10)
{
ColumnNames_t selectedColumns(columnList);
return Display(selectedColumns, nRows);
return Display(selectedColumns, nRows, nMaxCollectionElements);
}

private:
Expand Down
38 changes: 13 additions & 25 deletions tree/dataframe/src/RDFDisplay.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ void RDisplay::AddToRow(const std::string &stringEle)

void RDisplay::AddCollectionToRow(const std::vector<std::string> &collection)
{


auto row = fCurrentRow;
// For each element of the collection, save it. The first element will be in the current row, next ones will have
// their own row.
Expand All @@ -135,14 +137,14 @@ void RDisplay::AddCollectionToRow(const std::vector<std::string> &collection)
// Update the width if this element is the biggest found
EnsureCurrentColumnWidth(stringEle.length());

if (index == 0 || index == collectionSize - 1) {
if (index < fNMaxCollectionElements) {
// Do nothing, by default DisplayElement is printed
} else if (index == 1) {
} else if (index == fNMaxCollectionElements) {
element.SetDots();
// Be sure the "..." fit
EnsureCurrentColumnWidth(3);
} else {
// In the Print(), after the dots, all element will just be ignored except the last one.
// In the Print(), after the dots, all element will just be ignored.
element.SetIgnore();
}

Expand Down Expand Up @@ -172,11 +174,10 @@ void RDisplay::MovePosition()
}
}

RDisplay::RDisplay(const VecStr_t &columnNames, const VecStr_t &types, int entries)
RDisplay::RDisplay(const VecStr_t &columnNames, const VecStr_t &types, int entries, size_t nMaxCollectionElements)
: fTypes(types), fWidths(columnNames.size(), 0), fRepresentations(columnNames.size()),
fCollectionsRepresentations(columnNames.size()), fNColumns(columnNames.size()), fEntries(entries)
fCollectionsRepresentations(columnNames.size()), fNColumns(columnNames.size()), fEntries(entries), fNMaxCollectionElements(nMaxCollectionElements)
{

// Add the first row with the names of the columns
fTable.push_back(std::vector<DElement_t>(columnNames.size()));
for (const auto &name : columnNames) {
Expand All @@ -203,14 +204,15 @@ void RDisplay::Print() const
{
auto columnsToPrint =
fNColumns - GetNColumnsToShorten(); // Get the number of columns that fit in the characters limit
std::vector<bool> hasPrintedNext(fNColumns,
false); // Keeps track if the collection as already been shortened, allowing to skip
// all elements until the next printable element.

if (columnsToPrint < fNColumns)
Info("Print", "Only showing %lu columns out of %lu\n", columnsToPrint, fNColumns);

if (fNMaxCollectionElements < 1)
Info("Print", "No collections shown since fNMaxCollectionElements is %lu\n", fNMaxCollectionElements);

auto nrRows = fTable.size();

for (size_t rowIndex = 0; rowIndex < nrRows; ++rowIndex) {
auto &row = fTable[rowIndex];

Expand All @@ -224,23 +226,9 @@ void RDisplay::Print() const
if (element.IsDot()) {
printedElement = "...";
} else if (element.IsPrint()) {
// Maybe the element is part of a collection that is being shortened, and so it was already printed.
if (!hasPrintedNext[columnIndex]) {
printedElement = element.GetRepresentation();
}
hasPrintedNext[columnIndex] =
false; // Encountered "next printable element", shortening can start again when needed.
printedElement = element.GetRepresentation();
} else { // IsIgnore
// Shortening is starting here. Print directly the last element, to have something like 1 ... 3, and don't
// print anything else.
if (!hasPrintedNext[columnIndex]) {
size_t i = rowIndex + 1; // Starting from the next row...
for (; !fTable[i][columnIndex].IsPrint(); ++i) {
// .. look for the first element that can be printed, it will be the last of the collection.
}
printedElement = fTable[i][columnIndex].GetRepresentation(); // Print the element
hasPrintedNext[columnIndex] = true; // And start ignoring anything else until the next collection.
}
// Do nothing, printedElement remains ""
}
if (!printedElement.empty()) {
// Found at least one element, so the row is not empty.
Expand Down
132 changes: 118 additions & 14 deletions tree/dataframe/test/dataframe_display.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ using namespace ROOT::RDF;
using namespace ROOT::VecOps;

static const std::string DisplayPrintDefaultRows(
"b1 | b2 | b3 | \n0 | 1 | 2.0000000 | \n | ... | | \n | 3 | | \n0 | 1 | "
"2.0000000 | \n | ... | | \n | 3 | | \n0 | 1 | 2.0000000 | \n | ... | | \n "
" | 3 | | \n0 | 1 | 2.0000000 | \n | ... | | \n | 3 | | \n0 | 1 | "
"2.0000000 | \n | ... | | \n | 3 | | \n");
"b1 | b2 | b3 | \n0 | 1 | 2.0000000 | \n | 2 | | \n | 3 | | \n0 | 1 | "
"2.0000000 | \n | 2 | | \n | 3 | | \n0 | 1 | 2.0000000 | \n | 2 | | \n "
" | 3 | | \n0 | 1 | 2.0000000 | \n | 2 | | \n | 3 | | \n0 | 1 | "
"2.0000000 | \n | 2 | | \n | 3 | | \n");

static const std::string DisplayAsStringDefaultRows(
"b1 | b2 | b3 | \n0 | 1 | 2.0000000 | \n | 2 | | \n | 3 | | \n0 | 1 | "
"2.0000000 | \n | 2 | | \n | 3 | | \n0 | 1 | 2.0000000 | \n | 2 | | \n "
" | 3 | | \n0 | 1 | 2.0000000 | \n | 2 | | \n | 3 | | \n0 | 1 | "
"2.0000000 | \n | 2 | | \n | 3 | | \n | | | \n");
"b1 | b2 | b3 | \n0 | 1 | 2.0000000 | \n | 2 | | \n | 3 | | \n0 | 1 | "
"2.0000000 | \n | 2 | | \n | 3 | | \n0 | 1 | 2.0000000 | \n | 2 | | \n "
" | 3 | | \n0 | 1 | 2.0000000 | \n | 2 | | \n | 3 | | \n0 | 1 | "
"2.0000000 | \n | 2 | | \n | 3 | | \n | | | \n");

TEST(RDFDisplayTests, DisplayNoJitDefaultRows)
{
Expand Down Expand Up @@ -103,12 +103,12 @@ TEST(RDFDisplayTests, DisplayRegexDefaultRows)
}

static const std::string
DisplayPrintTwoRows("b1 | b2 | b3 | \n0 | 1 | 2.0000000 | \n | ... | | \n | 3 | "
" | \n0 | 1 | 2.0000000 | \n | ... | | \n | 3 | | \n");
DisplayPrintTwoRows("b1 | b2 | b3 | \n0 | 1 | 2.0000000 | \n | 2 | | \n | 3 | "
" | \n0 | 1 | 2.0000000 | \n | 2 | | \n | 3 | | \n");

static const std::string DisplayAsStringTwoRows(
"b1 | b2 | b3 | \n0 | 1 | 2.0000000 | \n | 2 | | \n | 3 | | \n0 | 1 | "
"2.0000000 | \n | 2 | | \n | 3 | | \n | | | \n");
"b1 | b2 | b3 | \n0 | 1 | 2.0000000 | \n | 2 | | \n | 3 | | \n0 | 1 | "
"2.0000000 | \n | 2 | | \n | 3 | | \n | | | \n");

TEST(RDFDisplayTests, DisplayJitTwoRows)
{
Expand Down Expand Up @@ -139,8 +139,9 @@ TEST(RDFDisplayTests, DisplayJitTwoRows)

static const std::string DisplayAsStringOneColumn("b1 | \n0 | \n0 | \n0 | \n0 | \n0 | \n | \n");
static const std::string DisplayAsStringTwoColumns(
"b1 | b2 | \n0 | 1 | \n | 2 | \n | 3 | \n0 | 1 | \n | 2 | \n | 3 | \n0 | 1 | \n | 2 | "
"\n | 3 | \n0 | 1 | \n | 2 | \n | 3 | \n0 | 1 | \n | 2 | \n | 3 | \n | | \n");
"b1 | b2 | \n0 | 1 | \n | 2 | \n | 3 | \n0 | 1 | \n | 2 | \n | 3 | \n0 | 1 | \n | 2 | "
"\n | 3 | \n0 | 1 | \n | 2 | \n | 3 | \n0 | 1 | \n | 2 | \n | 3 | \n | | \n");


TEST(RDFDisplayTests, DisplayAmbiguity)
{
Expand Down Expand Up @@ -245,3 +246,106 @@ TEST(RDFDisplayTests, Friends)
const auto expected = "friend.x | \n0 | \n | \n";
EXPECT_EQ(res, expected);
}

static const std::string DisplayPrintVectors(
"S0 | S1 | S3 | S9 | S10 | S11 | S20 | S20_ | \n"
" | 0 | 0 | 0 | 0 | 0 | 0 | 0 | \n"
" | | 0 | 0 | 0 | 0 | 0 | 0 | \n"
" | | 0 | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | | 0 | 0 | 0 | 0 | \n"
" | | | | | ... | ... | ... | \n"
" | 0 | 0 | 0 | 0 | 0 | 0 | 0 | \n"
" | | 0 | 0 | 0 | 0 | 0 | 0 | \n"
" | | 0 | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | | 0 | 0 | 0 | 0 | \n"
" | | | | | ... | ... | ... | \n"
" | 0 | 0 | 0 | 0 | 0 | 0 | 0 | \n"
" | | 0 | 0 | 0 | 0 | 0 | 0 | \n"
" | | 0 | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | 0 | 0 | 0 | 0 | 0 | \n"
" | | | | 0 | 0 | 0 | 0 | \n"
" | | | | | ... | ... | ... | \n");

static const std::string DisplayAsStringVectors(
"S0 | S1 | S3 | S9 | S10 | S11 | S20 | S20_ | \n | 0 | 0 | 0 | 0 | 0 | 0 | 0 | \n | | 0 | 0 | 0 | 0 | 0 | 0 | \n | | 0 | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | | 0 | 0 | 0 | 0 | \n | | | | | 0 | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | 0 | 0 | 0 | 0 | 0 | 0 | 0 | \n | | 0 | 0 | 0 | 0 | 0 | 0 | \n | | 0 | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | | 0 | 0 | 0 | 0 | \n | | | | | 0 | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | 0 | 0 | 0 | 0 | 0 | 0 | 0 | \n | | 0 | 0 | 0 | 0 | 0 | 0 | \n | | 0 | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | 0 | 0 | 0 | 0 | 0 | \n | | | | 0 | 0 | 0 | 0 | \n | | | | | 0 | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | 0 | 0 | \n | | | | | | | | \n"
);

TEST(RDFDisplayTests, Vectors)
{
std::vector<int> v0 (0);
std::vector<int> v1(1);
std::vector<int> v3(3);
std::vector<int> v9(9);
std::vector<int> v10(10);
std::vector<int> v11(11);
std::vector<int> v20(20);

RDataFrame vc(3);

auto dd = vc.Define("S0", [&v0] { return v0; })
.Define("S1", [&v1] { return v1; })
.Define("S3", [&v3] { return v3; })
.Define("S9", [&v9] { return v9; })
.Define("S10", [&v10] { return v10; })
.Define("S11", [&v11] { return v11; })
.Define("S20", [&v20] { return v20; })
.Define("S20_", [&v20] { return v20; })
.Display<std::vector<int>, std::vector<int>,
std::vector<int>, std::vector<int>,
std::vector<int>, std::vector<int>,
std::vector<int>, std::vector<int>>({"S0", "S1", "S3", "S9",
"S10", "S11", "S20", "S20_"});

// Testing the std output printing
std::cout << std::flush;
// Redirect cout.
std::streambuf *oldCoutStreamBuf = std::cout.rdbuf();
std::ostringstream strCout;
std::cout.rdbuf(strCout.rdbuf());
dd->Print();
// Restore old cout.
std::cout.rdbuf(oldCoutStreamBuf);

EXPECT_EQ(strCout.str(), DisplayPrintVectors);

// Testing the string returned
EXPECT_EQ(dd->AsString(), DisplayAsStringVectors);
}

TEST(RDFDisplayTests, CustomMaxWidth)
{

std::vector<int> v3(3);
ROOT::RDataFrame vc(3);
auto dd = vc.Define("S3", [&v3] { return v3; })
.Display<std::vector<int>>({"S3"}, 1, 2);

// Testing the std output printing
std::cout << std::flush;
// Redirect cout.
std::streambuf *oldCoutStreamBuf = std::cout.rdbuf();
std::ostringstream strCout;
std::cout.rdbuf(strCout.rdbuf());
dd->Print();
// Restore old cout.
std::cout.rdbuf(oldCoutStreamBuf);

EXPECT_EQ(strCout.str(), "S3 | \n0 | \n0 | \n... | \n");
}