This is an automated email from the ASF dual-hosted git repository.

kevingurney pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new 547b2406d7 GH-38166: [MATLAB] Improve tabular object display (#38482)
547b2406d7 is described below

commit 547b2406d71bf9ad14e2bcc7064c6923165dd737
Author: sgilmore10 <[email protected]>
AuthorDate: Fri Oct 27 11:01:19 2023 -0400

    GH-38166: [MATLAB] Improve tabular object display (#38482)
    
    
    
    ### Rationale for this change
    
    Currently, the display for `arrow.tabular.RecordBatch` and 
`arrow.tabular.Table` are not very MATLAB-like.
    
    ### What changes are included in this PR?
    
    1. Updated the display of both `arrow.tabular.Table` and 
`arrow.tabular.RecordBatch`.
    2. Added a new utility function `arrow.internal.display.boldFontIfPossible`
    3. Renamed  `arrow.array.internal.display.pluralizeStringIfNeeded` to 
`arrow.internal.display.pluralizeStringIfNeeded`
    4. Renamed `arrow.tabular.internal.displaySchema` to 
`arrow.tabular.internal.display.getSchemaString`.
    
    **Example RecordBatch Display**
    
    ```matlab
    >> t = table(1, false, datetime(2023, 1, 1), VariableNames=["Number", 
"Logical", "Date"]);
    >> rb = arrow.recordBatch(t)
    
    rb =
    
      Arrow RecordBatch with 1 row and 3 columns:
    
        Schema:
    
            Number: Float64 | Logical: Boolean | Date: Timestamp
    
        First Row:
    
            1 | false | 2023-01-01 00:00:00.000000
    ```
    
    **Example Table Display**
    
    ```matlab
    >> t = table(1, false, datetime(2023, 1, 1), VariableNames=["Number", 
"Logical", "Date"]);
    >> arrowTable = arrow.table(t)
    
    arrowTable =
    
      Arrow Table with 1 row and 3 columns:
    
        Schema:
    
            Number: Float64 | Logical: Boolean | Date: Timestamp
    
        First Row:
    
            1 | false | 2023-01-01 00:00:00.000000
    ```
    
    ### Are these changes tested?
    
    Yes, I added a new test class in `matlab/test/arrow/tabular` called 
`tTabularDisplay.m`.
    
    ### Are there any user-facing changes?
    
    Yes. Users will now see the new `Table`/`RecordBatch` display
    
    * Closes: #38166
    
    Authored-by: Sarah Gilmore <[email protected]>
    Signed-off-by: Kevin Gurney <[email protected]>
---
 .../+arrow/+array/+internal/+display/getHeader.m   |   2 +-
 .../+display/boldFontIfPossible.m}                 |  15 ++-
 .../+internal/+display/pluralizeStringIfNeeded.m   |   0
 .../getSchemaString.m}                             |   7 +-
 .../+internal/+display/getTabularDisplay.m         |  44 ++++++
 .../+internal/+display/getTabularHeader.m}         |  21 ++-
 matlab/src/matlab/+arrow/+tabular/RecordBatch.m    |   4 +-
 matlab/src/matlab/+arrow/+tabular/Schema.m         |   2 +-
 matlab/src/matlab/+arrow/+tabular/Table.m          |   5 +-
 matlab/test/arrow/tabular/tTabularDisplay.m        | 148 +++++++++++++++++++++
 10 files changed, 228 insertions(+), 20 deletions(-)

diff --git a/matlab/src/matlab/+arrow/+array/+internal/+display/getHeader.m 
b/matlab/src/matlab/+arrow/+array/+internal/+display/getHeader.m
index 5c8704d5bf..85301ddefa 100644
--- a/matlab/src/matlab/+arrow/+array/+internal/+display/getHeader.m
+++ b/matlab/src/matlab/+arrow/+array/+internal/+display/getHeader.m
@@ -16,7 +16,7 @@
 % permissions and limitations under the License.
 
 function header = getHeader(className, numElements, numNulls)
-    import arrow.array.internal.display.pluralizeStringIfNeeded
+    import arrow.internal.display.pluralizeStringIfNeeded
     elementString = pluralizeStringIfNeeded(numElements, "element");
 
     nullString = pluralizeStringIfNeeded(numNulls, "null value");
