Can uitable display nested tables?

15 次查看(过去 30 天)
Jonathan
Jonathan 2024-1-2
评论: Jonathan 2024-1-10
I am trying to display nested tables in a uifigure using uitable but fail to display the table properly when it contains subtables. An example with the patients dataset from the table examples in the docs, e.g.:
load patients
T1 = table(LastName,Systolic,Diastolic);
T2 = mergevars(T1,{'Systolic','Diastolic'}, ...
'NewVariableName','BloodPressure', ...
'MergeAsTable',true);
% display to show table has nedted table for bloodpressure
head(T2,3)
% display in figure
f=uifigure;
uitable(f, 'Data', T2);
g=uigridlayout(f, 'RowHeight', {'1x'}, 'ColumnWidth', {'1x'});
uitable(g, 'Data', T2);
Unfortunately it seems to output all data in BloodPressure column as { table} instead of the values as displayed in the command window since it looks like this:
uitable not properly displaying nested table
I read through the uitable documentation and fail to see an example with subtables.
Am i trying to achieve something that is not possible?
Is there an alternative I could try?
  3 个评论
Taylor
Taylor 2024-1-2
Yes, it would appear that this is how the nested/sub-tables are being handled by uitable. Removing the "MergeAsTable" input to mergevars remedies the issue (i.e., the values are displayed, not just "1x1 table"). To the end of finding alternatives, what is your ultimate goal with the nested/sub-tables?
Jonathan
Jonathan 2024-1-2
编辑:Jonathan 2024-1-2
I can not share my specific data hence I recreated a similar dataset using the data available from the matlab docs. Ultimately I want to show the labels ("Systolic" and "Diastolic" in this example) of the meged table as well as is shown when using head(T2, 3) in the console window:
Problem with removing the MergeAsTable option is that these headers are not shown. For now I have chosen to use splitvars as a workaround, effectively flattening the nested table while concatenating the labels, e.g. BloodPressure_Systolic, but this is not to my nor my PIs liking.

请先登录,再进行评论。

回答(1 个)

Harsha Vardhan
Harsha Vardhan 2024-1-10
编辑:Harsha Vardhan 2024-1-10
Hi,
I understand that you want to display nested tables in an ‘uitable’ object.
As per the current documented features of ‘uitable’, it is not possible to view the nested table in an ‘uitable’ object as per your requirements. Please refer to the documentation of ‘uitable’ here:
However, as an alternative, you can try to get your desired nested table display using the ‘uihtml’ function. Using this function, you can embed HTML, JavaScript®, or CSS content in your app to display data visualizations.
You can check the documentation of ‘uihtml’ function here.
  1. Create HTML UI component - MATLAB uihtml: https://www.mathworks.com/help/matlab/ref/uihtml.html
  2. Create HTML Content in Apps - MATLAB & Simulink: https://www.mathworks.com/help/matlab/creating_guis/create-an-html-file-that-sets-data-or-responds-to-data-changes-from-matlab.html
Here's a step-by-step guide to create a nested table in MATLAB using 'uihtml':
As a first step, convert the MATLAB table into a structure array and then serializes it into JSON format. This JSON format is then used to pass the table data to an HTML UI component within a MATLAB figure.
You can check this documentation about transferring data from MATLAB to Javascript using the ‘jsonencode’ function : https://www.mathworks.com/help/matlab/ref/jsonencode.html
Please check modified MATLAB code below which passes table data to an HTML UI component within a MATLAB figure.
load patients
T1 = table(LastName,Systolic,Diastolic);
T2 = mergevars(T1,{'Systolic','Diastolic'}, ...
'NewVariableName','BloodPressure', ...
'MergeAsTable',true);
% display to show table has nedted table for bloodpressure
head(T2,3);
% Convert table to struct
dataStruct = table2struct(T2);
% Encode the struct as JSON
jsonData = jsonencode(dataStruct);
% Create UI figure and HTML component
f = uifigure('Name', 'Nested Table Display');
g=uigridlayout(f, 'RowHeight', {'1x'}, 'ColumnWidth', {'1x'});
htmlComponent = uihtml(g, 'HTMLSource', 'nestedTable.html');
htmlComponent.Data = jsonData;
Next, you can follow below steps to create a ‘nestedTable.html’ file as a source for the HTML UI component.
  1. Automated Header Mapping: Extract column names directly from the JSON data's keys to construct table headers.
  2. Nested Content Representation: Identify nested data within the JSON and dynamically create sub-headers and rows.
  3. Responsive Data Integration: Implement a listener for data changes that triggers re-rendering of the table.
