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