Creating a Flight Tracking Dashboard, Part 3: Using Modular Application Development Principles to Assemble the Dashboard
Are you ready to take your app building skills to the next level? This article walks through an advanced workflow for assembling a flight tracking dashboard. While the techniques covered are targeted for experienced MATLAB developers, they offer a powerful foundation for building scalable, professional-grade applications.
In this article, you'll learn how to:
- Structure your code using the model-view-controller (MVC) design pattern
- Build modular, reusable UI components
- Design a dynamic and customizable frontend using the GUI Layout Toolbox
- Incorporate responsive theme support for light and dark themes
- Package and deploy a dashboard as a standalone app or web app
![]() |
Guest Writer: Ken Deeley
Ken is an application engineer in Cambridge, UK, supporting MathWorks users with their technical computing projects. Ken joined the MathWorks customer training team in 2011 after research work in mathematics with applications to motion planning for autonomous guided vehicle (AGV) robotics. Ken specializes in software development, machine learning, and financial applications, with a particular focus on graphics and app development. He enjoys training MathWorks users on best practices, working with customers on consulting projects, and capturing common customer workflows and requirements to inform future MathWorks development activities.
|
Overview
In the second blog article of this series, we saw how to develop a custom chart to encapsulate the 3D graphics and helper functions used to visualize the aircraft. We also discussed how a similar approach could be used to create a chart showing the current position of the aircraft on its flight route.
In this article, we'll see how to assemble the flight tracking dashboard by developing a series of modular components. First, we'll develop classes to store and organize the flight data. These classes represent the backend of the dashboard. Next, we'll create a series of frontend components for visualizing and manipulating the flight data. This separation of concerns follows the model-view-controller software architecture pattern for application development, explained in more detail in this technical article [1]. We will also make use of the latest release of GUI Layout Toolbox (which is now fully compatible with the JavaScript-based graphics system introduced in R2025a) to help organize the frontend components and allow the end user to configure the dashboard layout (see instructions for Add-Ons to install a toolbox).
Finally, we'll assemble the various components into a dashboard application suitable for sharing with end users, and discuss the options available for deploying the dashboard, focusing on web deployment. By the end of this article, we'll have a fully functional dashboard for tracking flight data running as a web app.
All the code used in this series of blog articles is available on GitHub.

Table of Contents
- Create a storage class for the flight data.
- Create the application data model.
- Define a superclass for implementation of the views and controllers.
- Create views by aggregation with charts.
- Define class hierarchies to simplify view implementation.
- Create a view of the flight path using a geoglobe object.
- Design reusable modular components for use within the views and controllers.
- Use GUI Layout Toolbox layouts to develop a dynamic frontend.
- Provide theme support within the application.
- Assemble the dashboard.
- Deploy the dashboard as a web app.
- Summary
- References
Create a storage class for the flight data.
Our dashboard is designed to display flight data such as the position, altitude, and speed of the aircraft. These variables are all time series, so storing them in a timetable is a natural choice. We've created some (simulated) data representing a 1-hour flight between Glasgow and Stansted airports in the UK.
tt = readtimetable( "FlightPath.csv" );
disp( head( tt ) )
Timetables are flexible and enable us to freely add and remove variables. We will add some derived variables to the timetable, such as the heading, climb rate, and slip. However, if our intention is to deploy an application to end users, we may want to limit the ways in which they can modify the application data, which is not possible using a standard MATLAB data type such as a timetable. On the other hand, using object-oriented programming means that we can provide read-only access to a data set, and guarantee that the timetable contains all the variables required for the application.
We'll create a new class FlightPathData to store the timetable containing the flight data. We handle data input using the class constructor. This takes a filename as input and imports the data using readtimetable.
Note that a FlightPathData object can be constructed without entering a filename. In this case, the object will have empty properties. It's good practice to support zero-input argument syntax for a data storage class, because it means that it's easier to support arrays of objects. For example, we might need an object array if our application supports loading multiple datasets simultaneously.
We construct a FlightPathData object from the file FlightPath.csv containing flight data.
FPD = FlightPathData( "FlightPath.csv" );
Create the application data model.
The FlightPathData class provides data storage. For a modular application such as a dashboard, we also need the ability to maintain state information. Moreover, when the end user interacts with the dashboard controls, we need to notify other parts of the application of any changes. This information sharing is achieved through the use of events and listeners, which also avoids unnecessary coupling between different parts of the application. Since only handle classes can maintain state and issue events, we create a handle class wrapper FlightDashboardModel for our data storage class FlightPathData. The following diagram was generated using MATLAB's Class Diagram Viewer with the FlightPathData and FlightDashboardModel classes and enabling the "Associations" option.