diff --git 
a/matlab/src/matlab/+arrow/+array/+internal/+display/pluralizeStringIfNeeded.m 
b/matlab/src/matlab/+arrow/+internal/+display/boldFontIfPossible.m
similarity index 76%
copy from 
matlab/src/matlab/+arrow/+array/+internal/+display/pluralizeStringIfNeeded.m
copy to matlab/src/matlab/+arrow/+internal/+display/boldFontIfPossible.m
index ae9eafba92..cb980cbff9 100644
--- 
a/matlab/src/matlab/+arrow/+array/+internal/+display/pluralizeStringIfNeeded.m
+++ b/matlab/src/matlab/+arrow/+internal/+display/boldFontIfPossible.m
@@ -1,4 +1,4 @@
-%PLURALIZESTRINGIFNEEDED Pluralizes str if num is not equal to 1.
+%BOLDFONTIFPOSSIBLE Bolds the input string if possible
 
 % Licensed to the Apache Software Foundation (ASF) under one or more
 % contributor license agreements.  See the NOTICE file distributed with
@@ -15,9 +15,12 @@
 % implied.  See the License for the specific language governing
 % permissions and limitations under the License.
 
-function str = pluralizeStringIfNeeded(num, str)
-    if num ~= 1
-        str = str + "s";
-    end
-end
+function str = boldFontIfPossible(str)
 
+    arguments
+        str(1, 1) string {mustBeNonzeroLengthText}
+    end
+    if usejava("desktop")
+        str = compose("<strong>%s</strong>", str);
+    end
+end
\ No newline at end of file
diff --git 
a/matlab/src/matlab/+arrow/+array/+internal/+display/pluralizeStringIfNeeded.m 
b/matlab/src/matlab/+arrow/+internal/+display/pluralizeStringIfNeeded.m
similarity index 100%
copy from 
matlab/src/matlab/+arrow/+array/+internal/+display/pluralizeStringIfNeeded.m
copy to matlab/src/matlab/+arrow/+internal/+display/pluralizeStringIfNeeded.m
diff --git a/matlab/src/matlab/+arrow/+tabular/+internal/displaySchema.m 
b/matlab/src/matlab/+arrow/+tabular/+internal/+display/getSchemaString.m
similarity index 92%
rename from matlab/src/matlab/+arrow/+tabular/+internal/displaySchema.m
rename to matlab/src/matlab/+arrow/+tabular/+internal/+display/getSchemaString.m
index 8d6740b195..7da945ca99 100644
--- a/matlab/src/matlab/+arrow/+tabular/+internal/displaySchema.m
+++ b/matlab/src/matlab/+arrow/+tabular/+internal/+display/getSchemaString.m
@@ -1,4 +1,5 @@
-%DISPLAYSCHEMA Generates arrow.tabular.Schema display text.
+%GETSCHEMASTRING Generates a string representation of an 
+% arrow.tabular.Schema object.
 
 % Licensed to the Apache Software Foundation (ASF) under one or more
 % contributor license agreements.  See the NOTICE file distributed with
@@ -15,7 +16,7 @@
 % implied.  See the License for the specific language governing
 % permissions and limitations under the License.
 
-function text = displaySchema(schema)
+function text = getSchemaString(schema)
     fields = schema.Fields;
     names = [fields.Name];
     types = [fields.Type];
@@ -46,5 +47,5 @@ function text = displaySchema(schema)
     end
 
     text = names + ": " + typeIDs;
-    text = "    " + strjoin(text, " | ");
+    text = strjoin(text, " | ");
 end
