Community Highlights

Community Pick

Adam Danz
907 views (last 30 days)

New in R2021a: Improvements to tiled chart layout

Adam Danz 2021년 3월 24일 (2021년 3월 31일에 수정됨)
Latest activity Edit by Adam Danz 2021년 6월 22일

tiledlayout, introduced in MATLAB R2019b, offers a flexible way to add subplots, or tiles, to a figure.

Reviewing two changes to tiledlayout in MATLAB R2021a

  1. The new TileIndexing property
  2. Changes to TileSpacing and Padding properties

1) TileIndexing

By default, axes within a tiled layout are created from left to right, top to bottom, but sometimes it's better to organize plots column-wise from top to bottom and then left to right. Starting in r2021a, the TileIndexing property of tiledlayout specifies the direction of flow when adding new tiles.

tiledlayout(__,'TileIndexing','rowmajor') creates tiles by row (default).

tiledlayout(__,'TileIndexing','columnmajor') creates tiles by column.

.

2) TileSpacing & Padding changes

Some changes have been made to the spacing properties of tiles created by tiledlayout.

TileSpacing: sets the spacing between tiles.

  • "loose" is the new default and replaces "normal" which is no longer recommended but is still accepted.
  • "tight" replaces "none" and brings the tiles closer together still leaving space for axis ticks and labels.
  • "none" results in tile borders touching, following the true meaning of none.
  • "compact" is unchanged and has slightly more space between tiles than "tight".

Padding: sets the spacing of the figure margins.

  • "loose" is the new default and replaces "normal" which is no longer recommended but is still accepted.
  • "tight" replaces "none" and reduces the figure margins. "none" is no longer recommended but is still accepted.
  • "compact" is unchanged and adds slightly more marginal space than "tight".
  • Reducing the figure margins to a true none is still not an option.

The release notes show a comparison of these properties between r2020b and r2021a.

Here's what the new TileSpacing options (left column of figures below) and Padding options (right column) look like in R2021a. Spacing properties are written in the figure names.

.

And here's a grid of all 12 combinations of the 4 TileSpacing options and 3 Padding options in R2021a.

.

Code used to generate these figures

%% Animate the RowMajor and ColumnMajor indexing with colored tiles 
fig1 = figure('position',[200 200 560 420]); 
tlo1 = tiledlayout(fig1, 3, 3, 'TileIndexing','rowmajor');
title(tlo1, 'RowMajor indexing')
fig2 = figure('position',[760 200 560 420]); 
tlo2 = tiledlayout(fig2, 3, 3, 'TileIndexing','columnmajor');
title(tlo2, 'ColumnMajor indexing')
colors = jet(9);
drawnow()
for i = 1:9
    ax = nexttile(tlo1);
    ax.Color = colors(i,:);
    text(ax, .5, .5, num2str(i), 'Horiz','Cent','Vert','Mid','Fontsize',24)
      ax = nexttile(tlo2);
      ax.Color = colors(i,:);
      text(ax, .5, .5, num2str(i), 'Horiz','Cent','Vert','Mid','Fontsize',24)
      drawnow
      pause(.3)
  end
%% Show TileSpacing options
tileSpacing = ["loose","compact","tight","none"];
figHeight = 140;  % unit: pixels
figPosY = fliplr(50 : figHeight+32 : (figHeight+30)*numel(tileSpacing)); 
for i = 1:numel(tileSpacing)
    uif = uifigure('Units','Pixels','Position', [150 figPosY(i) 580 figHeight], ...
        'Name', ['TileSpacing: ', tileSpacing{i}]);
    tlo = tiledlayout(uif,1,3,'TileSpacing',tileSpacing(i)); 
    h = arrayfun(@(i)nexttile(tlo), 1:tlo.GridSize(2));
    box(h,'on')
    drawnow()
end
%% Show Padding options
padding = ["loose","compact","tight"];
for i = 1:numel(padding)
    uif = uifigure('Units','Pixels','Position', [732 figPosY(i) 580 figHeight], ...
        'Name', ['Padding: ', padding{i}]);
    tlo = tiledlayout(uif,1,3,'Padding',padding(i)); 
    h = arrayfun(@(i)nexttile(tlo), 1:tlo.GridSize(2));
    box(h,'on')
    drawnow()
end
%% Show all combinations of TileSpacing and Padding options
tileSpacing = ["loose","compact","tight","none"];
padding = ["loose","compact","tight"];
[tsIdx, padIdx] = meshgrid(1:numel(tileSpacing), 1:numel(padding));
figSize = [320 220]; % width, height (pixels)
figPosX = 150 + (figSize(1)+2)*(0:numel(tileSpacing)-1); 
figPosY = 50 + (figSize(2)+32)*(0:numel(padding)-1);
[figX, figY] = meshgrid(figPosX, fliplr(figPosY));
for i = 1:numel(padIdx)
    uif = uifigure('Units','pixels','Position',[figX(i), figY(i), figSize], ...
        'name', ['TS: ', tileSpacing{tsIdx(i)}, ', Pad: ', padding{padIdx(i)}]);
    tlo = tiledlayout(uif,2,2,'TileSpacing',tileSpacing(tsIdx(i)),'Padding',padding(padIdx(i))); 
    h = arrayfun(@(i)nexttile(tlo), 1:prod(tlo.GridSize));
    box(h,'on')
    drawnow()
end
 
Adam Danz
Adam Danz 2021년 6월 22일 (2021년 6월 22일에 수정됨)

Notice: Bug using columnmajor indexing with nexttile(tilelocation) syntax (R2021a)

When defining tiledlayout using columnmajor indexing, specifying the tile index using nexttile(tilelocation) results in an error message for some indices:

Error using nexttile
The tile does not fit in the layout.  

This bug does not affect rowmajor indexing and the bug is avoided when using nexttile without indexing.

Example: A 3x4 layout where tiles 4, 8, and 12 produce an error when indexed in nexttile :

fig = figure();
tlo = tiledlayout(3, 4, ...
'TileIndexing', 'ColumnMajor', ...
'Parent',fig);
for i = 1:12
    try
        nexttile(i)
    catch
        fprintf('Error on tile %d\n', i)
    end
end
Error on tile 4
Error on tile 8
Error on tile 12

This bug has been reported (case Number 04933885).

Workarounds

To avoid the bug use columnmajor indexing, here are two workarounds.

1. Specify axes layout after axes are created.

fig = figure();
tlo = tiledlayout(3, 4, ...
'TileIndexing', 'ColumnMajor', ...
'Parent',fig);
ax = axes(tlo);
ax.Layout.Tile = 4;

2. Create all tiles in the grid and remove unneeded tiles.

fig = figure();
tlo = tiledlayout(3, 4, ...
'TileIndexing', 'ColumnMajor', ...
'Parent',fig);
allTileIndices =  1:prod(tlo.GridSize);
ax = arrayfun(@(i) nexttile(tlo), allTileIndices); 
neededTileIndices = [4,8,12];
notNeededTileIndices = setdiff(allTileIndices, neededTileIndices);
delete(ax(notNeededTileIndices))
ax(notNeededTileIndices) = [];
 
Carlos Toro Navarrete
Carlos Toro Navarrete 2021년 3월 24일

This is great, thanks for sharing

 

Community Treasure Hunt

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

Start Hunting!