Live line plotting over a surface/mesh/imagesc plot.

Hello,
I have a matrix (size 1000x1000) of height values, that I can view with mesh command. From the same figure (that mesh is displayed) I use ginput to the get the coordinates of the mouse and based on the coordinates I can plot the horizontal and vertical line profiles:
[x y] = ginput(1);
figure(2)
subplot(2, 1, 1)
set(gcf, 'Units', 'Inches', 'Position', [5, 5, 10, 3], 'PaperUnits', 'Inches', 'PaperSize', [16, 9.0])
plot(Zp(:, round(x(1))), 'b-'); title('Vertical'); grid on
subplot(2, 1, 2);
plot(Zp(round(y(1)), :), 'k-'); title('Horizontal');
Now, what I really need is a live line profile plotting, so as I drag the mouse over the mesh figure I can see the two line profiles.
It is like continuously updating the values of x(1) and y(1) and updating figure(2).
Is it even possible? And if so, could anyone guide me with how to do it?
Thanks.

11 Comments

What is "live line profile plotting" ?
"as I drag the mouse over the mesh figure I can see the two line profiles" - I'm lost.
Feri
Feri on 10 Mar 2020
Edited: Feri on 10 Mar 2020
Suppose that at t=t0 the mouse is at [row col] = [100, 200] on the mesh figure; row 100 and column 200 (each containing 1000 values) are being plotted in another figure with subplots(2,1,1) and (2,1,2); now, without closing any of the figures, if you move the mouse such that it is now on [row col] = [500, 650], the figure with subplots immidiately updates itself with row 500 and column 650 values.
The update of the subplot figure happens as the user moves the mouse over the mesh figure (and thus updates the mouse location).
Thank you.
What would the subplot(2,1,1) look like for any given pair of columns/rows ?
Feri
Feri on 10 Mar 2020
Edited: Feri on 10 Mar 2020
Thats how the "line profiles" plot looks like, plotted based on the (imaginary) location of the mouse over the mesh figure. (both subplot(2,1,1) and subplot(2,1,2))
Adam, the following is able to show the mouse coordinates as the figure title, however, it is not able to plot the commented line, because the variable Zp is not recognized by the mouseMove function. Even when I put it as an input argument for the function it still does not recognizes it.
I think if I can somehow force the moveMouse function to get the Zp (or any n x n matrix) then I can plot the results lively...Maybe...
set(gcf,'windowbuttonmotionfcn', @mouseMove);
%figure;
function mouseMove(object, eventdata, handles)
C = get(gca, 'CurrentPoint');
x = C(1,1);
y = C(1, 2);
% plot((1:length(Zp)), Zp(round(y), :), '.');
title(gca, ['(X,Y) = (', num2str(x), ', ',num2str(y), ')']);
end
I think you'll have to reconsider how the user will interact with the data to select which column and row will be plotted. The data you describe (1000x1000) has 1 million coordinates and the graphic updates won't keep up with a smoothly moving mouse.
Here's a demo the shows this problem. The data is 30x30 (see 1st line of code) and the mouseMove function only does two simple things 1) updates the title of the axis and 2) shows crosshairs. Copy it to a new m-file and run it.
As you can see, it runs fairly smoothly.
Now, change the first line to data = randi(100,1000,1000); to match your data size and run it again. You'll have to leave the mouse in place for quite a long time to allow the graphics to update to the new mouse position.
data = randi(100,30,30);
ax = gca() ;
mesh(ax, data)
view(ax, 2) % assumed
axis(ax,'tight') % required
xl = xline(min(xlim(ax)), 'k-');
yl = yline(min(ylim(ax)), 'k-');
set(gcf,'windowbuttonmotionfcn', {@mouseMove, data, xl, yl, ax});
function mouseMove(object, eventdata, data, xl, yl, ax)
% Get mouse coordinate
C = get(gca, 'CurrentPoint');
x = round(C(1,1));
y = round(C(1,2));
% If mouse isn't on axis, do nothing.
if x < ax.XLim(1) || x > ax.XLim(2) || y < ax.YLim(1) || y > ax.YLim(2)
return
end
% Update crosshairs
xl.Value = x;
yl.Value = y;
% plot((1:length(Zp)), Zp(round(y), :), '.');
title(gca, ['(X,Y) = (', num2str(x), ', ',num2str(y), ')']);
end
Yes, it is slow as you said, do you have any suggestion how to make it a bit faster? is it because each time the moveMouse is executed the "data" is being passed to it, so that the bigger the data, the longer to pass it over?
Or any idea of how to achieve this goal: The goal is to allow the user to interactively see the cross sections of the surface as the mouse moves.
Also, with the current situation, how can I plot the row and column pairs in another plot so that the cross sections are clearly visible?
Thank you so much.
I don't think that approach can be made faster. You can remove the "data" variable from the mouseMove inputs and the windowbuttonmotionfcn inputs (it's not being used) and you can even comment-out the two lines that update the crosshairs but the problem still persists.
Even replacing the windobuttonmotionfcn idea with ginput(1) takes a lot of time.
You could create a small GUI with two inputs where user enters a row number and a col num which updates two subplots. That's not as interactive as you'd like but it would probably be much faster.
"how can I plot the row and column pairs in another plot "
The x and y variables are the row and col numbers. You just need to use those to index the data variable.
From your question, "I have a matrix (size 1000x1000) of height values, that I can view with mesh command", is that really what you want to do? This creates a 3D plot (as in my answer).
Adam,
Thank you for your response. As you mentioned, having the user put the values in another GUI is not a 100% interactive method.
However, instead of mesh if I use imagesc just to see the data, it works fast enough, even for a 1000x1000 data.
Would you be able to guide me to how to set the ax2.XData, and ax2.YData of a plot with two subplots, one plotting the rows, the other plotting the columns? (Assuming that the axes handle is called ax2.).
I'm having difficulties passing x and y as the row and column indices to the axes handle.
Thanks a million.
Feri
Feri on 11 Mar 2020
Edited: Feri on 11 Mar 2020
I got it, was finally able to pass the correct values to the axes, great.
Thanks a million Adam.
How do I make this as the Accepted Answer?
Using imagesc makes much more sense. See the demo below.
Note that this solution merely updates values of the line objects rather than replotting lines. This is much faster and more efficient than replotting lines.