\ No newline at end of file
diff --git 
a/matlab/src/matlab/+arrow/+tabular/+internal/+display/getTabularDisplay.m 
b/matlab/src/matlab/+arrow/+tabular/+internal/+display/getTabularDisplay.m
new file mode 100644
index 0000000000..054922fa03
--- /dev/null
+++ b/matlab/src/matlab/+arrow/+tabular/+internal/+display/getTabularDisplay.m
@@ -0,0 +1,44 @@
+%GETTABULARDISPLAY Generates the display for arrow.tabular.Table and
+% arrow.tabular.RecordBatch.
+
+% Licensed to the Apache Software Foundation (ASF) under one or more
+% contributor license agreements.  See the NOTICE file distributed with
+% this work for additional information regarding copyright ownership.
+% The ASF licenses this file to you under the Apache License, Version
+% 2.0 (the "License"); you may not use this file except in compliance
+% with the License.  You may obtain a copy of the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS,
+% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+% implied.  See the License for the specific language governing
+% permissions and limitations under the License.
+
+function tabularDisplay = getTabularDisplay(tabularObj, className)
+    import arrow.tabular.internal.display.getSchemaString
+    import arrow.tabular.internal.display.getTabularHeader
+
+    numRows = tabularObj.NumRows;
+    numColumns = tabularObj.NumColumns;
+    tabularDisplay = getTabularHeader(className, numRows, numColumns);
+
+    if numColumns > 0
+        twoNewLines = string([newline newline]);
+        fourSpaces = string(repmat(' ', 1, 4));
+        eightSpaces = string(repmat(' ', 1, 8));
+
+        schemaHeader = fourSpaces + "Schema:";
+        schemaBody =   eightSpaces + getSchemaString(tabularObj.Schema);
+        schemaDisplay = schemaHeader + twoNewLines + schemaBody;
+        tabularDisplay = tabularDisplay + twoNewLines + schemaDisplay;
+    
+        if numRows > 0
+            rowHeader = fourSpaces + "First Row:";
+            rowBody = eightSpaces + 
tabularObj.Proxy.getRowAsString(struct(Index=int64(1)));
+            rowDisplay = rowHeader + twoNewLines + rowBody;
+            tabularDisplay = tabularDisplay + twoNewLines + rowDisplay;
+        end
+    end
+end
diff --git 
a/matlab/src/matlab/+arrow/+array/+internal/+display/pluralizeStringIfNeeded.m 
b/matlab/src/matlab/+arrow/+tabular/+internal/+display/getTabularHeader.m
similarity index 51%
rename from 
matlab/src/matlab/+arrow/+array/+internal/+display/pluralizeStringIfNeeded.m
rename to 
matlab/src/matlab/+arrow/+tabular/+internal/+display/getTabularHeader.m
index ae9eafba92..4c647986ce 100644
--- 
a/matlab/src/matlab/+arrow/+array/+internal/+display/pluralizeStringIfNeeded.m
+++ b/matlab/src/matlab/+arrow/+tabular/+internal/+display/getTabularHeader.m
@@ -1,4 +1,5 @@
-%PLURALIZESTRINGIFNEEDED Pluralizes str if num is not equal to 1.
+%GETTABULARHEADER Generates the display header for arrow.tabular.Table and
+% arrow.tabular.RecordBatch.
 
 % Licensed to the Apache Software Foundation (ASF) under one or more
 % contributor license agreements.  See the NOTICE file distributed with
@@ -15,9 +16,17 @@
 % implied.  See the License for the specific language governing
 % permissions and limitations under the License.
 
-function str = pluralizeStringIfNeeded(num, str)
-    if num ~= 1
-        str = str + "s";
-    end
-end
+function header = getTabularHeader(className, numRows, numColumns)
+    import arrow.internal.display.boldFontIfPossible
+    import arrow.internal.display.pluralizeStringIfNeeded
 
+    numRowsString = boldFontIfPossible(numRows);
+    numColsString = boldFontIfPossible(numColumns);
+    rowWordString = pluralizeStringIfNeeded(numRows, "row");
+    colWordString = pluralizeStringIfNeeded(numColumns, "column");
+    formatSpec = "  Arrow %s with %s %s and %s %s";
+    if numColumns > 0
+        formatSpec = formatSpec + ":";
+    end
+    header = compose(formatSpec,className, numRowsString, rowWordString, 
numColsString, colWordString);
+end
\ No newline at end of file
diff --git a/matlab/src/matlab/+arrow/+tabular/RecordBatch.m 
b/matlab/src/matlab/+arrow/+tabular/RecordBatch.m
index fdedaecb5e..0225f3d771 100644
--- a/matlab/src/matlab/+arrow/+tabular/RecordBatch.m
+++ b/matlab/src/matlab/+arrow/+tabular/RecordBatch.m
@@ -112,7 +112,9 @@ classdef RecordBatch < matlab.mixin.CustomDisplay & ...
 
     methods (Access=protected)
         function displayScalarObject(obj)
