Change GridSize of existing non empty TiledChartLayout object

Hello all,
I have a question regarding managing tiles layout.
I would like to change the organization of the layout after the tiles have already been created (for instance, for adding or removing a tile).
I thought I could just modify the GridSize property of the TiledChartLayout object after getting its handle.
However, when I try this approach, I get:
"Unable to set GridSize when TiledChartLayout is not empty"
So, it is unclear to me how to actually manage this situation.
Dummy example:
figure;
tl=tiledlayout(1,1); %first step-just one plot
nexttile(1);
plot([1 2 3],[4 5 6],'-o');
Imagine that now, after creating the figure, I would like to add a second tile, organising tiles in 2 rows and one column.
I was thinking I could simply do:
tl.GridSize=[2 1];
nexttile(2)
plot([1 2 3],-[4 5 6],'-s');
but it is not working. I get an error when trying to change the grid size (tl.GridSize=[2 1])
Unable to set GridSize when TiledChartLayout is not empty
If just try to add a new tile without trying to change the grid size (i.e. using directly nexttile(2)), I get the error:
Error using nexttile
The tile does not fit in the layout.
Any suggestion how to manage this?
Thank you,
Gabriele

 채택된 답변

Adam Danz
Adam Danz 2021년 6월 7일
How to change grid layout of tiledlayout in existing figure?
If the tiledlayout was generated with the flow arrangement then simply call nexttile to add new axes.
If the tiledlayout is fixed and the source code is not available or cannot be changed, then you can copy the tiles to a new figure with your desired layout.
Create base figure with 2x2 layout
fig = figure();
tlo = tiledlayout(fig,2,2);
for i = 1:4
nexttile()
x = linspace(-i*pi,i*pi);
plot(x, sin(x).*rand(size(x)))
title(sprintf('Tile %d',i))
xlabel(sprintf('X%d',i))
ylabel(sprintf('Y%d',i))
end
linkaxes
figure(fig) % show figure
Copy tiles to new figure with 3x2 layout and add 1 tile
originalFig is the figure handle to original figure. Get the handle using gcf or when you open the figure using openfig().
originalFig = gcf();
% Get tile (aka axes) handles
ax = flip(findobj(fig,'type','axes'));
% Create new figure with new tile grid
newfig = figure();
tlo = tiledlayout(newfig, 2,3);
% copy existing axes from original figure to new figure
newax = gobjects(tlo.GridSize);
tempax = gobjects(size(ax));
for i = 1:numel(ax)
tempax(i) = nexttile();
newax(i) = copyobj(ax(i),newfig);
set(newax(i), 'units', tempax(i).Units, 'Position', tempax(i).Position)
tempax(i).Visible = 'off';
end
% add new tile
nexttile()
plot(magic(5),'-')
% This is optional but must come after adding additional tiles.
delete(tempax)

추가 답변 (2개)

Gabriele
Gabriele 2021년 6월 7일
Thank you Adam for the suggestion on a workaround.
I do not know if I'm missing something, but I have the feeling the same result can be achieved by changing the Parent of each tile from the old tiledlayout to a new tiledlayout...
%Create basic figure as you did:
fig = figure();
tlo_original = tiledlayout(fig,2,2);
for i = 1:4
nexttile()
x = linspace(-i*pi,i*pi);
plot(x, sin(x).*rand(size(x)))
title(sprintf('Tile %d',i))
xlabel(sprintf('X%d',i))
ylabel(sprintf('Y%d',i))
end
linkaxes
figure(fig) % show figure
%Create a new figure with new layout
fig_new=figure;
tlo_new=tiledlayout(fig_new,3,2);
ax = findobj(fig,'type','axes'); %get handles of original axes in old figure
%change parent to new tiled layout for all axes
for ja=1:numel(ax)
ax(ja).Parent=tlo_new;
end
figure(fig_new);
% add new tile - as you did
nexttile()
plot(magic(5),'-')
Is there anything wrong for later use of the new TiledLayout in just changing the Parent property as I did?

댓글 수: 1

That approach is fine, too. Just don't accidentally over-write the original figure by saving it (assuming the figure was opened). To reduce the chances of that happening you could close the original figure after the loop or, better yet, use onCleanup to close the figure in the event of an error. You might even want to open the figure in invisible mode using openfig(___,visibility).

댓글을 달려면 로그인하십시오.

Scott MacKenzie
Scott MacKenzie 2021년 6월 6일
Try using flow for the grid size...
tiledlayout('flow');
nexttile;
plot([1 2 3],[4 5 6],'-ob');
pause(2);
nexttile;
plot([2 1 3]',[4 5 6]','-dr');
First plot:
After 2 seconds:

댓글 수: 6

Thank you Scott for the suggestion.
This may be a workarond, in principle.
However, from my tests, this require that tiledlayout is set to "flow" from the beginning (creation of first plot).
What if the tiledlayout was created with fixed layout instead of using flow?
I tried to change the TileArrangement property of an existing tiled layout from "fixed" to "flow", but I get an error:
Unable to set the 'TileArrangement' property of class 'TiledChartLayout' because it is read-only.
So, basically, for an existing TiledChartLayout, I'm unable to change GridSize and I'm unable to change TileArrangement.
As a result, if the tiled layout was not created with tiledlayout('flow') originally, I'm unable to add/remove tiles.
I hope this better clarify my issue.
Any suggestion?
Scott MacKenzie
Scott MacKenzie 2021년 6월 6일
편집: Scott MacKenzie 2021년 6월 6일
Hmm, in that case, I'm not sure what to suggest.
BTW, I guess you have a reason for not setting the grid to the final size at the beginning and then just adding plots one by one until the grid is full
thanks for the reply! yes, indeed, there is an underlying reason.
The situation is that graphs are basically ready and need to be updated without re-running the code.
I could craete a new tiled layout with proper grid size, and change the parent of each tile in the old tiled layout to the new tiled layout, but I would prefer to see whether there may be a swifter solution keeping the original tiled layout and updating its properties.
Adam Danz
Adam Danz 2021년 6월 6일
편집: Adam Danz 2021년 6월 6일
Scott's solution to use the flow TileArrangement is the closest you'll get to your goal using TiledLayout. It does everything you're asking for except for controlling the GridSize which is auto-updated every time you add a tile. But, as you've discovered, the tiledLayout must be set to flow before any tiles are added to the figure.
I agree, it would be nice to be able to redefine the grid. You could put in a feature request in the link below.
Since you can't set the position properties of tiled layout axes, you could create the axes with axes() and then write a function that updates their positions as needed. You can change the position properties of subplot too but if one subplot overlaps with another, it deletes the overlapped subplot so using axes is safer.
Thanks Adam for the reply.
I have then to admit that this is actually a non-negligible drawback of using tiledlayout, because it makes modification of already existing figures more complicated than using subplot.
With subplot it is possible to basically resize subplots as needed, even on already existing figures, just using the syntax subplot(m,n,p,ax) for an existing axes ax.
I was hoping to find something similar also for tiledlayout.
Adam Danz
Adam Danz 2021년 6월 7일
편집: Adam Danz 2021년 6월 7일
I would like to be able to redefine the grid size too but I don't think the drawback is as bad as you do.
I've had to reorganize figures like this in the past. There are workarounds. I'll add an answer to share the solution I've used.

댓글을 달려면 로그인하십시오.

카테고리

도움말 센터File Exchange에서 Creating, Deleting, and Querying Graphics Objects에 대해 자세히 알아보기

제품

릴리스

R2021a

질문:

2021년 6월 6일

댓글:

2021년 6월 7일

Community Treasure Hunt

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

Start Hunting!

Translated by