Customizing uifigures part 2 - Undocumented Matlab (2024)

I would like to introduce guest blogger Iliya Romm of Israel’s Technion Turbomachinery and Heat Transfer Laboratory. Today Iliya will discuss how Matlab’s new web-based figures can be customized with user-controlled CSS and JavaScript code.
When we compare the documented properties of a “classic” uicontrol with an App Designer control such as uicheckbox, we see lists of 42 and 15 properties, respectively. At first glance, this implies that our ability to customize App Designer elements is relatively very limited. This is surely a disquieting conclusion, especially for those used to being able to change most aspect of their Matlab figures via Java. Fortunately, such a conclusion is quite far from reality, as we will shortly see.
To understand this claim, we need to consider a previous post on this blog, where Yair discussed how uifigures are actually HTML webpages rendered by Matlab. As such, they have a DOM that can be accessed and manipulated through JavaScript commands to achieve various visual customizations. Today we’ll explore the structure of the uifigure webpage; take a look at some possibilities provided by the Dojo Toolkit; and see how to use Dojo to customize uifigure controls visually using CSS styles and/or HTML attributes.


User customizations of Matlab uifigures (click to zoom-in)

A brief introduction to CSS

CSS stands for Cascading Style Sheets. As described on the official webpage of W3C (which governs web standards):

CSS is the language for describing the presentation of Web pages, including colors, layout, and fonts. CSS is independent of HTML. This is referred to as the separation of structure (or: content) from presentation.

CSS rules (or “styles”) can be defined in one of three places:

  • A separate file, such as the main.css that Matlab uses for uifigures (this file is found minified in %matlabroot%\toolbox\matlab\uitools\uifigureappjs\release\gbtclient\css)
  • An inline block inside the HTML’s <head> section
  • Directly within a DOM node

Deciding which of the above to use, is largely a choice of the right tool for the job. Usually, the first two choices should be preferred, as they adhere to the “separation of structure and presentation” idea better. However, in the scope of this demonstration, we’ll be using mostly the 3rd option, because it allows us not to worry about possible CSS precedence issues (suggested read).
The syntax of CSS is generally: selector { property: value }, but it can have other forms as well.

Getting down to business

Let us consider a very basic uifigure that only contains a uitextarea and its label:

Customizing uifigures part 2 - Undocumented Matlab (2)

The auto-generated code for it is:

classdef DOMdemo < matlab.apps.AppBase % Properties that correspond to app components properties (Access = public) UIFigure matlab.ui.Figure % UI Figure LabelTextArea matlab.ui.control.Label % Text Area TextArea matlab.ui.control.TextArea % This is some text. end methods (Access = private) % Code that executes after component creation function startupFcn(app) end end % App initialization and construction methods (Access = private) % Create UIFigure and components function createComponents(app) % Create UIFigure app.UIFigure = uifigure; app.UIFigure.Position = [100 100 280 102]; app.UIFigure.Name = 'UI Figure'; setAutoResize(app, app.UIFigure, true) % Create LabelTextArea app.LabelTextArea = uilabel(app.UIFigure); app.LabelTextArea.HorizontalAlignment = 'right'; app.LabelTextArea.Position = [16 73 62 15]; app.LabelTextArea.Text = 'Text Area'; % Create TextArea app.TextArea = uitextarea(app.UIFigure); app.TextArea.Position = [116 14 151 60]; app.TextArea.Value = {'This is some text.'}; end end methods (Access = public) % Construct app function app = DOMdemo() % Create and configure components createComponents(app) % Register the app with App Designer registerApp(app, app.UIFigure) % Execute the startup function runStartupFcn(app, @startupFcn) if nargout == 0 clear app end end % Code that executes before app deletion function delete(app) % Delete UIFigure when app is deleted delete(app.UIFigure) end endend

Let’s say we want to modify certain aspects of the TextArea widget, such as the text color, background, and/or horizontal alignment. The workflow for styling elements involves:

  1. Find the handle to the webfigure
  2. Find the DOM node we want to modify
  3. Find the property name that corresponds to the change we want
  4. Find a way to manipulate the desired node from Matlab

Step 1: Find the handle to the webfigure

The first thing we need to do is to strategically place a bit of code that would allow us to get the URL of the figure so we can inspect it in our browser:

function startupFcn(app) % Customizations (aka "MAGIC GOES HERE"): warning off Matlab:HandleGraphics:ObsoletedProperty:JavaFrame warning off Matlab:structOnObject while true try win = struct(struct(struct(app).UIFigure).Controller).Container.CEF; disp(win.URL); break catch disp('Not ready yet!'); pause(0.5); % Give the figure (webpage) some more time to load end endend