You may check the code from ‘nestedTable.html’ below. The same code file 'nestedTable.html’ is also attached inside the zip file (nestedTable.zip) with this answer.
<!DOCTYPE html>
<html>
<head>
<!-- Style definitions for the table -->
<style>
/* Basic styling for the main table */
.main-table {
border-collapse: collapse;
width: 100%;
}
/* Consistent border and padding for all table elements */
.main-table, .main-table th, .main-table td {
border: 1px solid black;
}
/* Padding and text alignment for table headers and cells */
.main-table th, .main-table td {
padding: 5px;
text-align: left;
}
/* Background and text color for the main table headers */
.main-table th {
background-color: #097A7A;
color: white;
}
/* Styling for the headers of the nested table (sub-headers) */
.blood-pressure-header {
background-color: #CCCCCC;
text-align: center;
}
</style>
</head>
<body>
<!-- JavaScript to handle dynamic table creation based on the passed data -->
<script type="text/javascript">
// Setup function that is called when the body loads
function setup(htmlComponent) {
// Event listener for when the data property of the component changes
htmlComponent.addEventListener("DataChanged", function(event) {
// Parse the data from the HTML component which is in JSON format
var data = JSON.parse(htmlComponent.Data);
// Call the function to create a nested table with the parsed data
createNestedTable(data);
});
}
// Function to create a nested table dynamically based on the data
function createNestedTable(data) {
// Create the main table element and set its class
var mainTable = document.createElement('table');
mainTable.className = 'main-table';
// Create the header for the main table
var thead = mainTable.createTHead();
var headerRow = thead.insertRow();
// Get the keys from the first item in the data array, which are the column names
var keys = Object.keys(data[0]);
// Iterate over the keys to create the header cells
keys.forEach(function(key) {
// Create a header cell and set its text
var th = document.createElement('th');
th.innerText = key;
// If the key is an array, it's a nested object, set colspan accordingly
if (data[0][key] instanceof Array) {
// Determine the number of subkeys for the nested object
var subKeys = Object.keys(data[0][key][0]);
// Set the colspan attribute to the number of subkeys
th.colSpan = subKeys.length;
th.style.textAlign = "center";
headerRow.appendChild(th);
// Create a separate header row for the nested table sub-headers
var subHeaderRow = thead.insertRow();
// Create sub-header cells for each subkey
subKeys.forEach(function(subKey) {
var subTh = document.createElement('th');
subTh.className = 'blood-pressure-header';
subTh.innerText = subKey;
subHeaderRow.appendChild(subTh);
});
} else {
// If it's not a nested object, just add the header cell
th.rowSpan = "2";
headerRow.appendChild(th);
}
});
// Create the table body
var tbody = mainTable.createTBody();
// Iterate over the data items to create each row
data.forEach(function(patient) {
// Create a row for each patient
var row = tbody.insertRow();
// Iterate over the keys again to create cells for each data point
keys.forEach(function(key) {
// If the data point is an array, it's the nested object
if (patient[key] instanceof Array) {
// Get the nested data object and create a cell for each subkey
var nestedData = patient[key][0];
var nestedKeys = Object.keys(nestedData);
nestedKeys.forEach(function(nestedKey) {
var cell = row.insertCell();
cell.innerText = nestedData[nestedKey];
});
} else {
// If it's not a nested object, create a cell and set its text
var cell = row.insertCell();
cell.innerText = patient[key];
}
});
});
// Add the complete table to the body of the document
document.body.appendChild(mainTable);
}
</script>
<!-- This body tag calls the setup function when the window's HTML component is loaded -->
<body onload="setup(window.htmlComponent)">
<!-- The nested table will be dynamically created inside this body tag -->
</body>
</html>
Next, when the above modified MATLAB code is executed, it gives us the required nested table display as seen in the below image.
Please note that if your data includes multiple levels of nested sub tables, you may need to tailor the HTML and JavaScript code accordingly. If you face any issues while displaying HTML content in the App, please refer to this documentation about debugging it : https://www.mathworks.com/help/matlab/creating_guis/debug-html-content-in-apps.html .
Hope this helps in solving your query!
  1 个评论
Jonathan
Jonathan 2024-1-10
This seems promissing as a suitable workaround, will try and report back.

请先登录,再进行评论。

产品


版本

R2023b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by