-            disp(obj.toString());
+            className = matlab.mixin.CustomDisplay.getClassNameForHeader(obj);
+            tabularDisplay = 
arrow.tabular.internal.display.getTabularDisplay(obj, className);
+            disp(tabularDisplay + newline);
         end
     end
 
diff --git a/matlab/src/matlab/+arrow/+tabular/Schema.m 
b/matlab/src/matlab/+arrow/+tabular/Schema.m
index 3ee40f0e14..a50522c6b5 100644
--- a/matlab/src/matlab/+arrow/+tabular/Schema.m
+++ b/matlab/src/matlab/+arrow/+tabular/Schema.m
@@ -116,7 +116,7 @@ classdef Schema < matlab.mixin.CustomDisplay & ...
             numFields = obj.NumFields;
 
             if numFields > 0
-                text = arrow.tabular.internal.displaySchema(obj);
+                text = "    " + 
arrow.tabular.internal.display.getSchemaString(obj);
                 disp(text + newline);
             end
 
diff --git a/matlab/src/matlab/+arrow/+tabular/Table.m 
b/matlab/src/matlab/+arrow/+tabular/Table.m
index c2f7345040..1ed205d639 100644
--- a/matlab/src/matlab/+arrow/+tabular/Table.m
+++ b/matlab/src/matlab/+arrow/+tabular/Table.m
@@ -112,9 +112,10 @@ classdef Table < matlab.mixin.CustomDisplay & 
matlab.mixin.Scalar
     end
 
     methods (Access=protected)
-
         function displayScalarObject(obj)
-            disp(obj.toString());
+            className = matlab.mixin.CustomDisplay.getClassNameForHeader(obj);
+            tabularDisplay = 
arrow.tabular.internal.display.getTabularDisplay(obj, className);
+            disp(tabularDisplay + newline);
         end
 
     end