We equip FlightDashboardModel with an import method for loading data from a file, and a reset method for removing the loaded data. We add the property CurrentTime, a scalar datetime value, to represent the state of the application. We equip the model with the events CurrentTimeChanged and FlightDataChanged. For more information about designing a model class, see [1].
Define a superclass for implementation of the views and controllers.
The views and controllers that comprise the dashboard frontend have several things in common. First, they should all have a reference to the model (FlightDashboardModel), so that they can access and modify the application data and state during dashboard operation. Next, to respond dynamically to the model events CurrentTimeChanged and FlightDataChanged, the views and controllers should have listeners with corresponding callback functions onCurrentTimeChanged and onFlightDataChanged. All frontend components must implement these callbacks, but the concrete implementation will necessarily be different between the various views and controllers. We can enforce this behavioral contract by using abstract methods.
MATLAB's ComponentContainer class provides a convenient means to implement frontend components. It equips each view and controller with a container object to hold the required graphics and control objects, provides standard public properties such as Parent, Position, Units, and Visible, and manages the component's lifecycle. On construction, we remove the autoparenting behavior of the component and ensure that it spans its parent by setting the following properties:
- Parent = []
- Units = "normalized"
- Position = [0, 0, 1, 1]
Finally, we note that the R2024b release saw the introduction of weak reference handles. This enables a reference to an object to be created without interfering with the lifecycle of the underlying object. To avoid creating a strong reference cycle in the component via the object reference captured by the listener callback function handle, we create a weak reference to the component and access its Handle property in the callback function. From R2024b onwards, avoiding unnecessary strong reference cycles is the recommended best practice to help improve future code performance.
weakObj = matlab.lang.WeakReference( obj );
obj.FlightDataChangedListener = listener( obj.Model, "FlightDataChanged", @( s, e ) weakObj.Handle.onFlightDataChanged( s, e ) );
obj.CurrentTimeChangedListener = listener( obj.Model, "CurrentTimeChanged", @( s, e ) weakObj.Handle.onCurrentTimeChanged( s, e ) );
See FlightDashboardComponent for full implementation details. This class is the common superclass for all of the dashboard's frontend components.

Create views by aggregation with charts.
In the previous blog article we saw how to encapsulate a related set of graphics objects and functions as a custom chart. We can use charts as standalone objects within scripts and functions, or embed them in a larger application. In this example, we'll create two views by aggregation [2] with charts that were created previously. Specifically,
- AircraftAttitudeView is aggregated with the AircraftChart, and
- MapView is aggregated with the PositionChart.
Creating a view via aggregation with a chart is particularly simple: the view stores a reference to the chart as one of its private properties, and instantiates the chart in its setup method. When the view responds to model events through its implementation of the required listener callbacks, it updates the chart using the chart's public properties or methods.

Define class hierarchies to simplify view implementation.
We can identify two groups of views that share implementation details.
- There are six views that display a specific flight instrument (airspeed, horizon, altitude, turn, heading, and climb rate). These share the same architecture, using a box panel (uix.BoxPanel) from GUI Layout Toolbox, an intermediate grid layout and panel, and a flight instrument component from Aerospace Toolbox.
- There are four views that use a text-based display to show the current value of a variable (time, latitude, longitude, and yaw). These views use the same graphics objects (an axes, rectangle, and text box).
To share common code between multiple classes, we create a class hierarchy. This enables future modifications to the shared code to be made in a single location, rather than having to make the same change across a number of files.
For the first group of views, we define a superclass FlightInstrumentView that contains the shared graphics objects and an abstract property Instrument. It's the responsibility of each subclass to define the appropriate flight instrument (e.g., using uiaeroairspeed or uiaeroaltimeter).

