i need your help. My program reads a M-File which is a recorded Video.
To display each image i use "imagesc", because the image is saved as a 200x200 Matrix with normalized values ranging from 0 to 1.
After reading each image i do some calculus. The Result should be displayed as an overlay to the image(one Point, and one Line). With the code below this works as expected for the first iteration of the loop.
At all further iterations the image is redrawn(which is correct) but the Point and Line is not cleared.
How can i achieve that the plots are cleared when a new image is displayed.
I tried several variations with the "hold" command. But got no success.
Additional question(not that important):
Is it possible to exchange the "plot" commands below with "set"(especially for the Point)?
My program consist of several more Axes Elements which i cut out to keep the example simple. This means my UI is very slow with "plot" commands so i tried to speed it up with "set".
It works quite well, but I'm not sure if a simple Point can be displayed with "set".
Thanks in advance.
function work()
h_figure = figure('Name','MainFig');
hImage.ax = axes('Units', 'Pixels','Position', [50 375 200 200]);
imagesc('Parent',hImage.ax,'CData',zeros(200));
hImage.axc = get(gca, 'Children');
hProfileLeft.ax = axes('Position', [50 200 200 100]);
hProfileLeft.pl = plot(hProfileLeft.ax, 1:200);
for(frame = obj.Startframe:obj.Endframe)
imgIntens= obj.video.A.intens(:,:,frame);
ProfileResult = doSomeCalc(someArgs);
set(hImage.axc, 'CData', imgIntens); % Show Image(200x200 double)
hold(hImage.ax, 'on'); % Using hold so that plot is overlayed
plot(ProfileResult.peaks.x, ProfileResult.peaks.y,'Parent',hImage.ax); % Simple Point
plot(ProfileResult.corridor.left, 1:200, 'Parent',hImage.ax); % Line
set(hProfileLeft.pl,'YData', ProfileResult.trace); % Draw data to different axes
hold(hImage.ax, 'off');
end
end
I encountered the same annoying behavior. For me the conclusion was to manually call cla.
And use line instead of plot, it has more options (especially nice that you can label the lines yourself) and won't delete the plot when called, also returns you the handles. Once you got the handles you can delete them separately.
Related
Quite a simple question but just couldn't find the answer online... I want to visualise a point cloud gathered from a lidar. I can plot the individual frames but wanted to loop them to create a "animation". I know how to do it for normal plots with drawnow but can't get it working with a scatter3. If I simply call scatter3 again like I have done in the commented code then the frame that I am viewing in the scatter plot jumps around with every update (Very uncomfortable). How do i get the scatter3 plot to update to the new points without changing the UI of the scatter ie. Still be able to pan and zoom around the visualised point cloud while it loops through.
EDIT: The file is a rosbag file, I cannot attach it because it is 170MB. The problem doesn't happen when using scatter3 in a loop with a normal array seems to be something with using scatter3 to call a PointCloud2 type file using frame = readMessages(rawBag, i).
EDIT: The problem does not seem to be with the axis limits but rather with the view of the axis within the figure window. When the scatter is initialised it is viewed with the positive x to the right side, positive y out of the screen and positive z upwards, as shown in view 1. Then after a short while it jumps to the second view, where the axis have changed, positive x is now out of the screen, positive y to the right and positive z upwards (both views shown in figures). This makes it not possible to view in a loop as it is constantly switching. So basically how to update the plot without calling scatter3(pointCloudData)?
rawBag = rosbag('jackwalking.bag');
frame = readMessages(rawBag, 1);
scatter3(frame{1});
hold on
for i = 1:length(readMessages(rawBag))
disp(i)
frame = readMessages(rawBag, i);
% UPDATE the 3D Scatter %
% drawnow does not work?
% Currently using:
scatter3(frame{1})
pause(.01)
end
The trick is to not use functions such as scatter or plot in an animation, but instead modify the data in the plot that is already there. These functions always reset axes properties, which is why you see the view reset. When modifying the existing plot, the axes are not affected.
The function scatter3 (as do all plotting functions) returns a handle to the graphics object that renders the plot. In the case of scatter3, this handle has three properties of interest here: XData, YData, and ZData. You can update these properties to change the location of the points:
N = 100;
data = randn(N,3) * 40;
h = scatter3(data(:,1),data(:,2),data(:,3));
for ii = 1:500
data = data + randn(N,3);
set(h,'XData',data(:,1),'YData',data(:,2),'ZData',data(:,3));
drawnow
pause(1/5)
end
The new data can be totally different too, it doesn't even need to contain the same number of points.
But when modifying these three properties, you will see the XLim, YLim and ZLim properties of the axes change. That is, the axes will rescale to accommodate all the data. If you need to prevent this, set the axes' XLimMode, YLimMode and ZLimMode to 'manual':
set(gca,'XLimMode','manual','YLimMode','manual','ZLimMode','manual')
When manually setting the limits, the limit mode is always set to manual.
As far as I understood what you describe as "plots jumpying around", the reason for this are the automatically adjusted x,y,z limits of the scatter3 plot. You can change the XLimMode, YLimMode, ZLimMode behaviour to manual to force the axis to stay fixed. You have to provide initial axes limits, though.
% Mock data, since you haven't provided a data sample
x = randn(200,50);
y = randn(200,50);
z = randn(200,50);
% Plot first frame before loop
HS = scatter3(x(:,1), y(:,1), z(:,1));
hold on
% Provide initial axes limits (adjust to your data)
xlim([-5,5])
ylim([-5,5])
zlim([-5,5])
% Set 'LimModes' to 'manual' to prevent auto resaling of the plot
set(gca, 'XLimMode', 'manual', 'YLimMode', 'manual', 'ZLimMode', 'manual')
for i=2:len(x,2)
scatter3(x(:,i), y(:,i), z(:,i))
pause(1)
end
This yields an "animation" of plots, where you can pan and zoom into the data while continuous points are added in the loop
I am trying to write a relatively simple function which allows me to plot any numbers of figures (previously saved as .fig files) one close to the other.
I have looked for the solution in the website, but it does not work for me.
Moreover, I am almost there with my code, since the outputs are almost what I want: indeed I get the two figures in the right position, but in two separate windows and a third window which is correctly merging the two inputs, but they look weird, with a lower resolution! So I get three outputs in total.
Here is my code, I hope you can help me.
(Try with your own .fig files and check if you also have the three wrong outputs like me).
function SubPlotFig (varargin)
for i = 1:nargin
hf = hgload(varargin{i});
ax(i) = findobj(hf,'Type','axes');
end
hc = figure;
for i = 1:nargin
subplot(1,2,i,ax(i));
copyobj(ax(i),hc);
end
Attachment_1
Attachment_2
When you call hgload, it will open a figure from a .fig file and display it. You are doing this inside of your first loop, so you will see a figure for each of the inputs. The figure that you see is exactly what you saved for each figure.
for i = 1:nargin
hf = hgload(varargin{i}); % <---- Creates a figure
ax(i) = findobj(hf,'Type','axes');
end
In the second loop, you create a subplot for each of the axes within the figures that you just opened. These of course are going to be smaller because you are now putting multiple axes within a figure that is the default size. They aren't really "low resolution", just smaller on the screen. If you want to make them bigger, then you'll want to increase your figure size.
% Create all of the subplots
hc = figure;
for i = 1:nargin
hax = subplot(1,2,i,ax(i));
copyobj(ax(i),hc);
colorbar(hax);
end
% Make sure we are using the jet colormap
colormap(jet)
% Get the current figure position
pos = get(hc, 'Position');
% Double the width since you now have two plots
set(hc, 'Position', [pos(1:2) pos(3)*2, pos(4)])
The problem was the colormap. Now it is solved. Here is the correct code, can be useful for others :)
function SubPlotFig (varargin)
for i = 1:nargin
hf = openfig(varargin{i},'reuse');
cm = colormap;
c(i) = findobj(hf,'Type','Colorbar');
ax(i) = findobj(hf,'Type','Axes');
end
hc = figure;
for i = 1:nargin
subplot(1,2,i,ax(i));
copyobj(ax(i),hc);
colormap(ax(i),cm);
copyobj([c(i),ax(i)],hc);
end
I'm trying to save a figure with a no-default dimension, but I always obtain the default size plot.
figure
for i=1:6
for j=1:4
subplot(6,4,j+(i-1)*4)
[...]
end
end
w=600; h=800;
set(gcf,'Position',[30 60 w h]);
set(gcf, 'PaperUnits', 'centimeters');
set(gcf,'PaperPositionMode','manual')
print('test','-depsc');
It is mainly a 6-by-4 subplot. I looked for a solution on internet, I found many comments about Position, PaperUnits, PaperPositionMode, but none has worked so far. The only solution that works is when I export as .fig.
What I actually realized, is that after the set(gcf,'Position',[30 60 w h]) the window dimension of the plot is correct, but the subplot are squeezed like when the dimension is the default. If I just insert a pause and manually resize the window (even by almost nothing), the subplots expand nicely within the larger window. But still, with the print command the result is not the desired one.
I tried also with saveas and I got the same result.
Ah, if I manually save the figure, it works perfectly, but, of course, I need to automatize the process!
Thanks for your help!
Although i can't reproduce this behaviour as MATLAB 2014b automatically handles axes resizing, i'll still post an answer, that may need some adjustments.
Basically, what you need to do is :
% Get a handle to your figure object
Myfig=gcf;
% Get all of your figure Children - Warning : if you have a global
% legend in your figure, it will belong to your figure Children and you
% ll have to ignore it
AllChildren=get(Myfig,'Children');
MyAxes=findobj(AllChildren,'type','axes');
% Now you have your axes objects, whose Position attributes should be in
% normalized units. What you need to do now is to store these positions
% before changing the size of your figure, to reapply them after
% resizing (the beauty of normalized positions).
Positions=zeros(size(MyAxes,1),4);
for ii=1:size(MyAxes,1)
Positions(ii,:)=get(MyAxes(ii),'Position');
end
% Resize your figure
w=600;
h=800;
set(gcf,'Position',[30 60 w h]);
% Reuse the positions you stored to resize your subplots
for ii=1:size(MyAxes,1)
set(MyAxes(ii),'Position',Positions(ii,:));
end
This should do the trick.
I've got 10 grayscale images. I'd like to plot a simple YELLOW line over each image separately, then show them all over one plot (montage style).
I tried to draw all images first, but that made plotting lines very tricky (X,Y axes weren't standard for plotting over each separate image).
I thought about burning the line over the image, but I don't have the computer vision toolkit (easy functions to do this), otherwise it seemed complicated to both convert the grayscale to color and get it to burn the image.
I thought I might be able to use the function newplot to create a temporary plot space for each image, draw the line with a simple plot(...) call, then save it and just montage(...) all the individual plots at the end.
Is this possible? I've never played with the function newplot or tried to loop through individual plots, saving them up for a call to montage(...) this way, but it seems like a logical/simple approach.
I finally worked it out with subplot, subimage, and plot, using subplot with the position arguments does what I want easily enough. Using subplot kept the axis relative to the subplot I was on so I could plot the line with a standard fplot/plot call. The trick was normalizing the position to percentages vs. thinking of it in terms of pixels.
here's some code demoing it:
% Loop through this code, each time moving the subplot by position
LOOP {
% calculate left & bottom position as percentages (0..1)
subplot( 'Position', [ left bottom (1/cols) (1/rows) ] );
hold on
% (1) Draw the image
subimage(tmpImg, [0 255]);
axis off;
% (2) Plot the line over the original image
F = #(x) polyval(p, x);
fplot(F, [1 dimX 1 dimY], '-y');
}
Suppose that I have 2 figures in MATLAB both of which plot data of size (512x512), however one figure is being plotted by an external program which is sets the axis parameters. The other is being plotted by me (using imagesc). Currently the figures, or rather, the axes are different sizes and my question is, how do I make them equal?.
The reason for my question, is that I would like to export them to pdf format for inclusion in a latex document, and I would like to have them be the same size without further processing.
Thanks in Advance, N
Edit: link to figures
figure 1: (big)
link to smaller figure (i.e. the one whose properties I would like to copy and apply to figure 1)
For this purpose use linkaxes():
% Load some data included with MATLAB
load clown
% Plot a histogram in the first subplot
figure
ax(1) = subplot(211);
hist(X(:),100)
% Create second subplot
ax(2) = subplot(212);
Now link the axes of the two subplots:
linkaxes(ax)
By plotting on the second subplot, the first one will adapt
imagesc(X)
First, you have the following:
Then:
Extending the example to images only:
load clown
figure
imagesc(X)
h(1) = gca;
I = imread('eight.tif');
figure
imagesc(I)
h(2) = gca;
Note that the configurations of the the first handle prevail:
linkaxes(h)
1.Get the handle of your figure and the axes, like this:
%perhaps the easiest way, if you have just this one figure:
myFigHandle=gcf;
myAxHandle=gca;
%if not possible, you have to search for the handles:
myFigHandle=findobj('PropertyName',PropertyValue,...)
%you have to know some property to identify it of course...
%same for the axes!
2.Set the properties, like this:
%set units to pixels (or whatever you prefer to make it easier to compare to the other plot)
set(myFigHandle, 'Units','pixels')
set(myAxHandle, 'Units','pixels')
%set the size:
set(myFigHandle,'Position',[x_0 y_0 width height]) %coordinates on screen!
%set the size of the axes:
set(myAxHandle,'Position',[x_0 y_0 width height]) %coordinates within the figure!
Ok, based on the answer of #Lucius Domitius Ahenoba here is what I came up with:
hgload('fig1.fig'); % figure whose axis properties I would like to copy
hgload('fig2.fig');
figHandles = get(0,'Children');
figHandles = sort(figHandles,1);
ax(1) = findobj(figHandles(1),'type','axes','-not','Tag','legend','-not','Tag','Colorbar');
ax(2) = findobj(figHandles(2),'type','axes','-not','Tag','legend','-not','Tag','Colorbar');
screen_pos1 = get(figHandles(1),'Position');
axis_pos1 = get(ax(1),'Position');
set(figHandles(2),'Position',screen_pos1);
set(ax(2),'Position',axis_pos1);
This is the 'before' result:
and this is the 'after' result:
Almost correct, except that the aspect ratios are still off. Does anybody know how to equalize everything related to the axes? (I realize that I'm not supposed to ask questions when posting answers, however adding the above as a comment was proving a little unwieldy!)