From f1c4392d4d38eeb8fb15a32c691be8f116c89a83 Mon Sep 17 00:00:00 2001
From: Ivan Kabadzhov <kabadzhovivan@gmail.com>
Date: Tue, 12 Oct 2021 16:16:58 +0200
Subject: [PATCH 1/2] [Fix #6981] RDisplay::Print to list custom number of 
 elements from collections

AddCollectionToRow() modified so that the first 10 elements of long collections
are to be printed, then followed by "...". Previously, only the first and last
elements of collections of size >=3 were printed.

Print() logic is now simplified, since after "..." there is no guarantee
that there is going to be a next element.

Additional paramter to the constructor of the the RDisplay() was added,
that is the nMaxCollectionElements. It determines, number of elements to be
shown from long collction. Default is 10.

Corresponding tests were adapted and additional ones were added to check
the new functionality.

Regarding #6981 - to display the whole collection, please use AsString().
---
 tree/dataframe/inc/ROOT/RDF/RDisplay.hxx   |   4 +-
 tree/dataframe/inc/ROOT/RDF/RInterface.hxx |  28 ++--
 tree/dataframe/src/RDFDisplay.cxx          |  38 ++----
 tree/dataframe/test/dataframe_display.cxx  | 151 +++++++++++++++++++--
 4 files changed, 172 insertions(+), 49 deletions(-)

diff --git a/tree/dataframe/inc/ROOT/RDF/RDisplay.hxx b/tree/dataframe/inc/ROOT/RDF/RDisplay.hxx
index d245dbb5cb1ac..30a451e335d9b 100644
--- a/tree/dataframe/inc/ROOT/RDF/RDisplay.hxx
+++ b/tree/dataframe/inc/ROOT/RDF/RDisplay.hxx
@@ -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
@@ -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
diff --git a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx
index 205999dda3dff..8576f069e511d 100644
--- a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx
+++ b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx
@@ -2566,13 +2566,15 @@ 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
    /// form. RDisplay will either print on the standard output a summarized version through `Print()` or will return a
    /// complete version through `AsString()`.
    ///
-   /// This action is *lazy*: upon invocation of this method the calculation is booked but not executed. Also see RResultPtr.
+   /// This action is *lazy*: upon invocation of this method the calculation is booked but not executed. Also see
+   /// RResultPtr.
    ///
    /// Example usage:
    /// ~~~{.cpp}
@@ -2585,11 +2587,13 @@ 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);
    }
 
@@ -2597,14 +2601,17 @@ public:
    /// \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());
    }
@@ -2613,16 +2620,18 @@ 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);
    }
 
    ////////////////////////////////////////////////////////////////////////////
@@ -2632,10 +2641,11 @@ 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:
diff --git a/tree/dataframe/src/RDFDisplay.cxx b/tree/dataframe/src/RDFDisplay.cxx
index 34df42c750958..4f1d3f76aa9a5 100644
--- a/tree/dataframe/src/RDFDisplay.cxx
+++ b/tree/dataframe/src/RDFDisplay.cxx
@@ -124,6 +124,7 @@ 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.
@@ -135,14 +136,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();
       }
 
@@ -172,11 +173,11 @@ 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) {
@@ -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];
 
@@ -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.
diff --git a/tree/dataframe/test/dataframe_display.cxx b/tree/dataframe/test/dataframe_display.cxx
index 62cee1a5a2b35..15e8fdc9c04e0 100644
--- a/tree/dataframe/test/dataframe_display.cxx
+++ b/tree/dataframe/test/dataframe_display.cxx
@@ -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)
 {
@@ -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)
 {
@@ -139,8 +139,8 @@ 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)
 {
@@ -245,3 +245,126 @@ 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");
+}
\ No newline at end of file

From 1a8a4ef7a89b4c10a7f455bb00e0c923889e36cf Mon Sep 17 00:00:00 2001
From: Ivan Kabadzhov <46775299+ikabadzhov@users.noreply.github.com>
Date: Wed, 13 Oct 2021 17:31:40 +0200
Subject: [PATCH 2/2] Apply suggestions from code review

Co-authored-by: Enrico Guiraud <enrico.guiraud@cern.ch>
---
 tree/dataframe/inc/ROOT/RDF/RInterface.hxx | 16 ++++++++--------
 tree/dataframe/src/RDFDisplay.cxx          |  1 -
 2 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx
index 8576f069e511d..cd7610f07bdbb 100644
--- a/tree/dataframe/inc/ROOT/RDF/RInterface.hxx
+++ b/tree/dataframe/inc/ROOT/RDF/RInterface.hxx
@@ -2566,7 +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().
+   /// \param[in] nMaxCollectionElements Maximum number of collection elements to display per row.
    /// \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
@@ -2588,7 +2588,7 @@ public:
    /// ~~~
    template <typename... ColumnTypes>
    RResultPtr<RDisplay>
-   Display(const ColumnNames_t &columnList, const int &nRows = 5, const size_t &nMaxCollectionElements = 10)
+   Display(const ColumnNames_t &columnList, int nRows = 5, size_t nMaxCollectionElements = 10)
    {
       CheckIMTDisabled("Display");
 
@@ -2601,13 +2601,13 @@ public:
    /// \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().
+   /// \param[in] nMaxCollectionElements  Maximum number of collection elements to display per row.
    /// \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, const size_t &nMaxCollectionElements = 10)
+   Display(const ColumnNames_t &columnList, int nRows = 5, size_t nMaxCollectionElements = 10)
    {
       CheckIMTDisabled("Display");
       auto displayer = std::make_shared<RDFInternal::RDisplay>(columnList, GetColumnTypeNamesList(columnList), nRows,
@@ -2620,14 +2620,14 @@ 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().
+   /// \param[in] nMaxCollectionElements Maximum number of collection elements to display per row.
    /// \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, const size_t &nMaxCollectionElements = 10)
+   Display(std::string_view columnNameRegexp = "", int nRows = 5, size_t nMaxCollectionElements = 10)
    {
       const auto columnNames = GetColumnNames();
       const auto selectedColumns = RDFInternal::ConvertRegexToColumns(columnNames, columnNameRegexp, "Display");
@@ -2641,8 +2641,8 @@ 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,
-                                const size_t &nMaxCollectionElements = 10)
+   RResultPtr<RDisplay> Display(std::initializer_list<std::string> columnList, int nRows = 5,
+                                size_t nMaxCollectionElements = 10)
    {
       ColumnNames_t selectedColumns(columnList);
       return Display(selectedColumns, nRows, nMaxCollectionElements);
diff --git a/tree/dataframe/src/RDFDisplay.cxx b/tree/dataframe/src/RDFDisplay.cxx
index 4f1d3f76aa9a5..46009239cda89 100644
--- a/tree/dataframe/src/RDFDisplay.cxx
+++ b/tree/dataframe/src/RDFDisplay.cxx
@@ -124,7 +124,6 @@ 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.