For example, we could create AltitudeView and HorizonView objects within the same layout. We use the uix.HBox component from GUI Layout Toolbox to create a horizontal layout.
FDM = FlightDashboardModel( "FlightPath.csv" );
f = uifigure;
hb = uix.HBox( "Parent", f, "Padding", 5, "Spacing", 5 );
AV = AltitudeView( FDM, "Parent", hb );
HV = HorizonView( FDM, "Parent", hb );
Similarly, for the text-based views, we define a superclass TextAreaView to contain the shared graphics and a helper method updateTextArea that allows subclasses to modify the displayed text in response to model events. In this case, the shared graphics are encapsulated in a reusable component RectangularTextArea that we'll discuss in more detail in a later section.

Create a view of the flight path using a geoglobe object.
In the PositionChart mentioned above, we plot the route and current position of the aircraft using geoplot objects on a geoaxes. These graphics objects are available in base MATLAB. In addition, Mapping Toolbox provides the geoglobe and geoplot3 visualization functions for visualizing lines and points on a 3D globe. We'll use these functions to create the GlobeView class. This provides an interactive view of the aircraft's current position and flight route on the globe, including terrain information.
FDM = FlightDashboardModel( "FlightPath.csv" );
f = uifigure;
GV = GlobeView( FDM, "Parent", f );

If you have access to the Satellite Communication Toolbox, there are additional aircraft assets and map-based visualizations available for tracking applications. Here's an example [3] that shows communication links between an aircraft and a satellite constellation.
The GlobeView class manages the geographic globe and two line objects created using the geoplot3 function. One line object is used to plot the flight route, and the second is used to indicate the current position of the aircraft.

Design reusable modular components for use within the views and controllers.
To maximize code reuse between multiple applications, it's good practice to refactor out modular components (or widgets) from views and controllers when developing the frontend. This avoids individual views and controllers becoming overly long or complicated and means that the same component can be reused within the same app or between different apps.
We've already seen above that charts are good examples of reusable components - in our case, we can use AircraftChart and PositionChart as part of a script or function that we're writing, outside the context of an interactive application.
Two generic widgets in our dashboard are the playback controls for modifying the current time during the simulation, and the rectangular text area for displaying the current value of a flight variable.
The class PlaybackControls creates the first widget. Since this uses user interface control objects, this class is derived from ComponentContainer.
f = uifigure;
g = uigridlayout( f, [1, 1], "Padding", 0 );
PC = PlaybackControls( "Parent", g );
f.Position(4) = 50;
Likewise, the RectangularTextArea class defines the second reusable widget. This widget is reused in the dashboard across the second group of views in the class hierarchies discussed above. Since this widget uses an axes together with some axes children, we derive this class from ChartContainer. For further information about using ChartContainer and ComponentContainer to create modular components, see [4].
f = uifigure;
g = uigridlayout( f, [1, 1], "Padding", 0 );
RTA = RectangularTextArea( "Parent", g, "Value", "Hello world" );
The rectangular text area is composed of an axes object, containing two children: a rectangle and a text box. The playback controls widget comprises play, pause, and stop buttons, with a label to display the current time, a slider to select the current time, and a spinner to control the playback rate.

Use GUI Layout Toolbox layouts to develop a dynamic frontend.
To equip the dashboard with a dynamic interface, we use different layouts from GUI Layout Toolbox to organize the views and controls.
Flexible layouts

Flexible layouts provide draggable dividers between the rows and columns in a grid. Layouts in this category are uix.GridFlex, uix.HBoxFlex, and uix.VBoxFlex.
FDM = FlightDashboardModel();
f = uifigure( "AutoResizeChildren", "off" );
gf = uix.GridFlex( "Parent", f, "Padding", 15, "Spacing", 15 );
V(1) = AirspeedView( FDM, "Parent", gf );
V(2) = TurnView( FDM, "Parent", gf );
V(3) = HorizonView( FDM, "Parent", gf );
V(4) = HeadingView( FDM, "Parent", gf );
V(5) = AltitudeView( FDM, "Parent", gf );
V(6) = ClimbRateView( FDM, "Parent", gf );
gf.Heights = [-1, -1];
Card panels

