Graphics Objects and Customization

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

Written against MATLAB R2026b. A figure needs a graphical environment, so the MATLAB code on this page was not run here. GNU Octave 11.3.0 was used to check the parent-child structure and the effect of set, findobj and delete; that output is labelled Octave 11.3.0 output. Octave’s graphics handles are plain numbers, whereas MATLAB’s are objects, which the section on dot notation explains; the code that calls set and get runs in both.

Every chart in 2-D Plotting and 3-D Plotting and Surfaces is a tree of graphics objects. Knowing the tree turns the question of how to change a detail of a chart into a question of which object has which property.

Terminology

  • A graphics object is one visual component with properties: a figure, an axes, a line, a text label, a legend.

  • A handle is a reference to a graphics object, returned by the function that created it. Copying a handle does not copy the object. (This is the same idea as a handle class, and graphics objects are in fact handle objects.)

  • The hierarchy is the containment of objects: parents contain children. Parent and Children are properties that hold the links.

  • The root is the single object at the top, the graphics root, returned by groot. Its children are the open figures.

  • A property is a named setting of an object, for example Color, LineWidth, XData. Most properties accept a name-value pair when the object is created.

  • A theme (R2025a) is the light or dark colour scheme of a figure.

The object hierarchy

When you call plot, MATLAB creates (or reuses) a figure, creates (or reuses) an axes inside it and creates a line object inside the axes. An axes is one object that represents the x-, y- and z-axis scales, the tick marks, the tick labels and the axis labels; the labels and the title are objects owned by the axes. The figure also contains objects that are not in the axes, such as a legend, a colorbar, a tiled chart layout or interface components.

graph TD R["Root (groot)"] --> F["Figure"] F --> TL["TiledChartLayout"] F --> LG["Legend"] F --> CB["ColorBar"] TL --> AX["Axes"] F --> AX AX --> LN["Line (plot)"] AX --> SF["Surface (surf)"] AX --> BR["Bar, Scatter, Histogram ..."] AX --> TX["Text (title, labels, text)"]

The same containment can be read from the objects. The Children of an axes hold its lines, the Parent of a line is the axes, and the Parent of an axes is the figure (or a tiled chart layout, which is then the child of the figure).

Octave 11.3.0 (code run as written; the same calls exist in MATLAB):

