How to save a figure/plot after annotating?

Hi, i have been trying to google whole day a very simple answer to a basic question but unfortunately i cannot find the answer. My query is very simple. I have a plot and using the tool menu in the figure display window, i drew a rectangle on my plot marking an area of interest. The problem is if i use save as command from file menu, i cannot control the resolution of the saved plot. I tried to use the code generator for the box created and added the line of the code in the plot code and tried saving the figure using print and export_ fig commands but both times, the location was different as compared to the orignal postion in the maxized window.
How can i save the annotated plot in eps format with having the desired resolution.1
for annotation i used this code . In the attachment one can see how the blue box moves after saving it using a command.
annotation(f_stacked,'rectangle',[0.317276041666667 0.508639308855292 0.0172291666666667 0.390928725701941],...
'Color',[0 0 1],...
'LineWidth',3);
set (f_stacked, 'Clipping', 'on');% experimented with it, did not worked

4 个评论

annotation uses normalized coordinates from the figure by default; I think these screw up when exporting the figure.
Try rectangle instead of annotation object; it is drawn in axes units same as the lines are.
I've never really had to try to print/export figures but it seems to have been/continue to be a bane of everybodys' existence that have had to try. TMW just can't seem to solve a lot of similar issues cleanly for some reason...
@arjun luther, when the two previous commenters say stuff, I pay attention because they always give excellent advice.
@William Rose Agree, the stackedplot is not a regular axes into which one plots; I wouldn't be surprised if there are still warts with it that may not show on a regular axes as @arjun luther used for illustration.
@Adam Danz is good, although the link he posted uses only axes figures, not any that are a <standalone visualization object>. With only the laptop at the moment and a pressing deadline, I don't have time to try to explore much at this instant, sorry...

请先登录,再进行评论。

 采纳的回答

Thanks @William Rose for the kind words!
I had time to dig deeper.
Replicating the problem
Start with a default-sized figure. Create a stacked plot and an annotation rectangle placed at x=[1,3]. Note that I'm using the stackedplot position to compute the annotation rectangle position. Don't use undocumented methods to access the axes here.
fig = figure('Position', get(groot,'factoryFigurePosition'));
data = rand(10,5).*[ones(3,1);8*ones(7,1)];
dh = stackedplot(data);
hEdgeData = [1,3]; % horizontal edges of frame in data units
hEdgeNorm = dh.Position(1) + (hEdgeData-min(xlim(dh)))/range(xlim(dh))*dh.Position(3);
hWidth = diff(hEdgeNorm);
ah = annotation('rectangle',[hEdgeNorm(1),dh.Position(2),hWidth,dh.Position(4)],...
'Color', 'r', 'LineWidth', 2, 'LineStyle', '--');
After the stackedplot is rendered, change the figure size to half the width and height
fig = gcf;
fig.Position(3:4) = fig.Position(3:4)./2;
Explanation of the problem
The annotation rectangle is in normalized figure units. When the stackedplot size decreases, its position changes so the annotation rectangle is no longer in the intended position over the stackedplot.
Solution 1: Position constraint
An easy solution is to set the stackedplot's PositionConstraint to innerposition but this comes with a caveat. When the PositionConstrain is set to innerposition, the y axis labels may extend beyond the figure frame when the figure size is reduced.
dh = stackedplot(data);
dh.PositionConstraint = 'innerposition';
This is the result of the problem set above.
Solution 2: Add a listener that updates annotation rectangle upon position change
Whenever the stackedplot OuterPosition is changed, the listener will update the annotation rectangle. Set the figure to the desired size before exporting.
See inline comments for further explanation.
% Create stacked plot
fig = figure;
data = rand(10,5).*[ones(3,1);8*ones(7,1)];
stackHandle = stackedplot(data);
% Add the annotation rectangle but it will be all 0s for now.
annotHandle = annotation('rectangle',zeros(1,4),...
'Color', 'r', 'LineWidth', 2, 'LineStyle', '--');
% Add the listener
fig.UserData.PositionListener = addlistener(stackHandle,'OuterPositionChanged',@(h,evt)updateAnnotationPosition(h,evt,annotHandle));
% Call the listener function to initialize the annotation rectangle
updateAnnotationPosition(stackHandle,[],annotHandle)
function updateAnnotationPosition(stackHandle,~,annotationHandle)
% Update annotation rectangle position when stackedplot position changes.
hEdgeData = [1,3]; % horizontal edges of frame in data units
hEdgeNorm = stackHandle.Position(1) + (hEdgeData-min(xlim(stackHandle)))/range(xlim(stackHandle))*stackHandle.Position(3);
hWidth = diff(hEdgeNorm);
annotationHandle.Position = [hEdgeNorm(1),stackHandle.Position(2),hWidth,stackHandle.Position(4)];
end
Final result:

4 个评论