diff --git a/matlab/test/arrow/tabular/tTabularDisplay.m 
b/matlab/test/arrow/tabular/tTabularDisplay.m
new file mode 100644
index 0000000000..f99b25ab34
--- /dev/null
+++ b/matlab/test/arrow/tabular/tTabularDisplay.m
@@ -0,0 +1,148 @@
+%TTABULARDISPLAY Unit tests verifying the display of arrow.tabular.Table
+%and arrow.tabular.RecordBatch objects.
+
+% Licensed to the Apache Software Foundation (ASF) under one or more
+% contributor license agreements.  See the NOTICE file distributed with
+% this work for additional information regarding copyright ownership.
+% The ASF licenses this file to you under the Apache License, Version
+% 2.0 (the "License"); you may not use this file except in compliance
+% with the License.  You may obtain a copy of the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS,
+% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+% implied.  See the License for the specific language governing
+% permissions and limitations under the License.
+
+classdef tTabularDisplay < matlab.unittest.TestCase
+
+    properties (TestParameter)
+        TabularType
+    end
+
+    methods (TestParameterDefinition, Static)
+        function TabularType = initializeTabularType()
+
+            tableStruct = struct(FullClassName="arrow.tabular.Table", ...
+                ClassName="Table", FromTableFcn = @arrow.table);
+            
+            recordBatchStruct = 
struct(FullClassName="arrow.tabular.RecordBatch", ...
+                ClassName="RecordBatch", [email protected]);
+
+            TabularType = struct(Table=tableStruct, 
RecordBatch=recordBatchStruct);
+        end
+
+    end
+
+    methods (Test)
+
+        function ZeroRowsZeroColumns(testCase, TabularType)
+            % Verify tabular object display when the object has zero rows
+            % and zero columns.
+            import arrow.internal.test.display.makeLinkString
+            
+            tabularObj = TabularType.FromTableFcn(table); %#ok<NASGU>
+            
+            classNameString = 
makeLinkString(FullClassName=TabularType.FullClassName, ...
+                ClassName=TabularType.ClassName, BoldFont=true);
+            zeroString = getNumString(0);
+            header = compose("  Arrow %s with %s rows and %s columns", 
classNameString, zeroString, zeroString);
+            expectedDisplay = char(header + newline + newline);
+            actualDisplay = evalc('disp(tabularObj)');
+
+            testCase.verifyEqual(actualDisplay, expectedDisplay);
+        end
+
+        function ZeroRowsOneColumn(testCase, TabularType)
+            % Verify tabular object display when the object has zero rows
+            % and one column.
+            import arrow.internal.test.display.makeLinkString
+            
+            t = table(1, VariableNames="Number");
+            tabularObj = TabularType.FromTableFcn(t(1:0, :)); %#ok<NASGU>
+            
+            classNameString = 
makeLinkString(FullClassName=TabularType.FullClassName, ...
+                ClassName=TabularType.ClassName, BoldFont=true);
+            header = compose("  Arrow %s with %s rows and %s column:", 
classNameString, getNumString(0), getNumString(1));
+            
+            fieldString = makeFieldString("Number", "Float64", 
"arrow.type.Float64Type");
+            schema = join(["    Schema:" "        " + fieldString], [newline 
newline]);
+            
+            expectedDisplay = char(join([header schema + newline + newline], 
[newline newline]));
+            actualDisplay = evalc('disp(tabularObj)');
+
+            testCase.verifyEqual(actualDisplay, expectedDisplay);
+        end
+
+        function OneRowOneColumn(testCase, TabularType)
+            % Verify tabular object display when the object has one row
+            % and column.
+            import arrow.internal.test.display.makeLinkString
+            
+            t = table(1, VariableNames="Number");
+            tabularObj = TabularType.FromTableFcn(t); %#ok<NASGU>
+            
+            classNameString = 
makeLinkString(FullClassName=TabularType.FullClassName, ...
+                ClassName=TabularType.ClassName, BoldFont=true);
+            header = compose("  Arrow %s with %s row and %s column:", 
classNameString, getNumString(1), getNumString(1));
+            
+            fieldString = makeFieldString("Number", "Float64", 
"arrow.type.Float64Type");
+            schema = join(["    Schema:" "        " + fieldString], [newline 
newline]);
+            row = join(["    First Row:"  "        1"], [newline newline]);
+
+            
+            expectedDisplay = char(join([header schema row + newline + 
newline], [newline newline]));
+            actualDisplay = evalc('disp(tabularObj)');
+
+            testCase.verifyEqual(actualDisplay, expectedDisplay);
+        end
+
+        function ManyRowsAndColumns(testCase, TabularType)
+            % Verify tabular object display when the object has many rows
+            % and columns.
+            import arrow.internal.test.display.makeLinkString
+            
+            t = table((1:2)', ["A"; "B"], true(2, 1), VariableNames=["Number", 
"Letter", "Logical"]);
+            tabularObj = TabularType.FromTableFcn(t); %#ok<NASGU>
+            
+            classNameString = 
makeLinkString(FullClassName=TabularType.FullClassName, ...
+                ClassName=TabularType.ClassName, BoldFont=true);
+            header = compose("  Arrow %s with %s rows and %s columns:", 
classNameString, getNumString(2), getNumString(3));
+            
+            fieldOneString = makeFieldString("Number", "Float64", 
"arrow.type.Float64Type");
+            fieldTwoString = makeFieldString("Letter", "String", 
"arrow.type.StringType");
+            fieldThreeString = makeFieldString("Logical", "Boolean", 
"arrow.type.BooleanType");
+
+            fields = join([fieldOneString fieldTwoString fieldThreeString], " 
| ");
+            schema = join(["    Schema:" "        " + fields], [newline 
newline]);
+            row = join(["    First Row:"  "        1 | ""A"" | true"], 
[newline newline]);
+            
+            expectedDisplay = char(join([header schema row + newline + 
newline], [newline newline]));
+            actualDisplay = evalc('disp(tabularObj)');
+
+            testCase.verifyEqual(actualDisplay, expectedDisplay);
+        end
+    end
+end
+
+function numString = getNumString(num)
+    if usejava("desktop")
+        numString = compose("<strong>%d</strong>", num);
+    else
+        numString = compose("%d", num);
+    end
+end
+
+function str = makeFieldString(fieldName, classType, fullClassType)
+    import arrow.internal.test.display.makeLinkString
+
+    if usejava("desktop")
+        name = compose("<strong>%s</strong>:", fieldName);
+        typeStr = makeLinkString(FullClassName=fullClassType, 
ClassName=classType, BoldFont=true);
+        str = name + " " + typeStr;
+    else
+        str = fieldName + ": " + classType;
+    end
+end
\ No newline at end of file

Reply via email to