Live Script with animation - matlab

MATLAB 2016a introduced Live Scripts, allowing to show plotting output next to the script. Is it somehow possible to show animations? For example, the following code in a regular script will plot a few points and then rotate the axes:
x = rand(10, 3);
plot3(x(:, 1), x(:, 2), x(:, 3), 'o')
for ii = 1:360
camorbit(1, 10*cos(ii/90*pi)*pi/45)
drawnow
pause(0.01)
end
If this is embedded in a Live Script, the initial plot is shown, then seemingly nothing happens while the loop is running, then the last aspect (which is the same as the original plot) is shown in a new display item.
Alternatively, is there an option to interact with the plots in a live script (other than double-clicking to open the plot in a new figure)? E.g. rotate3d does not have an effect.
Edit: As of release 2019a, animations are possible as per release notes.

It seems the answer is no - Live Scripts are too young to be that feature rich yet. The fact alone that they're undebuggable would make me stay away from them for 1-2 versions more.
Have you looked into Matlab Notebooks? If you're after pretty formatting and some basic interactivity, It might be what you seek.

Release 2016b added the option to manipulate axes with controls that come into view when hovering over the axes. Note that this does not work for axes that are invisible (Visible='off'). Instead, the rulers and background have to be hidden:
ax = axes;
x = rand(9, 3);
plot3(ax,x(:, 1), x(:, 2), x(:, 3), 'x');
% Hide rulers and background color
ax.Color = [1 1 1 0];
ax.XAxis.Visible ='off';
ax.YAxis.Visible ='off';
ax.ZAxis.Visible ='off';
Axes arranged with subplot can be manipulated individually as well.

The example code as posted in the question produces a rotating plot as of MATLAB 2019a. It does not work yet in 2018b. The release notes for 2019a mention that
You can enable for-loop animations in the Live Editor to show changes
in plotted data over time. To enable animations in the Live Editor,
set the matlab.editor.AllowFigureAnimations setting to true:
s = settings;
s.matlab.editor.AllowFigureAnimation.PersonalValue = true;
Running these two lines before the example script will yield the expected behaviour.

Related

Matlab saves figure to a very large eps file for seemingly no reason

