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 00efb06dc0 GH-37835: [MATLAB] Improve `arrow.tabular.Schema` display
(#37836)
00efb06dc0 is described below
commit 00efb06dc0de9c40907576811ebb546198b7f528
Author: sgilmore10 <[email protected]>
AuthorDate: Fri Sep 29 16:16:50 2023 -0400
GH-37835: [MATLAB] Improve `arrow.tabular.Schema` display (#37836)
### Rationale for this change
We would like to change how `arrow.tabular.Schema`s are displayed in the
Command Window. Below is the current display:
```matlab
>> field1 = arrow.field("A", arrow.time32());
>> field2 = arrow.field("B", arrow.boolean());
>>s = arrow.schema([field1 field2])
s =
A: time32[s]
B: bool
```
This display is not very MATLAB-like.
### What changes are included in this PR?
1. Updated the display of `arrow.tabular.Schema`. Below is the new display:
```matlab
>> field1 = arrow.field("A", arrow.time32());
>> field2 = arrow.field("B", arrow.boolean());
>> s = arrow.schema([field1 field2])
s =
Arrow Schema with 2 fields:
A: Time32 | B: Boolean
```
When MATLAB is opened in desktop mode, `Schema`, `Time32`, and `Boolean`
are hyperlinks users can click on to view the help text for the different class
types.
### Are these changes tested?
Yes. Added three new test cases to `tSchema.m`:
1. `TestDisplaySchemaZeroFields`
2. `TestDisplaySchemaOneField`
3. `TestDisplaySchemaMultipleFields`
### Are there any user-facing changes?
Yes. `arrow.tabular.Schema`s will be displayed differently in the Command
Window.
### Notes
Once #37826 is merged, I will rebase my changes and mark this PR as ready
for review.
* Closes: #37835
Authored-by: Sarah Gilmore <[email protected]>
Signed-off-by: Kevin Gurney <[email protected]>
---
.../src/cpp/arrow/matlab/tabular/proxy/schema.cc | 11 ----
matlab/src/cpp/arrow/matlab/tabular/proxy/schema.h | 1 -
.../+arrow/+tabular/+internal/displaySchema.m | 50 +++++++++++++++++
matlab/src/matlab/+arrow/+tabular/Schema.m | 25 ++++++---
matlab/test/arrow/tabular/tSchema.m | 63 ++++++++++++++++++++++
5 files changed, 131 insertions(+), 19 deletions(-)
diff --git a/matlab/src/cpp/arrow/matlab/tabular/proxy/schema.cc
b/matlab/src/cpp/arrow/matlab/tabular/proxy/schema.cc
index ec1ac1eecb..023381e005 100644
--- a/matlab/src/cpp/arrow/matlab/tabular/proxy/schema.cc
+++ b/matlab/src/cpp/arrow/matlab/tabular/proxy/schema.cc
@@ -34,7 +34,6 @@ namespace arrow::matlab::tabular::proxy {
REGISTER_METHOD(Schema, getFieldByName);
REGISTER_METHOD(Schema, getNumFields);
REGISTER_METHOD(Schema, getFieldNames);
- REGISTER_METHOD(Schema, toString);
}
libmexclass::proxy::MakeResult Schema::make(const
libmexclass::proxy::FunctionArguments& constructor_arguments) {
@@ -141,14 +140,4 @@ namespace arrow::matlab::tabular::proxy {
context.outputs[0] = field_names_mda;
}
- void Schema::toString(libmexclass::proxy::method::Context& context) {
- namespace mda = ::matlab::data;
- mda::ArrayFactory factory;
-
- const auto str_utf8 = schema->ToString();
- MATLAB_ASSIGN_OR_ERROR_WITH_CONTEXT(const auto str_utf16,
arrow::util::UTF8StringToUTF16(str_utf8), context,
error::UNICODE_CONVERSION_ERROR_ID);
- auto str_mda = factory.createScalar(str_utf16);
- context.outputs[0] = str_mda;
- }
-
}
diff --git a/matlab/src/cpp/arrow/matlab/tabular/proxy/schema.h
b/matlab/src/cpp/arrow/matlab/tabular/proxy/schema.h
index 30883bc2a8..9ca4a94e53 100644
--- a/matlab/src/cpp/arrow/matlab/tabular/proxy/schema.h
+++ b/matlab/src/cpp/arrow/matlab/tabular/proxy/schema.h
@@ -39,7 +39,6 @@ namespace arrow::matlab::tabular::proxy {
void getFieldByName(libmexclass::proxy::method::Context& context);
void getNumFields(libmexclass::proxy::method::Context& context);
void getFieldNames(libmexclass::proxy::method::Context& context);
- void toString(libmexclass::proxy::method::Context& context);
std::shared_ptr<arrow::Schema> schema;
};
diff --git a/matlab/src/matlab/+arrow/+tabular/+internal/displaySchema.m
b/matlab/src/matlab/+arrow/+tabular/+internal/displaySchema.m
new file mode 100644
index 0000000000..8d6740b195
--- /dev/null
+++ b/matlab/src/matlab/+arrow/+tabular/+internal/displaySchema.m
@@ -0,0 +1,50 @@
+%DISPLAYSCHEMA Generates arrow.tabular.Schema display text.
+
+% 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 text = displaySchema(schema)
+ fields = schema.Fields;
+ names = [fields.Name];
+ types = [fields.Type];
+ typeIDs = string([types.ID]);
+
+ % Use <empty> as the sentinel for field names with zero characters.
+ idx = strlength(names) == 0;
+ names(idx) = "<empty>";
+
+ if usejava("desktop")
+ % When in desktop mode, the Command Window can interpret HTML tags
+ % to display bold font and hyperlinks.
+ names = compose("<strong>%s</strong>", names);
+ classNames = arrayfun(@(type) string(class(type)), types);
+
+ % Creates a string array with the following form:
+ %
+ % ["arrow.type.BooleanType" "Boolean" "arrow.type.StringType" "String"
...]
+ %
+ % This string array is passed to the compose call below. The
+ % format specifier operator supplied to compose contains two
+ % formatting operators (%s), so compose uses two elements from the
+ % string array (classNameAndIDs) at a time.
+ classNameAndIDs = strings([1 numel(typeIDs) * 2]);
+ classNameAndIDs(1:2:end-1) = classNames;
+ classNameAndIDs(2:2:end) = typeIDs;
+ typeIDs = compose("<a href=""matlab:helpPopup %s""
style=""font-weight:bold"">%s</a>", classNameAndIDs);
+ end
+
+ text = names + ": " + typeIDs;
+ text = " " + strjoin(text, " | ");
+end
\ No newline at end of file
diff --git a/matlab/src/matlab/+arrow/+tabular/Schema.m
b/matlab/src/matlab/+arrow/+tabular/Schema.m
index f679b1e0bc..3ee40f0e14 100644
--- a/matlab/src/matlab/+arrow/+tabular/Schema.m
+++ b/matlab/src/matlab/+arrow/+tabular/Schema.m
@@ -97,18 +97,29 @@ classdef Schema < matlab.mixin.CustomDisplay & ...
end
end
- methods (Access = private)
+ methods (Access=protected)
- function str = toString(obj)
- str = obj.Proxy.toString();
+ function header = getHeader(obj)
+ name = matlab.mixin.CustomDisplay.getClassNameForHeader(obj);
+ numFields = obj.NumFields;
+ if numFields == 0
+ header = compose(" Arrow %s with 0 fields" + newline, name);
+ elseif numFields == 1
+ header = compose(" Arrow %s with %d field:" + newline, name,
numFields);
+ else
+ header = compose(" Arrow %s with %d fields:" + newline, name,
numFields);
+ end
end
- end
+ function displayScalarObject(obj)
+ disp(getHeader(obj));
+ numFields = obj.NumFields;
- methods (Access=protected)
+ if numFields > 0
+ text = arrow.tabular.internal.displaySchema(obj);
+ disp(text + newline);
+ end
- function displayScalarObject(obj)
- disp(obj.toString());
end
end
diff --git a/matlab/test/arrow/tabular/tSchema.m
b/matlab/test/arrow/tabular/tSchema.m
index e4c706d9a3..bb95c1823b 100644
--- a/matlab/test/arrow/tabular/tSchema.m
+++ b/matlab/test/arrow/tabular/tSchema.m
@@ -526,7 +526,70 @@ classdef tSchema < matlab.unittest.TestCase
% Compare schema to double
testCase.verifyFalse(isequal(schema4, 5));
+ end
+
+ function TestDisplaySchemaZeroFields(testCase)
+ import arrow.internal.test.display.makeLinkString
+
+ schema = arrow.schema(arrow.type.Field.empty(0, 0)); %#ok<NASGU>
+ classnameLink =
makeLinkString(FullClassName="arrow.tabular.Schema",...
+ ClassName="Schema", BoldFont=true);
+ expectedDisplay = " Arrow " + classnameLink + " with 0 fields" +
newline;
+ expectedDisplay = char(expectedDisplay + newline);
+ actualDisplay = evalc('disp(schema)');
+ testCase.verifyEqual(actualDisplay, char(expectedDisplay));
+ end
+
+ function TestDisplaySchemaOneField(testCase)
+ import arrow.internal.test.display.makeLinkString
+
+ schema = arrow.schema(arrow.field("TestField", arrow.boolean()));
%#ok<NASGU>
+ classnameLink =
makeLinkString(FullClassName="arrow.tabular.Schema",...
+ ClassName="Schema", BoldFont=true);
+ header = " Arrow " + classnameLink + " with 1 field:" + newline;
+ indent = " ";
+
+ if usejava("desktop")
+ type = makeLinkString(FullClassName="arrow.type.BooleanType",
...
+ ClassName="Boolean", BoldFont=true);
+ name = "<strong>TestField</strong>: ";
+ fieldLine = indent + name + type + newline;
+ else
+ fieldLine = indent + "TestField: Boolean" + newline;
+ end
+ expectedDisplay = join([header, fieldLine], newline);
+ expectedDisplay = char(expectedDisplay + newline);
+ actualDisplay = evalc('disp(schema)');
+ testCase.verifyEqual(actualDisplay, char(expectedDisplay));
+ end
+ function TestDisplaySchemaField(testCase)
+ import arrow.internal.test.display.makeLinkString
+
+ field1 = arrow.field("Field1", arrow.timestamp());
+ field2 = arrow.field("Field2", arrow.string());
+ schema = arrow.schema([field1, field2]); %#ok<NASGU>
+ classnameLink =
makeLinkString(FullClassName="arrow.tabular.Schema",...
+ ClassName="Schema", BoldFont=true);
+ header = " Arrow " + classnameLink + " with 2 fields:" + newline;
+
+ indent = " ";
+ if usejava("desktop")
+ type1 =
makeLinkString(FullClassName="arrow.type.TimestampType", ...
+ ClassName="Timestamp", BoldFont=true);
+ field1String = "<strong>Field1</strong>: " + type1;
+ type2 = makeLinkString(FullClassName="arrow.type.StringType",
...
+ ClassName="String", BoldFont=true);
+ field2String = "<strong>Field2</strong>: " + type2;
+ fieldLine = indent + field1String + " | " + field2String +
newline;
+ else
+ fieldLine = indent + "Field1: Timestamp | Field2: String" +
newline;
+ end
+
+ expectedDisplay = join([header, fieldLine], newline);
+ expectedDisplay = char(expectedDisplay + newline);
+ actualDisplay = evalc('disp(schema)');
+ testCase.verifyEqual(actualDisplay, char(expectedDisplay));
end
end