This code waits until the page is sufficiently loaded, and then retrieve its local address (URL). The result will be something like this, which can be directly opened in any browser (outside Matlab):

http://localhost:31415/toolbox/matlab/uitools/uifigureappjs/componentContainer.html?channel=/uicontainer/861ef484-534e-4a50-993e-6d00bdba73a5&snc=88E96E

Step 2: Find the DOM node that corresponds to the component that we want to modify

Loading this URL in an external browser (e.g., Chrome, Firefox or IE/Edge) enables us to use web-development addins (e.g., FireBug) to inspect the page contents (source-code).

Note: in recent Matlab releases, the URL cannot be directly opened in a browser unless we first set Matlab to enable this (thanks to Perttu). We can turn on such browser debugging by running:

matlab.internal.webwindow(' ', 'DebugPort',4040) %note: the space is important!

before any other App, or kill all MatlabWindow processes (from the operating system’s task manager) before running the command. Then browse http://localhost:4040/ in your browser – this will display a list of links, one link for each uifigure, based on the uifigure’s title (name); click the requested uifigure’s link to see and debug the figure’s HTML/CSS contents.

Opening the URL inside a browser and inspecting the page contents, we can see its DOM:


Inspecting the DOM in Firefox (click to zoom-in)

Notice the three data-tag entries marked by red frames. Any idea why there are exactly three nonempty tags like that? This is because our App Designer object, app, contains 3 declared children, as defined in:

createComponents(app): app.UIFigure = uifigure; app.LabelTextArea = uilabel(app.UIFigure); app.TextArea = uitextarea(app.UIFigure);

… and each of them is assigned a random hexadecimal id whenever the app is opened.
Finding the relevant node involved some trial-and-error, but after doing it several times I seem to have found a consistent pattern that can be used to our advantage. Apparently, the nodes with data-tag are always above the element we want to style, sometimes as a direct parent and sometimes farther away. So why do we even need to bother with choosing more accurate nodes than these “tagged” ones? Shouldn’t styles applied to the tagged nodes cascade down to the element we care about? Sure, sometimes it works like that, but we want to do better than “sometimes”. To that end, we would like to select as relevant a node as possible.
Anyway, the next step in the program is to find the data-tag that corresponds to the selected component. Luckily, there is a direct (undocumented) way to get it:

% Determine the data-tag of the DOM component that we want to modify:hComponent = app.TextArea; % handle to the component that we want to modifydata_tag = char(struct(hComponent).Controller.ProxyView.PeerNode.getId); % this part is generic: can be used with any web-based GUI component

Let’s take a look at the elements marked with blue and green borders (in that order) in the DOM screenshot. We see that the data-tag property is exactly one level above these elements, in other words, the first child of the tagged node is an element that contains a widgetid property. This property is very important, as it contains the id of the node that we actually want to change. Think pointers. To summarize this part:

data-tag => widgetid => widget “handle”

We shall use this transformation in Step 4 below.
I wanted to start with the blue-outlined element as it demonstrates this structure using distinct elements. The green-outlined element is slightly strange, as it contains a widgetid that points back to itself. Since this obeys the same algorithm, it’s not a problem.

Step 3: Find the CSS property name that corresponds to the change we want

There is no trick here: it’s just a matter of going through a list of CSS properties and choosing one that “sounds about right” (there are often several ways to achieve the same visual result with CSS). After we choose the relevant properties, we need to convert them to camelCase as per documentation of dojo.style():

If the CSS style property is hyphenated, the JavaScript property is camelCased. For example: “font-size” becomes “fontSize”, and so on.

Note that Matlab R2016a comes bundled with Dojo v1.10.4, rev. f4fef70 (January 11 2015). Other Matlab releases will probably come with other Dojo versions. They will never be the latest version of Dojo, but rather a version that is 1-2 years old. We should keep this in mind when searching the Dojo documentation. We can get the current Dojo version as follows:

>> f=uifigure; drawnow; dojoVersion = matlab.internal.webwindowmanager.instance.windowList(1).executeJS('dojo.version'), delete(f)dojoVersion ={"major":1,"minor":10,"patch":4,"flag":"","revision":"f4fef70"}

This tells us that Dojo 1.10.4.f4fef70 is the currently-used version. We can use this information to browse the relevant documentation branch, as well as possibly use different Dojo functions/features.