A card panel (uix.CardPanel) manages a stack of graphics objects, showing one object at a time and hiding the others.
FDM = FlightDashboardModel();
f = uifigure( "AutoResizeChildren", "off" );
TAVD = TextAreaViewDisplay( FDM, "Parent", f );
Box panels

A box panel (uix.BoxPanel) is a decorated standard panel equipped with additional callbacks (MinimizeFcn, HelpFcn, DockFcn, and CloseRequestFcn). Setting these callbacks places button controls in the top right of the title bar. In the flight dashboard we use the MinimizeFcn callback to allow an entire row of flight instruments to be expanded and collapsed.
function boxPanelExample()
FDM = FlightDashboardModel();
f = uifigure( "AutoResizeChildren", "off" );
vb = uix.VBox( "Parent", f );
AltitudeView( FDM, "Parent", vb, "MinimizeFcn", {@onPanelMinimized, 1} );
HorizonView( FDM, "Parent", vb, "MinimizeFcn", {@onPanelMinimized, 2} );
function onPanelMinimized( s, ~, idx )
s.Minimized = ~s.Minimized;
if s.Minimized
vb.Heights(idx) = 22;
else
vb.Heights(idx) = -1;
end % if
end % onPanelMinimized
end % boxPanelExample
Provide theme support within the application.
Support for themes in MATLAB graphics and apps was introduced in R2025a. When designing an application, it's good practice to ensure that the components are responsive to theme changes.
We should ensure theme support at the level of each view and controller, as well as in the application launcher that managers the figure and figure-level controls. In a view or controller, theme support can be achieved by placing theme-responsive code in the update method. This suffices because the update method is called automatically whenever the theme changes.
At the application launcher level, it may be necessary to use the figure's ThemeChangedFcn callback to respond to theme changes. However, by default, the app figure responds automatically to changes in the MATLAB Desktop theme.
For the flight dashboard, we add a toolbar button to toggle between light and dark theme. The corresponding callback is simple: we set the figure's Theme property to either "light" or "dark". The views and controllers then update accordingly.

Assemble the dashboard.
After developing the views and controllers that comprise the dashboard's frontend, the final step is to assemble them in the application launcher. This class has several responsibilities:
- Check for software dependencies (in this case, GUI Layout Toolbox) and issue an alert if these are not installed.
- Create the figure and any figure-level controls such as menus or toolbars.
- Instantiate the model.
- Define the top-level application layout (e.g., using uigridlayout or layouts from GUI Layout Toolbox).
- Create the views and controllers that will be shown when the app starts.
- Implement any menu or toolbar button callbacks.
Deploy the dashboard as a web app.
Using MATLAB Compiler, the dashboard could be deployed to end users as a standalone executable (.exe) or web app (.ctf). MATLAB Web App Server enables enterprise deployment of web apps including authentication.
Since we've built the application programmatically, if we need to deploy the dashboard as a web app, we need to create a simple App Designer wrapper. In App Designer, we create an app file FlightDashboardApp that contains only the figure. In the startup function of the app, we call our application launcher, passing in the figure. We can then create a web app interactively using the Share menu in App Designer, or programmatically using compiler.build.webAppArchive.
Summary
We've provided an overview of how the various components of the flight dashboard have been designed, with an emphasis on code modularity and reuse. We've also discussed how to assemble the dashboard as well as the options for deployment to end users.
References
[1] Developing MATLAB Apps Using the Model-View-Controller Pattern, Laura Dempsey and Ken Deeley (2023).
[2] Object composition, Wikipedia, accessed April 2025.
[4] Creating Specialized Charts with MATLAB Object-Oriented Programming, Ken Deeley and David Sampson (2018).
- Category:
- App Building,
- Demos,
- Graphics
Comments
To leave a comment, please click here to sign in to your MathWorks Account or create a new one.