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

Reply via email to