Sign in to comment.

 Accepted Answer

Here's a functional demo that uses the WindowButtonMotionFcn property of a figure to capture the mouse position which is used to detect the closest (x,y) coordinates to the mouse within the axes. It continually updates a set of crosshairs that display the coordinates and updates two subplots showing the values along the selected row and column.
See inline comments for details.
Create the data and set up the plot
% Create data
data = peaks(1000);
% Plot data in main axis
ax(1) = subplot(4,1,[1,2]);
imagesc(ax(1), data)
ax(1).YDir = 'Normal';
axis(ax(1),'equal')
axis(ax(1),'tight') %required!
ax(1).Parent.WindowState = 'Maximized'; % maximize figure
ax(1).Toolbar.Visible = 'off'; % otherwise, toolbar may hide axis title
xlabel(ax(1), 'x axis lable')
ylabel(ax(1), 'y axis lable')
title(ax(1), 'Data')
% Set up cross hairs at axis edges
gobj(1) = xline(min(xlim(ax(1))), 'k-');
gobj(2) = yline(min(ylim(ax(1))), 'k-');
% Set up subplot 2; do all formatting here
ax(2) = subplot(4,1,3);
gobj(3) = plot(ax(2), 1:size(data,2), nan(1,size(data,2)), '-ko', 'MarkerSize', 4);
xlabel(ax(2), 'x index')
ylabel(ax(2), 'x value')
axis(ax(2), 'tight')
% Set up subplot 3; do all formatting here
ax(3) = subplot(4,1,4);
gobj(4) = plot(ax(3), 1:size(data,1), nan(1,size(data,1)), '-ko', 'MarkerSize', 4);
xlabel(ax(3), 'y index')
ylabel(ax(3), 'y value')
axis(ax(3), 'tight')
% After values are set above, assign windowbuttonmotion fcn
set(ax(1).Parent,'windowbuttonmotionfcn', {@mouseMove, data, ax, gobj});
Define the WindowButtonMotionFcn
function mouseMove(~, ~, data, ax, gobj)
% gobj(1) is xline
% gobj(2) is yline
% gobj(3) is subplot 2 line
% gobj(4) is subplot 3 line
% ax is a vector of subplot handles from top to bottom
% data is the imagesc data
% Get mouse coordinate, round to nearest integer.
C = ax(1).CurrentPoint;
x = round(C(1,1));
y = round(C(1,2));
% If mouse isn't on axis, do nothing.
if x < ax(1).XLim(1) || x > ax(1).XLim(2) || y < ax(1).YLim(1) || y > ax(1).YLim(2)
return
end
% Update crosshairs
gobj(1).Value = x;
gobj(1).Label = x;
gobj(2).Value = y;
gobj(2).Label = y;
% Update main title
% title(ax(1), sprintf('(x,y) = (%d, %d)', x, y));
% Update x-subplot
gobj(3).YData = data(x,:);
title(ax(2), sprintf('X = %d', x))
% Update y-subplot
gobj(4).YData = data(:,y);
title(ax(3), sprintf('Y = %d', y))
end
Addendum: turn on/off interactivity
Press the left mouse button to turn on interactivity and the right mouse button to pause it so that the crosshairs and subplots do not update with mouse motion.
%% Add this section to the first block of code where the figure is created.
% Remove the windowbuttonmotionfcn in that section.
WindowButtonMotionFcnInput = {@mouseMove, data, ax, gobj};
set(ax(1).Parent,'windowbuttondownfcn', {@startStopMouseMove, WindowButtonMotionFcnInput})
%% This function responds to mouse clicks and either assigns
% or removes the windowbuttonmotionfcn
function startStopMouseMove(hobj,~,WindowButtonMotionFcnInput)
buttonID = hobj.SelectionType;
switch buttonID
case 'normal' %left mouse button
% Start interactivity
set(hobj,'windowbuttonmotionfcn', WindowButtonMotionFcnInput);
case 'alt' % right mouse button
% Stop interactivity
set(hobj,'windowbuttonmotionfcn', []);
end
end

6 Comments

I would also add
grid(ax(2), 'on')
grid(ax(3), 'on')
to the top section of code.
It may be useful for the main axis as well.
iIt works exactly the way I wanted it.
Thank you so very much Adam :)
Feri
Feri on 12 Mar 2020
Edited: Feri on 12 Mar 2020
Hi Adam,
Is it possible to modify the above demo such that it live plots the mouse coordinates as long as the user holds the left click, and when the left click of the mouse is released the line profiles freez, (so that we can zoom in and out on profiles).
Thank you so much.
See addendum in answer.
Thanks a million :)

Sign in to comment.

More Answers (0)

Categories

Find more on Graphics Performance in Help Center and File Exchange

Asked:

on 4 Mar 2020

Commented:

on 12 Mar 2020

Community Treasure Hunt

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

Start Hunting!