I said @Adam Danz was good! :)
I've thought for 30 years that builtin functions to do the conversion from figure coordinates to the axis limits positions should be available and well documented how to use them with annotation; as is, all the examples there are black boxes with magic numbers for positions that make no sense just to look at as far as where the objects shown are with respect to the lines drawn on the plot. Why the user has to dig into the bowels of the arcane figure and axes positioning details is another of those real time-wasters that can tie up a user for days trying to get something to look as wanted while the real research/job awaits further actual work...the biggest complaint I had with MATLAB while still actively consulting. The work itself could generally be done very quickly; making something suitable to present to the client beyond the klunky builtin minimal graphics might take several days...and there went the margin on the job.
Hi, thanks for taking out the time and finding a simple solution for the problem. I choose solution #1 due to its simplicity and as@dpb said the main research lacks while we are focused on trying to concentrate on side tasks. Solution #1 is a quick fix without investing much time on the side task
once again thanks for all your efforts and valubale inputs.
Thanks @dpb, your feedback is much appreciated!
Glad to hear you're unstuck, @arjun luther!
As for the final export step, I recommend following @William Rose's advice below. First set the figure to the desired size.
I dunno, but somehow it seems to me that having to write a user callback for something like this just doesn't seem as though the pieces work together natively as they should -- it just seems naturally expected that when one places an annotation on a figure that it should be part of the figure and behave natively the way the callback does.
That the user has to do this level of customization to get such a feature in MATLAB continues to be a real downside in the use of MATLAB for graphics as soon as one gets away from just the canned plots; even adding such seemingly trivial tidbits as this adds up to a lot of wasted time in a hurry; exactly what the system is supposed to be there to prevent.
That it can be done is a plus, but that it takes such a level of familiarity with coding to do so is ... well, "just plain rude!" to quote one of my granddaughter's favorite expressions...

请先登录,再进行评论。

更多回答(1 个)

plot(0:10,0:10,'-rx')
ax=gca;
exportgraphics(ax,'MyFig300.eps','Resolution',300);
After issuing the plot command above, I added a rectangle using Insert -> Rectangle in the figure window. The saved eps file does include the rectangle.
Good luck.

4 个评论

In this example, I use the annotation command, like you did.
plot(0:10,0:10,'-rx'); grid on
annotation('rectangle',[.01 .01 .98 .98],'Color',[0 0 1]);
annotation('rectangle',[.45 .45 .10 .10],'Color',[0 1 0]);
ax=gca;
exportgraphics(ax,'MyFig300.eps','Resolution',300)
The rectangles in the eps file are in the same place as the Matlab plot above. annotate's frame (0 to 1 and 0 to 1) includes areas outside the plot box (axis labels, title area, etc.).
Hi, I tried your method but it doesnt keeps the box in the place. Maybe it has something to do with the amount of data points and the type of plot, i am using.There hasnt been much info regarding stacked plot. When i maximize the output window, i can see the correct position of the box, but in smaller layout window where one can see both the code and output window together, i see that the box is misplaced and upon using the export command it outputs the figure that is shown in layout with mispalced box not the full maximized window with correct position. I also dont understand that, once i create a box using the insert menu in maximized output window, the box disappears when i close it and return to the normal layout window.
[edit: correct spelling]
@dpb says rectangle() uses the units of the quantities being plotted. That is good to know, since it is a lot more convenient to use plot units.
Your sample plot has a rectangle that crosses subplots. This is probably not possible with rectangle(), but you can make such a rectange with annotate().
I have not used stackedplot() much. It works somewhat differently than regular plots, as @dpb noted. If the problem persists, and you really are bothered by it, you could investigate using a loop with subplot(9,1,i) to make 9 subplots. But you will get an x-axis under every plot, which is ugly, unnecessary, and a waste of space. I don't know if the rectangle placement in the eps file would work any better with subplots than it does with stackedplot().
% datetime vector: 8:00, 8:01,...,10:59,11:00, similar to your plot
D=datetime(2023,7,10,8,0:180,0);
t=convertTo(D,'excel');
x=cos(48*pi*t')*ones(1,9);
stackedplot(D,x)
annotation('rectangle',[.35 .47 .04 .46],'Color',[0 1 0],'Linewidth',3);
exportgraphics(gca,'MyFig300.eps','Resolution',300)
The code makes a figure similar to yours: nine stacked plots, plus a rectangle that spans 5 plots. It saves the figure as an eps file with specified resolution. The rectangle in the eps file (atached) looks like it is in the same place as in the Matlab figure.
@William Rose, the point about annotation being able to cross axes boundaries is a good one; hadn't really thought about that the stackedplot is multiple axes even though don't show..

请先登录,再进行评论。

类别

帮助中心File Exchange 中查找有关 Annotations 的更多信息

产品

版本

R2023a

Community Treasure Hunt

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

Start Hunting!

Translated by