Related
The following code plots a figure. The code should work on Matlab >= R2014b. I want to remove the space within the legend. How to do this?
x = 0:0.5:10;
figure; hold on;
plot(x,sin(x), 'Marker', 'o');
plot(x,cos(x), 'Marker', 's');
[leg, objs] = legend({'sin', 'cos'}, 'Location', 'SouthWest');
line_start_end = [0.01, 0.4];
line_text_step = 0.01;
% for each line, text object, adjust their position in legend
for i = 1:numel(objs)
if strcmp(get(objs(i), 'Type'), 'line')
% line object
if 2 == numel(get(objs(i), 'XData')) % line
set(objs(i), 'XData', line_start_end);
else % marker on line
set(objs(i), 'XData', sum(line_start_end)/2);
end
else
%text object
text_pos = get(objs(i), 'Position');
text_pos(1) = line_start_end(2) + line_text_step;
set(objs(i), 'Position', text_pos);
end
end
See the following result:
What I want is :
There is a submission named resizeLegend by David J. Mack on File Exchange that does exactly that.
You can replace your loop with just this line:
resizeLegend();
which gives:
As #Sardar Usama suggested, I put my solution here. I hope it is useful for you.
The first answer is nice. However, I finally use the following code to do this task.
close all
x = 0:0.5:10;
figure; hold on;
ph(1) = plot(x,sin(x), 'Marker', 'o');
ph(2) = plot(x,cos(x), 'Marker', 's');
ax = gca;
ax.Box = 'on';
bx = axes('position', [ax.Position(1:2), 0.3, 0.4], 'Box', 'on', 'XTick', [], 'YTick', []);%, 'Color', [0.8549,0.7020,1.0000]);
cx = axes('position', [ax.Position(1:2), 0.3, 0.4], 'Box', 'on', 'XTick', [], 'YTick', []);%, 'Color', [0.8549,0.5020,1.0000]);
[legb, objsb] = legend(bx, ph, {'sin', 'cos'}, 'Location', 'SouthWest');
[legc, objsc] = legend(cx, ph, {'sin', 'cos'}, 'Location', 'SouthWest');
line_start_end = [0.01, 0.3];
line_text_step = 0.05;
legendshrink(ax.Position(1:2), legb, objsb, bx, line_start_end, line_text_step);
legendshrink(ax.Position(1:2), legc, objsc, cx, line_start_end, line_text_step);
% you need only to adjust cx' position.
cx.Position(1:2) = [ax.Position(1)+ax.Position(3)-cx.Position(3), ax.Position(2)];
legc.Position(1:2) = cx.Position(1:2);
where legendshrink is defined as:
function legendshrink(leg_pos_xy, leg, objs, bx, line_start_end, line_text_step)
% leg_post_xy = ax.Position(1:2);
% [leg, objs] = legend(bx, line_handles, text_cell);
% line_start_end = [0.01, 0.4];
% line_text_step = 0.01;
% for each line, text object, adjust their position in legend
for i = 1:numel(objs)
if strcmp(get(objs(i), 'Type'), 'line')
% line object
if 2 == numel(get(objs(i), 'XData')) % line
set(objs(i), 'XData', line_start_end);
else % marker on line
set(objs(i), 'XData', sum(line_start_end)/2);
end
else
%text object
text_pos = get(objs(i), 'Position');
text_pos(1) = line_start_end(2) + line_text_step;
set(objs(i), 'Position', text_pos);
end
end
% get minimum possible width and height
legend_width_no_right = 0;
for i = 1:numel(objs)
% legend margin left
if strcmp(get(objs(i), 'Type'), 'line')
if numel(get(objs(i), 'XData')) == 2
leg_margin_x = get(objs(i), 'XData');
leg_margin_x = leg_margin_x(1)*leg.Position(3);
end
else
cur_right = get(objs(i), 'Extent');
cur_right = (cur_right(1)+cur_right(3))*leg.Position(3);
if cur_right > legend_width_no_right
legend_width_no_right = cur_right;
end
end
end
legend_width = legend_width_no_right + leg_margin_x;
legend_height = leg.Position(4);
bx.Position = [leg_pos_xy, legend_width, legend_height];
leg.Position(1:2) = bx.Position(1:2);
leg.Box = 'off';
end
resulting
I am currently working on a project simulating the movement of two spacecraft and a moon (Phobos) around Mars. A MATLAB tool called SPICE gives me an array with the x, y and z distances and I have used these to plot the orbit which works fine. Now I want to get markers for each of the spacecraft and Phobos to see when they flyby each other. I got the markers working but not at the same time, they run after each other. I found an example on youtube so it must be possible but he has not released the code how to do it (https://www.youtube.com/watch?v=nArR2P0o4r4).
This is the code I have:
a = position_MEX_Mars(1,:);
b = position_MEX_Mars(2,:);
c = position_MEX_Mars(3,:);
k = position_MAVEN_Mars(1,:);
l = position_MAVEN_Mars(2,:);
m = position_MAVEN_Mars(3,:);
x = position_Phobos_Mars(1,:);
y = position_Phobos_Mars(2,:);
z = position_Phobos_Mars(3,:);
ah = axes;
set(ah,'XLim',[min(x) max(x)],'YLim',[min(y) max(y)],...
'ZLim',[min(z) max(z)]);
plot3(0,0,0,'ro-',x,y,z,a,b,c,k,l,m);
grid on;
hold on;
hpoint = line('XData', 0,'YData', 0,'ZData', 0,'Color','black','Marker',...
'o','MarkerSize',10);
ht = hgtransform('parent',ah);
set(hpoint,'Parent',ht);
for i =2:length(x)
trans = makehgtform('translate',[x(i) y(i) z(i)]);
set(ht,'Matrix',trans);
pause(0.001);
end
This will run a nice animated plot of the trajectory of Phobos in time but only Phobos and not simultaneous with MEX and MAVEN (spacecraft from ESA and NASA).
I tried this but does not work:
a = position_MEX_Mars(1,:);
b = position_MEX_Mars(2,:);
c = position_MEX_Mars(3,:);
k = position_MAVEN_Mars(1,:);
l = position_MAVEN_Mars(2,:);
m = position_MAVEN_Mars(3,:);
x = position_Phobos_Mars(1,:);
y = position_Phobos_Mars(2,:);
z = position_Phobos_Mars(3,:);
ah = axes;
set(ah,'XLim',[min(x) max(x)],'YLim',[min(y) max(y)],...
'ZLim',[min(z) max(z)]);
plot3(0,0,0,'ro-',x,y,z,a,b,c,k,l,m);
grid on;
hold on;
hpoint = line('XData', 0,'YData', 0,'ZData', 0,'Color','black','Marker',...
'o','MarkerSize',10);
ht = hgtransform('parent',ah);
set(hpoint,'Parent',ht);
for i =2:length(x)
trans1 = makehgtform('translate',[x(i) y(i) z(i)]);
set(ht,'Matrix',trans1);
trans2 = makehgtform('translate',[a(i) b(i) c(i)]);
set(ht,'Matrix',trans2);
pause(0.001);
end
I also tried merging the arrays so that it plots them each one step after each other but that makes the animation not smooth and is not satisfying for the project.
a = position_MEX_Mars(1,:);
b = position_MEX_Mars(2,:);
c = position_MEX_Mars(3,:);
k = position_MAVEN_Mars(1,:);
l = position_MAVEN_Mars(2,:);
m = position_MAVEN_Mars(3,:);
x = position_Phobos_Mars(1,:);
y = position_Phobos_Mars(2,:);
z = position_Phobos_Mars(3,:);
tempx = [position_MEX_Mars(1,:); position_Phobos_Mars(1,:); position_MAVEN_Mars(1,:)];
xt = tempx(:);
tempy = [position_MEX_Mars(2,:); position_Phobos_Mars(2,:); position_MAVEN_Mars(2,:)];
yt = tempy(:);
tempz = [position_MEX_Mars(3,:); position_Phobos_Mars(3,:); position_MAVEN_Mars(3,:)];
zt = tempz(:);
ah = axes;
set(ah,'XLim',[min(x) max(x)],'YLim',[min(y) max(y)],...
'ZLim',[min(z) max(z)]);
plot3(0,0,0,'ro-',x,y,z,a,b,c,k,l,m);
grid on;
hold on;
hpoint = line('XData', 0,'YData', 0,'ZData', 0,'Color','black','Marker',...
'o','MarkerSize',10);
ht = hgtransform('parent',ah);
set(hpoint,'Parent',ht);
for i =2:length(x)
trans = makehgtform('translate',[xt(i) yt(i) zt(i)]);
set(ht,'Matrix',trans);
pause(0.001);
end
I think I am close but I seem to be missing something and my knowledge of MATLAB is not that great yet. I hope you can help me out.
Cheers Jeroen
Here's a simplified (and not physically correct) example that could perhaps be useful:
t = linspace(0,2,1000); %// time parameter
x1 = 10*cos(2*pi*t+1);
y1 = 5*sin(2*pi*t+1); %// trajectory of object 1
x2 = 2*cos(6*pi*t-2);
y2 = 3*sin(6*pi*t-2); %// trajectory of object 1
plot(x1,y1,'color',[.5 .5 .5]); %// plot trajectory of object 1
hold on
plot(x2,y2,'color',[.5 .5 .5]); %// plot trajectory of object 2
h1 = plot(x1(1),y1(1),'ro'); %// plot initial position of object 1
h2 = plot(x2(1),y2(1),'b*'); %// plot initial position of object 2
axis([-12 12 -12 12]) %// freeze axis size
grid on
for n = 1:numel(t)
set(h1, 'XData', x1(n), 'YData', y1(n)); %// update position of object 2
set(h2, 'XData', x2(n), 'YData', y2(n)); %// update position of object 2
drawnow %// refresh figure
end
The thing that you tries to do is not really as easy as you think. The main issue is that you need to update everything at the same time. This have been implemented in several ways during the years. One way to do this is by using a so called a double buffer.
This means that you have two "surfaces" to paint on. In matlab this is translated to 2 axes (or 2 figures maybe). However, you do only have one axes visible at the same time. This means that you will have time to paint everything on the "hidden surface" before displaying the content. When you are done with everything you need you just switch which surface being visible.
It is possible that this can be done in a simpler way, but I am not familiar with the hgtransfrom functions in matlab.
EDIT
This is an example how it can be done
function test()
fig = figure;
ax1 = axes;
plot(1:10);
ax2 = axes;
plot(1:10,'r');
setVisibility(ax2,'off');
pause(1);
for k = 1:5
setVisibility(ax2,'on');
setVisibility(ax1,'off');
pause(1);
setVisibility(ax1,'on');
setVisibility(ax2,'off');
pause(1);
end
function setVisibility(ax, visibility)
set(ax, 'visible', visibility)
set(findall(ax), 'visible', visibility)
I'd like to draw a curve on an empty (semilog-y) graph by clicking the points I want it to run through, on the X-Y plane.
Is there a function for this?
edit: I'm trying to do this by obtaining the position of last pointer click -
axis([0 3000 0 1000]);
co=get(gcf, 'CurrentPoint');
It seems to return the cursor position at the time of execution, but it does not change later.
edit2: Here's what works for me. The actual drawing I can do by using the arrays of points collected.
clear
clc
h=plot(0);
grid on;
xlim([0 3000]);
ylim([0 1000]);
datacursormode on;
% Enlarge figure to full screen.
screenSize = get(0,'ScreenSize');
set(gcf, 'units','pixels','outerposition', screenSize);
hold on;
% Print the x,y coordinates - will be in plot coordinates
x=zeros(1,10); y=zeros(1,10);
for p=1:10;
[x(p),y(p)] = ginput(1) ;
% Mark where they clicked with a cross.
plot(x(p),y(p), 'r+', 'MarkerSize', 20, 'LineWidth', 3);
% Print coordinates on the plot.
label = sprintf('(%.1f, %.1f)', x(p), y(p));
text(x(p)+20, y(p), label);
end
Not really, but now there is:
function topLevel
%// parameters
xrange = [0 100];
yrange = [1e-4 1e4];
%// initialize figure, plot
figure, clf, hold on
plot(NaN, NaN);
axis([xrange yrange]);
set(gca, 'YScale', 'log')
t = text(sum(xrange)/2, sum(yrange)/2, ...
'<< Need at least 3 points >>',...
'HorizontalAlignment', 'center');
%// Main loop
xs = []; p = [];
ys = []; P = [];
while true
%// Get new user-input, and collect all of them in a list
[x,y] = ginput(1);
xs = [xs; x]; %#ok<AGROW>
ys = [ys; y]; %#ok<AGROW>
%// Plot the selected points
if ishandle(p)
delete(p); end
p = plot(xs, ys, 'rx');
axis([xrange yrange]);
%// Fit curve through user-injected points
if numel(xs) >= 3
if ishandle(t)
delete(t); end
%// Get parameters of best-fit in a least-squares sense
[A,B,C] = fitExponential(xs,ys);
%// Plot the new curve
xp = linspace(xrange(1), xrange(end), 100);
yp = A + B*exp(C*xp);
if ishandle(P)
delete(P); end
P = plot(xp,yp, 'b');
end
end
%// Fit a model of the form y = A + B·exp(C·x) to data [x,y]
function [A, B, C] = fitExponential(x,y)
options = optimset(...
'maxfunevals', inf);
A = fminsearch(#lsq, 0, options);
[~,B,C] = lsq(A);
function [val, B,C] = lsq(A)
params = [ones(size(x(:))) x(:)] \ log(abs(y-A));
B = exp(params(1));
C = params(2);
val = sum((y - A - B*exp(C*x)).^2);
end
end
end
Note that as always, fitting an exponential curve can be tricky; the square of the difference between model and data is exponentially much greater for higher data values than for lower data values, so there will be a strong bias to fit the higher values better than the lower ones.
I just assumed a simple model and used a simple solution, but this gives a biased curve which might not be "optimal" in the sense that you need it to be. Any decent solution really depends on what you want specifically, and I'll leave that up to you ^_^
I have a question concerning my GUI that has bothered me for some hours now and I cannot get it fixed. The function: I load an image, subset it and plot it as as surf plot.
Afterwards I start a GUI, which lets me choose upper left and lower right coordinates of rectangles. The rectangles get drawn onto the surf-plot.
I have two issues: I want to indicate the mouse-clicks by little red patches, the rectangles by red lines.
1)
The little red patches work fine, except the first on is really big and fills almost the whole plot-window. As soon as I choose the second point for the first coordinate, everything goes back to normal and the patches plot in the small manner I want them to.
I debugged the code to see if somehting is wrong with the coordinates, but they seem to be ok!
2)
The drawing of the lines is inaccurate! Especially the first few lines are offset of the mousclick by up to 100 pixels, usually to the left. Sometimes they even move around when adding the next lines. After placing a few rectangles in that way they usually get better and are in place. Any idea why this is?
Here is the code:
function resampdem
clc;clear;clear all
%% read DEMs and header
img1 = imread('srtm_55_06.tif');
% subset
img1 = img1(1:500,1:500);
[x y] = meshgrid(1:500,1:500);
%%
f = figure;
imageHandle = surfl(x,y,img1);
colormap jet
shading interp
view(0,90);
set(imageHandle,'ButtonDownFcn',#ImageClickCallback)
hold on
a = axes;
set(a, 'Visible', 'off');
%# Create controls.
uicontrol('Parent', f, 'Style', 'edit', 'String', 'Input...');
m = 1;
bin = [];
%%% Funktion zur Auswertung des Mouseklicks
helpdlg('Corner: Upper Left');
function ImageClickCallback ( objectHandle , eventData )
% if mod(m,2) == 0
% string = 'Upper Left';
% else
% string = 'Lower Right';
%
% end
% message = sprintf('Corner: %s',string);
% helpdlg(message);
axesHandle = get(objectHandle,'Parent');
coordinates = get(axesHandle,'CurrentPoint');
coordinates = coordinates(1,1:2);
bin(m,1) = coordinates(1)
bin(m,2) = coordinates(2)
patch([bin(m,1)-3 bin(m,1)+3 bin(m,1)+3 bin(m,1)-3], [bin(m,2)+3 bin(m,2)+3 bin(m,2)-3 bin(m,2)-3],'r','Parent',a);
if mod(size(bin,1),2) == 0
resamp_area(bin,m);
end
m = m+1
end
%%% Funktion zum Zeichnen der Rechtecke
function resamp_area(coords,m)
x1 = coords(m-1,1);
x2 = coords(m,1);
y1 = coords(m-1,2);
y2 = coords(m,2);
patch([x1 x1+20 x1+20 x1], [y1 y1 y1-20 y1-20],'w','Parent',a);
%horizontal lines
line([x1, x2], [y1, y1], 'Parent', a, 'Color',[1 0 0], 'LineWidth',2.0);
line([x1, x2], [y2, y2], 'Parent', a, 'Color',[1 0 0], 'LineWidth',2.0);
%vertical lines
line([x1, x1], [y1, y2], 'Parent', a, 'Color',[1 0 0], 'LineWidth',2.0);
line([x2, x2], [y1, y2], 'Parent', a, 'Color',[1 0 0], 'LineWidth',2.0);
%get(t)
end
end
I have little or no experience with volumetric data in MATLAB,
I need to complete next task:
I have 3 vectors ( rows ):
x_ = vector(1:smpl:max_row,1);
y_ = vector(1:smpl:max_row,2);
z_ = vector(1:smpl:max_row,3);
that are samples from large 3 columns array vector with height max_row.
x_ , y_ , z_ are points of 3D figure - surface points of the figure ( volume ). They represent 3D body that should be drawn in matlab.
I created linear grid:
%linear grid
a = -1.1:step:(-1.1+step*(length(x_)-1));
b = -1.1:step:(-1.1+step*(length(y_)-1));
c = -1.1:step:(-1.1+step*(length(z_)-1));
[x,y,z] = meshgrid(-1.1:step:(-1.1+step*(length(x_)-1)));
and also I create array v length(x_)*length(x_)*length(x_) that contains '1' in cells that are of 3D body representation function points and '0' another.
I tryied to make interpolation:
vi = interp3(x,y,z,v,x,y,z,'nearest');
but then vi = v that I've already created.
Now I need to plot the v array on 3D and form 3D body like in
http://www.mathworks.com/help/techdoc/ref/isonormals.html
for example.
I make that next way:
%plotting:
figure
p = patch(isosurface(x,y,z,v,1e-5,'verbose'),'FaceColor','green','EdgeColor','none');
grid on;
isonormals(v,p);
daspect([1 1 1])
view(3);
axis tight;
camproj perspective;
camlight
lighting gouraud
colormap(hsv)
but I get then only small rectangles in place of function '1' that are not connected like in picture that is attached.
I expect solid body enclosed by that points to be plotted.
Does anybody know what is the problem , how to draw 3D body from the x,y,z,v arrays ?
Thanks in advance.
image:
http://imgur.com/Ulegj
Try this, which will be a nice plot (it interpolates a bit though):
x = vector(1:smpl:max_row,1);
y = vector(1:smpl:max_row,2);
z = vector(1:smpl:max_row,3);
% Settings
displaySurface = 1;
displayPoints = 0;
xres = 800; % Resolution, the higher, the smoother
yres = 800;
cm = 'default'; % Colormap
% Axes Limits
xmin = min(x);
ymin = min(y);
xmax = max(x);
ymax = max(y);
xi = linspace(xmin, xmax, xres);
yi = linspace(ymin, ymax, yres);
% Figure
myfig = figure('Position', [200 200 800 600]);
rotate3d off
[XI, YI] = meshgrid(xi, yi);
ZI = griddata(x, y, z, XI, YI, 'cubic');
mesh(XI,YI,ZI);
colormap(cm)
if(displaySurface == 1)
hold on;
surf(XI, YI, ZI, 'EdgeColor', 'none');
end
hold on;
xlabel('x');
ylabel('y');
zlabel('z');
title('Title', 'FontWeight', 'bold');
xlim([xmin xmax])
ylim([ymin ymax])
grid off;
if(displayPoints == 1)
hold on
plot3(x, y, z,'marker','p','markerfacecolor','w','linestyle','none')
hidden off
end