I use LaTeX for most of my writings and always uses eps files -- that Matlab can create. There wasn't any problem but, for a new case I started studying Matlab generated a 95MB file (and eps2pdf fails to produce a pdf with that)
This question would likely be difficult to answer. It seems like an unexpected Matlab behavior but I cannot share the original code unfortunately (plus the code is very long and depends of so many variables and functions...). I have tried to build a minimum working example using built-in functions but of course it doesn't reproduce the problem. Still, I can give the structure of the code and type of objects created (see end of post): curves, surfaces, transparency, no crazy things.
This code has been running without any problem for many different situations, and gives me files of a few MB. The number of points present in one of the surfac, the approximate shape, the number of points in the curves etc. nothing changes or the changes are minute. I cannot explain the file size difference.
I would welcome either an explanation of the behavior or an alternative for getting this picture to eps. Or both of course. For now I output it to png, but I'd like vector files very much. Has anyone encountered the issue of very large eps before?
colordef white;
figure('Color','White','Name','STUFF')
hold all
% Show a curve
lpot = plot3(//STUFF\\, '-',...
'Color', [0 0 1], 'LineWidth', 2);
% Show a curve
ph = plot3(//STUFF\\,'-',...
'Color', [1 0 0], 'LineWidth', 2);
% Show a curve
plot3(//STUFF\\, '-',...
'Color', [0 1 0], 'LineWidth', 2);
% Show a point
plot3(//STUFF\\, ...
'k', 'MarkerSize', 10, 'Marker', '^', ...
'MarkerFaceColor', [1 1 0]);
% Show a surface
surf(//STUFF\\);
colormap(jet);
shading interp;
% Show a surface in transparency
surf_1 = trisurf(//STUFF\\);
set(surf_1,'FaceColor', [1 1 1], 'EdgeAlpha', 0, 'FaceAlpha', 0.5);
% Axis adjustements
axis equal tight
xlabel('stuff');
ylabel('stuff');
zlabel('stuff');
view(2);
grid on;
h_cbar = colorbar;
ylabel(h_cbar, //STUFF\\);
legend(//STUFF\\,...
{//STUFF\\});
set(gcf,'units','normalized','outerposition',[0.10 0.10 0.80 0.80])
hold off
hgexport(gcf, ['mytoobigfigure.eps'],...
hgexport('factorystyle'), 'Format', 'eps');
The code runs on matlab r2014b, windows 7.
Thanks everyone!
Yay, thanks to Peter comment, I solved the problem! The fix:
myfig = gcf; % or define myfig when the figure is created
myfig.RendererMode = 'manual' % use a set with older versions of Matlab
Which does not mean I understand why this happens and this is most likely not a desired behavior of Matlab. I think that for some reason, the renderer would switch from OpenGL to painters while saving the figure. Examining the eps, it was clear the transparency was very wrong (off in most places) and the polygon offset (or the property that allows to draw line in front of their patches) was also very poor. Whether or not a bitmap was involved, it is beyond my skills to retrieve such an information. But clearly the saved figure was not the same as the displayed figure. It should also be noted that switching the renderer to manual does not affect the picture in any other way on the screen. I wonder if setting the renderer to manual by default would not be a good idea... would there be any drawbacks to forcing OpenGl all the time?
If somebody has a more detailed answer on the topic, I'd be happy to read it.
Go to File -> Export setup -> Rendering -> Custom rendering and change the painters (vector format) to OpenGL (bitmap format) and click on "Apply to figure". Now save the figure in whatever format. Even an eps file is not bigger than a few MB.
This works for me!

Creating annotation boxes for subplots in a for-loop in Matlab

I have the following code in Matlab that runs through a for loop, reads data from a file and plots 9 different figures, that correspond to some particular "channels" in my data, so I decided to annotate them in the for loop.
clear
clc
for i=1:9
subplot(3,3,i);
hold on
x = [4 13]; % from your example
y = ([1 1]); % from your example
y2 = ([-0.4 -0.4]);
H=area(x,y,'LineStyle','none',...
'FaceColor',[1 0.949019610881805 0.866666674613953]);
H1=area(x,y2,'LineStyle','none',...
'FaceColor',[1 0.949019610881805 0.866666674613953]);
% Create textbox
annotation('textbox',...
[0.719849840255583 0.603626943005185 0.176316293929713 0.308290155440411],...
'String',{'FABLIGHT04','Channel',i},...
'FontWeight','bold',...
'FontSize',10,...
'FontName','Geneva',...
'FitBoxToText','off',...
'EdgeColor','none');
axis([0 24 -0.4 1])
set(gca,'XTick',[0:1:24])
set(gca,'YTick',[-0.4:0.2:1])
xlabel('Time (s)');
end
Initially it was giving me 9 different figures and the annotation thing worked fine. But I wanted to be able to tile them onto a subplot for easier comparison.
Since I switched over to using subplot, it does not annotate my figure properly. On opening the editing dock and generating the code, I find that matlab is plotting everything first and then just putting the annotation boxes in the same figure, one on top of the other. Looking at the code it generated, it apparently takes this part of the code:
annotation('textbox',...
[0.719849840255583 0.603626943005185 0.176316293929713 0.308290155440411],...
'String',{'FABLIGHT04','Channel',i},...
'FontWeight','bold',...
'FontSize',10,...
'FontName','Geneva',...
'FitBoxToText','off',...
'EdgeColor','none');
and does it as:
annotation(figure1,'textbox'...)
etc etc
So for all 9 text boxes, it puts them onto the same figure. I tried to do S=subplot(3,3,i) then annotation(S,'textbox') etc etc, I have also tried S(i)=subplot(3,3,i) and then annotation(S,'textbox') etc etc but nothing seems to work.
I have also tried to change the location of the box. I can't seem to figure out how to make it smaller either.
Does anyone know how to have annotation boxes in the right subplot in a for loop?
Thanks
I'm afraid annotation objects are properties of figures and NOT axes, as such its harder to customize the position of each annotation objects because no matter how many subplots you have, they are all part of the same figure and you need to specify their position relatively to the figure coordinate system.
Therefore, you can manually set the position of each text box in your code depending on the subplot it belongs to...
Simple example:
clear
clc
close all
figure('Units','normalized'); %// new figure window
for k = 1:2
str = sprintf('Subplot %d',k);
subplot(1,2,k)
plot(rand(1,10));
%// Customize position here
hAnnot(k) = annotation('textbox', [k*.4-.2 .6 .1 .1],...
'String', str,'FontSize',14);
end
Which looks like this:
Its not very elegant but I'm personally not aware of any other option if you do need to use annotations objects. A less cumbersome alternative would be to use a simple text objects, which are properties of axes and therefore much more friendly to position :)
Hope that helps!

Expand (maximise) subplot figure temporarily — then collapse it back

Often in Matlab we would plot a figure with many subplot axes, but they are all tiny.
In the prevalent UX paradigm, you would expect to be able to double-click such a small plot to have a closer look using the entire screen space.
Typically this is the reason I avoid using subplot, but plot many individual figures instead — so I can move them around on the screen and double-click on their titlebars which (on Windows) maximises the figure to full screen. (Double-click again, and it returns to its normal size.)
However, the advantage of subplot is that the set of plots is grouped in one panel. When I'm plotting many such groups (each with a dozen separate subplot axes), having that many individual figures becomes hard to work with.
So, is there a way to enable this functionality in Matlab already?
Combining parts of these three posts, here's what I have so far:
h = subplot(2,2,1);
line(1:10, rand(1,10));
set(h, 'buttondownfcn', ['h=gca; hc = copyobj(h, gcf);' ...
'set(hc, ''Units'', ''normal'',' ...
' ''Position'', [0.05 0.1 0.8 0.85],' ...
' ''buttondownfcn'', ''delete(gca)'');']);
It's not perfect, but it works.
Click on the axes:
Click on the expanded axes, and it disappears:
Note that this still allows you to pan, zoom, and "rotate 3D" the resulting axes. Selecting the arrow tool actually enters "Edit Mode", so it's better to unselect the tool you are using instead. For example: if you were zooming in, click on the zoom-in icon again to deselect the tool. Clicking will then "collapse" the blow-up of the axes.
The limitation so far is that you can sometimes see parts of the underlying little subplot axes underneath. If someone can recommend an elegant way to hide them, that would be a nice improvement.
EDIT Learning from this answer (using a uipanel to prevent other contents from showing through), I now have turned the solution into this:
gcaExpand.m:
function gcaExpand
set(copyobj(gca, uipanel('Position', [0 0 1 1])), ...
'Units', 'normal', 'OuterPosition', [0 0 1 1], ...
'ButtonDownFcn', 'delete(get(gca, ''Parent''))');
end
gcaExpandable.m:
function gcaExpandable
set(gca, 'ButtonDownFcn', [...
'set(copyobj(gca, uipanel(''Position'', [0 0 1 1])), ' ...
' ''Units'', ''normal'', ''OuterPosition'', [0 0 1 1], ' ...
' ''ButtonDownFcn'', ''delete(get(gca, ''''Parent''''))''); ']);
end
The first one expands the current plot immediately. The second one adds the functionality where clicking onto the plot expands it. In both cases clicking again returns things back to normal.
I've placed them into the directory with all my other custom Matlab functions that I'm using on a day-to-day basis. The above can also be included in functions to be sent out.
Initially, I was going to write a custom version of subplot that applied gcaExpandable automatically, but that didn't work, because commands like plot erase the ButtonDownFcn property (as well as all other properties, except the position). According to this answer, we can avoid resetting those properties by changing the NextPlot to 'replacechildren', but that has side-effects. For example, plot no longer automatically rescales the axes. Therefore, the cleanest solution so far seems to be as above.

Axes background color not rendering properly when exporting videos

Running Matlab R2011b under Linux, I am generating a video using the VideoWriter. My code goes something like this:
h_fig = figure();
set(h_fig, 'Visible', 'on')
set(h_fig, 'Position', [300,200,898,720]);
h_axs = axes('Parent', h_fig);
set(h_axs,'nextplot','replacechildren');
vidObj = VideoWriter('leadfollow3.avi');
...
for i = 1:n
h_axs_a = subplot(3,2,[1 2]);
plot(h_axs_a, x, a_mag_lead, x, a_mag_follow, 'r');
...
The plot is composed of several subplots. The first subplot renders fine, but for the rest, the axes background remains grey instead of white. What's worse, for certain frames it switches to white, leading to annoying flicker in the video (see example video here). Individual plots outside the video writer loop don't display this artifact. What might be the best strategy to troubleshoot this?
Edit: after I got a chance to try this code on Windows, it seems that the problem is restricted to Linux. Nonetheless, I would still very much like to know a possible solution, since I do not have regular access to Windows boxes where I could do my computations.
You missed the crucial lines of code where you actually turn the figure into an image and send it to the VideoWriter, so it's difficult to be of much help. However, if you're not doing so already, I suggest you use export_fig for this task.

Inhibit Matlab Window Focus Stealing

Is there a way to tell Matlab not to steal window focus (from an external editor) such as Emacs) upon graphical commands such as figure and plot. This would increase my productivity a lot because I often want to continue code development during data (re-)processing.
It is possible, the trick is to not use the figure statement, but to change the current figure directly. This will change the active plot without changing the focus. Typically I do something like this:
function change_current_figure(h)
set(0,'CurrentFigure',h)
Then, all of the figure(h) statements need to be changed to change_curent_figure(h).
Note, this is included in the matlab documentation.
It should be noted, this only works if the figure is already created. If new figures are going to be periodically created, one could create the figures as the very first few lines of code, save the handles, do the processing, and then plot to them. This example would work. Note, the drawnow command will flush the event buffer, making sure all figures are plotted.
I've seen this work from 2007-2010, not sure if the latest or earlier versions support this, although I have no reason to suspect they don't.
fig1=figure;
fig2=figure;
drawnow;
[a b]=do_complex_processing;
change_current_figure(fig1)
plot(a);
change_current_figure(fig2)
plot(b);
I've got the same question, with the additional complexity that the code creating figures came from an external supplier, and I didn't want to modify it. Here are two possibilities (identified with the help of MathWorks support) tested on Matlab 2014b:
1. Generate the figures without showing them, then show them after the code completion
set(0, 'DefaultFigureVisible', 'off');
for i = 1:10
fprintf('i: %g\n', i)
figure;
pause(1);
end
set(0, 'DefaultFigureVisible', 'on');
figHandles = findall(0, 'Type', 'figure');
set(figHandles(:), 'visible', 'on')
This code does exactly what's needed, but the added inconvenience is that you cannot see any progress of your code run, thus being unable to interrupt a long run if something goes wrong.
2. Dock the figures
Create a new figure:
figure
Dock it:
This will put the figure into the Matlab IDE window.
Make new figures docked and run the code:
set(0, 'DefaultFigureWindowStyle', 'docked');
for i = 1:10
fprintf('i: %g\n', i)
figure;
pause(1);
end
set(0, 'DefaultFigureWindowStyle', 'normal');