Step 4: Manipulate the desired element from Matlab

In this demo, we’ll use a combination of several commands:

  • {matlab.internal.webwindow.}executeJS() – For sending JS commands to the uifigure.
  • dojo.query() – for finding nodes inside the DOM.
  • dojo.style() (deprecated since v1.8) – for applying styles to the required nodes of the DOM.
    Syntax: dojo.style(node, style, value);
  • dojo.setAttr (deprecated since v1.8) – for setting some non-style attributes.
    Syntax: dojo.setAttr(node, name, value);

Consider the following JS commands:

  • search the DOM for nodes having a data-tag attribute having the specified value, take their first child of type <div>, and return the value of this child’s widgetid attribute:
    ['dojo.getAttr(dojo.query("[data-tag^=''' data_tag '''] > div")[0],"widgetid")']
  • search the DOM for nodes with id of widgetid, then take the first element of the result and set its text alignment:
    ['dojo.style(dojo.query("#' widgetId(2:end-1) '")[0],"textAlign","center")']
  • append the CSS style defined by {SOME CSS STYLE} to the page (this style can later be used by nodes):
    ['document.head.innerHTML += ''<style>{SOME CSS STYLE}</style>''']);

Putting it all together

It should finally be possible to understand the code that appears in the animated screenshot at the top of this post:

%% 1. Get a handle to the webwindow:win = struct(struct(struct(app).UIFigure).Controller).Container.CEF;%% 2. Find which element of the DOM we want to edit (as before):data_tag = char(struct(app.TextArea).Controller.ProxyView.PeerNode.getId);%% 3. Manipulate the DOM via a JS command% ^ always references a class="vc-widget" element.widgetId = win.executeJS(['dojo.getAttr(dojo.query("[data-tag^=''' data_tag '''] > div")[0],"widgetid")']);% Change font weight:dojo_style_prefix = ['dojo.style(dojo.query("#' widgetId(2:end-1) '")[0],'];win.executeJS([dojo_style_prefix '"fontWeight","900")']);% Change font color:win.executeJS([dojo_style_prefix '"color","yellow")']);% Add an inline css to the HTML <head>:win.executeJS(['document.head.innerHTML += ''<style>'... '@-webkit-keyframes mymove {50% {background-color: blue;}}'... '@keyframes mymove {50% {background-color: blue;}}</style>''']);% Add animation to control:win.executeJS([dojo_style_prefix '"-webkit-animation","mymove 5s infinite")']);% Change Dojo theme:win.executeJS('dojo.setAttr(document.body,''class'',''nihilo'')[0]');% Center text:win.executeJS([dojo_style_prefix '"textAlign","center")']);

A similar method for center-aligning the items in a uilistbox is described here (using a CSS text-align directive).
The only thing we need to ensure before running code that manipulates the DOM, is that the page is fully loaded. The easiest way is to include a pause() of several seconds right after the createComponents(app) function (this will not interfere with the creation of the uifigure, as it happens on a different thread). I have been experimenting with another method involving webwindow‘s PageLoadFinishedCallback callback, but haven’t found anything elegant yet.

A few words of caution

In this demonstration, we invoked Dojo functions via the webwindow’s JS interface. For something like this to be possible, there has to exist some form of “bridge” that translates Matlab commands to JS commands issued to the browser and control the DOM. We also know that this bridge has to be bi-directional, because binding Matlab callbacks to uifigure actions (e.g. ButtonPushFcn for uibuttons) is a documented feature.
The extent to which the bridge might allow malicious code to control the Matlab process needs to be investigated. Until then, the ability of webwindows to execute arbitrary JS code should be considered a known vulnerability. For more information, see XSS and related vulnerabilities.

Final remarks

It should be clear now that there are actually lots of possibilities afforded by the new uifigures for user customizations. One would hope that future Matlab releases will expose easier and more robust hooks for CSS/JS customizations of uifigure contents. But until that time arrives (if ever), we can make do with the mechanism shown above.
Readers are welcome to visit the GitHub project dedicated to manipulating uifigures using the methods discussed in this post. Feel free to comment, suggest improvements and ideas, and of course submit some pull requests 🙂
p.s. – it turns out that uifigures can also display MathML. But this is a topic for another post…