fig = figure("visible","off");
t = (0:60:600)/60;
T1 = 21 + 1.5*(1-exp(-t/4));
T2 = 21 + 0.9*(1-exp(-t/6));
h = plot(t, T1, "-o", t, T2, "--s");
ax = gca;
fprintf("class(h) = %s, numel(h) = %d\n", class(h), numel(h));
fprintf("type of h(1): %s, type of ax: %s, type of fig: %s\n", get(h(1),"type"), get(ax,"type"), get(fig,"type"));
set(h(1), "LineWidth", 2);
fprintf("LineWidth = %g\n", get(h(1),"LineWidth"));
fprintf("axes is parent of lines: %d\n", isequal(get(h(1),"parent"), ax));
fprintf("figure is parent of axes: %d\n", isequal(get(ax,"parent"), fig));
fprintf("ishghandle(h): %s\n", mat2str(ishghandle(h)'));
fprintf("gca equals ax: %d, gcf equals fig: %d\n", isequal(gca, ax), isequal(gcf, fig));
found = findobj(ax, "Type", "line");
fprintf("findobj lines: %d\n", numel(found));
xlabel("Time (min)"); ylabel("Temperature (degC)");
s = get(get(ax,"xlabel"),"string");
fprintf("xlabel: %s\n", s);
delete(h(2));
fprintf("valid after delete: %s\n", mat2str(ishghandle(h)'));
fprintf("kids of axes: %d\n", numel(get(ax,"children")));
close(fig);

Octave 11.3.0 output (a warning about Octave’s gnuplot toolkit printed first is omitted):

class(h) = double, numel(h) = 2
type of h(1): line, type of ax: axes, type of fig: figure
LineWidth = 2
axes is parent of lines: 1
figure is parent of axes: 1
ishghandle(h): [true true]
gca equals ax: 1, gcf equals fig: 1
findobj lines: 2
xlabel: Time (min)
valid after delete: [true false]
kids of axes: 1

The output confirms the tree: two lines are children of the axes, the axes is a child of the figure, gca and gcf return the objects that were just created, the label is stored on a child object of the axes, and deleting one line leaves its handle in the array but marks it invalid. The first line is where Octave and MATLAB differ: in Octave class(h) is double, in MATLAB it is matlab.graphics.chart.primitive.Line, not run here.

Handles: set, get and dot notation

Every plotting function can return its object or objects. A call with one series returns a scalar; with several series, an array.

h  = plot(t, [T1' T2']);     % h is a 2-by-1 array of Line objects
c  = h(1).Color;             % read a property
h(1).LineWidth = 2;          % set it
h(2).LineStyle = "--";
set(h, "Marker", "o")        % set the same property on every object of an array
ax = gca;
ax.Title.String = "Sensors";          % a property that holds another object
ax.Title.FontWeight = "normal";
v = get(h(1), "YData");               % the older function form

Not run here. In MATLAB, h(1).Color is a 1-by-3 RGB triplet (the documentation shows [0 0.4470 0.7410] for a default line); the default colours of the light theme changed slightly in R2025a, so do not hard-code the value.

The two forms:

  • Dot notation, object.PropertyName, reads a property, object.PropertyName = value sets it, and several dots reach properties of objects held in properties (ax.Title.FontWeight). For a non-scalar variable, index first (h(1).LineStyle). The release that introduced dot notation for graphics objects (R2014b, the release that made handles objects) is not stated on the documentation pages consulted; code that must run before it has to use set and get.

  • set(h,"Name",value) and get(h,"Name") are older. They still work in R2026b, accept an array of handles (set(h,"LineStyle","--") sets all of them), and set(h) or get(h) with one argument lists the properties. The property names in set and get are not case-sensitive, while dot notation is.

  • Name-value pairs at creation are shortest: plot(t,T1,LineWidth=2,Color="r").

With dot notation, end indexing appends to data properties such as XData and YData, which is the basis of the animation below. Ensure the x and y data stay the same size before the next redraw.

A handle is a reference

h  = plot(1:10);
h2 = h;               % a second variable referring to the same line
h2.Color = [1 0 0];   % h.Color is now [1 0 0] too

close gcf             % deletes the figure and its children
isvalid(h)            % false: the variable still exists but the object is gone
h.Color               % error: invalid or deleted object

Not run here. A handle copy does not copy the line, and after the figure is closed every variable that referred to its objects stays in the workspace but is invalid. isvalid(h), isgraphics(h) (R2014b) and ishandle(h) test a handle; delete(h) removes an object, and clf and cla delete the children of a figure or an axes. To copy an object use copyobj.

Finding objects: gcf, gca, groot, findobj

Function Returns

gcf, gca

The current figure and current axes. They create one if none exists. gco is the object under the mouse and gcbo, gcbf are the object and figure whose callback is running.

groot

The root object; groot.Children lists the open figures, and get(groot,"ScreenPixelsPerInch") queries system settings.

findobj(obj,"Type","line")

The objects below obj whose properties match the name-value pairs; without a first argument the search starts at the root. findobj(ax,"DisplayName","S1") finds a named series. findall also finds objects whose HandleVisibility is off.

ancestor(h,"axes")

The nearest ancestor of a given type.

isgraphics(h,"axes")

Whether the variable refers to a valid graphics object of that type.

The earlier Octave output shows findobj returning the two lines of the axes. A common fragment tags a series so that it can be found again and updated:

plot(t, T1, Tag="S1")
line1 = findobj(gca, "Tag", "S1");
line1.LineWidth = 3;

Not run here. findobj returns a handle to the line created with Tag="S1" and the second line widens it.

Customizing a chart

t  = (0:30)';
S1 = 20 + 6.0*(1 - exp(-t/8));

fig = figure;
h = plot(t, S1, "o-", LineWidth=1.5, MarkerSize=5, MarkerFaceColor="auto");
ax = gca;
ax.FontSize = 12;
ax.XGrid = "on";
ax.YGrid = "on";
ax.XLim = [0 30];
ax.YLim = [19 27];
ax.XTick = 0:5:30;
ax.Title.String = "Sensor S1";
ax.XLabel.String = "Time (min)";
ax.YLabel.String = "Temperature (\circ C)";

[~, imax] = max(S1);
text(t(imax), S1(imax), "  maximum", VerticalAlignment="top")
annotation("textarrow", [0.6 0.75], [0.35 0.45], String="settling")

Not run here. The chart shows S1 as a line with circles, a grid, fixed limits, ticks every 5 minutes, a title and labels, a small text label next to the last point and an arrow with the text "settling" in figure coordinates (the two numbers in each pair are normalized positions in the figure, between 0 and 1).

text(x,y,txt) puts text at a data point inside the axes, in data units, and it scales with the axes. annotation draws arrows, lines, ellipses, rectangles and text boxes in the figure, at normalized coordinates, so it does not move with the data; use text, xline or yline for anything that belongs to a data value.

Many properties are common to all objects, and the full lists are the property pages of each object class (Line Properties, Axes Properties, Figure Properties):

Object Frequently used properties

Line

Color, LineStyle, LineWidth, Marker, MarkerSize, MarkerFaceColor, XData, YData, DisplayName, Visible, Tag

Axes

XLim, YLim, XScale, YScale, XTick, XTickLabel, FontSize, Box, XGrid, Title, XLabel, ColorOrder, NextPlot

Figure

Name, Position, Color, Theme, Visible, Units, Children, CurrentAxes

Default values

The root object holds default values that are applied to every object created afterwards. The name of such a property combines default, the object type and the property name.

set(groot, "defaultLineLineWidth", 2)          % all lines created from now on
set(groot, "defaultAxesFontSize", 12)
set(groot, "defaultFigureColor", "w")

plot(1:5)                                       % uses the defaults
set(groot, "defaultLineLineWidth", "remove")    % back to the factory value

Not run here. The chart is drawn with 2-point lines and 12-point axes text. The defaults last for the session; put them in startup.m (see The Search Path, Startup and Files) to keep them. The release notes for R2025a say that some default colours changed; setting the defaults explicitly keeps figures the same across releases.

Figures, tabs and themes

  • The desktop introduced in R2025a (see Desktop and Command Window) opens figures as tabs in the document area. In R2026b, figures created with figure that have a menu bar or a toolbar no longer support docking into the desktop, while uifigure figures still do.

  • Themes (R2025a). A figure is light or dark. theme(fig,"dark"), theme(fig,"light") or theme(fig,"auto") set it, and gt = theme(fig) returns a GraphicsTheme object with the properties Name and BaseColorStyle. By default a figure follows the theme of the desktop, and colours chosen by MATLAB adapt to it (the "gem" palette is the light default, "glow" the dark default). Colours you set explicitly are not changed, so choose them with the theme in mind. exportgraphics takes the background from the theme when it is not set (see Exporting Figures and Images).

  • Since R2025a, the Figure Palette, Plot Browser, Property Editor and plottools were removed or incorporated into the toolstrip, so figurepalette, plotbrowser, propertyeditor, propedit and plottools return an error. Use plot edit mode with the Property Inspector (inspect(h) opens it for an object) instead.

Animation with drawnow

MATLAB redraws graphics when the program is idle, at the end of a command, or when drawnow is called. A loop that changes a property and does not yield shows only the last state. drawnow flushes the queue; drawnow limitrate limits the redraw rate for speed, and pause(s) also yields. Update the properties of an existing object instead of calling plot in each iteration, which would create new objects every time.

The heatflow simulation produces one temperature per step for the sensor at the plate centre. This sketch animates it without a plate solver, using a closed form for the sensor:

nSteps = 60;
h = plot(0, 20, "-o");
xlim([0 nSteps])
ylim([19 27])
xlabel("Step")
ylabel("Temperature (\circ C)")

for k = 1:nSteps
    h.XData(end+1) = k;
    h.YData(end+1) = 20 + 6.0*(1 - exp(-k/16));
    drawnow limitrate
end

Not run here. A line grows from the point (0, 20) and levels near 26 degrees Celsius as the loop runs. Each iteration appends one point to XData and YData of the same object, so the loop does not create new lines, and drawnow limitrate keeps the redraw cost low. The two assignments are consistent in size by the time the redraw happens.

animatedline (R2014b) is built for this: an = animatedline; addpoints(an,x,y); drawnow. It keeps memory bounded with MaximumNumPoints. getframe captures a frame for a movie, and exportgraphics(ax,"file.gif",Append=true) makes a basic animated GIF from charts with the same axes limits (see Exporting Figures and Images).

Common errors and pitfalls

The messages were not run here; the causes are documented behaviour.

  • Using a deleted handle. After close or delete, h.Color raises an error about an invalid or deleted object. Test with isvalid(h) or isgraphics(h) before use.

  • gca and gcf create objects. A script that calls gca after closing all figures opens a new empty figure and axes. Keep your own handles (ax = nexttile, fig = figure) and pass them as the first argument: plot(ax,...), title(ax,...).

  • Setting a property on an array with dot notation. h.Color = "r" fails when h has several elements. Index (h(1).Color), loop, or use set(h,"Color","r").

  • Axes properties revert. With the default NextPlot value of "replace", a new plot call deletes the children and resets most axes properties, such as limits that you had set. Set limits after plotting, or use hold on to keep the axes as they are.

  • Slow animation. Calling plot inside the loop creates and deletes objects. Update XData and YData of one object and call drawnow limitrate.

  • Objects in Octave. An Octave handle is a number: h.LineWidth = 2 is an error there, and code that must run in both systems uses set and get.

  • Property names. set(h,"linewidth",2) works, but h.linewidth does not: dot notation is case-sensitive.

Where older books differ

  • Before R2014b graphics handles were doubles, and every book of that period writes set(h,"Color","r"), get(h,"Children") and gcf as numbers (figure(1) still selects figure 1). The current objects accept both forms, and the type is a class such as matlab.graphics.chart.primitive.Line.

  • Books from before R2014b describe hggroup, uipanel and uicontrol trees; many of the interactive tools they describe were removed or replaced (see the R2025a bullet above).

  • Standalone charts such as heatmap, piechart and donutchart are not axes children: they sit directly in a figure or layout and have their own properties instead of an axes. Newer plotting functions such as boxchart and swarmchart do create objects in an axes. Neither group appears in the older books. Dark themes and the theme function are new in R2025a.

  • Defaults changed in R2014b (new colour order, parula) and in R2025a (new light palette, themes), so screenshots in older books differ from today’s output.