Related posts:

  1. Customizing uifigures part 3 As I have repeatedly posted in recent years, Matlab is advancing towards web-based GUI. The basic underlying technology is more-or-less stable: an HTML/Javascript webpage that is created-on-the-fly and rendered in a stripped-down browser window (based on Chromium-based jxBrowser in recent...
  2. Customizing uifigures part 1 Matlab's new web-based uifigures can be customized in a variety of undocumented ways. ...
  3. Customizing web-GUI uipanel We can customize Matlab's new web-based GUI panels in many interesting ways. Here's how... ...
  4. Matlab callbacks for uifigure JavaScript events Matlab callback code can be attached to JavaScript events in web-based uifigures. ...
  5. Customizing help popup contents The built-in HelpPopup, available since Matlab R2007b, has a back-door that enables displaying arbitrary text, HTML and URL web-pages....
  6. Customizing uitree nodes – part 1 This article describes how to customize specific nodes of Matlab GUI tree controls created using the undocumented uitree function...
Customizing uifigures part 2 - Undocumented Matlab (2024)

FAQs

What is uifigure in Matlab? ›

The uifigure function creates a figure that is specially configured for app building and serves as the container for your user interface. UI figures support the same types of modern graphics and interactive UI components that App Designer supports.

How to create a button in Matlab? ›

btn = uibutton( parent ) creates a button in the specified parent container. The parent can be a figure created using the uifigure function or one of its child containers. btn = uibutton( style ) creates a button of the specified style.

How do I make MATLAB Uifigure full screen? ›

Pressing Ctrl+F11 (Windows® and Linux®) or Ctrl+Command+F (macOS) toggles the 'fullscreen' state. Setting this property on a docked figure or in MATLAB Online™ is not supported. UI figures cannot be minimized directly from a full screen state.

How to detect image in MATLAB? ›

  1. Generate Code for Detecting Objects in Images by Using ACF Object Detector.
  2. Design the MATLAB Code File for Code Generation.
  3. Create ACF Stop Sign Detector Outside of the MATLAB Function.
  4. Generate C-MEX Function.
  5. Detect Objects Using Generated C-MEX Function.
  6. Clean Up.
  7. See Also.

How to create MATLAB code? ›

You can create a new script in the following ways:
  1. Highlight commands from the Command History, right-click, and select Create Script.
  2. On the Home tab, click the New Script button.
  3. Use the edit function. For example, edit new_file_name creates (if the file does not exist) and opens the file new_file_name .

How to create a control system in MATLAB? ›

Open Control System Designer with the specified plant. On the Control System tab, you can select a compensator tuning method, and create response plots for analyzing your controller performance. You can also store, compare, and export different control system designs.

How to create a tool in MATLAB? ›

Create Toolbox
  1. In the Environment section of the Home tab, select Package Toolbox from the Add-Ons menu.
  2. In the Package a Toolbox dialog box, click the. ...
  3. In the dialog box, add the following information about your toolbox. ...
  4. To ensure MATLAB detects the expected components, review the toolbox contents. ...
  5. Package your toolbox.

How to plot on UI axes in MATLAB? ›

Create Plots in UI Axes

Create a figure window with UI axes and assign the UIAxes object to the variable ax . Add a line plot to the axes by specifying the UIAxes object as the first input argument for the plot function. Set the hold state on and add a scatter plot.

What is MATLAB app designer? ›

App Designer is an interactive development environment for designing an app layout and programming its behavior. It provides a fully integrated version of the MATLAB® Editor and a large set of interactive UI components.

What is imread in MATLAB mean? ›

Description. example. A = imread( filename ) reads the image from the file specified by filename , inferring the format of the file from its contents. If filename is a multi-image file, then imread reads the first image in the file.

What is FCN in MATLAB? ›

The Fcn block applies the specified mathematical expression to its input. The expression can include one or more of these components: u — The input to the block. If u is a vector, u(i) represents the ithe element of the vector; u(1) or u alone represents the first element.

Top Articles
Latest Posts
Article information

Author: Jeremiah Abshire

Last Updated:

Views: 5824

Rating: 4.3 / 5 (74 voted)

Reviews: 81% of readers found this page helpful

Author information

Name: Jeremiah Abshire

Birthday: 1993-09-14

Address: Apt. 425 92748 Jannie Centers, Port Nikitaville, VT 82110

Phone: +8096210939894

Job: Lead Healthcare Manager

Hobby: Watching movies, Watching movies, Knapping, LARPing, Coffee roasting, Lacemaking, Gaming

Introduction: My name is Jeremiah Abshire, I am a outstanding, kind, clever, hilarious, curious, hilarious, outstanding person who loves writing and wants to share my knowledge and understanding with you.