Problem with user-created image displaying on UI Axes in app developer

4 views (last 30 days)
My goal is for the user to draw an image, and this image is animated on UI Axes. The idea is that the user draws a boat and this boat is displayed on the axis when the graph is being animated so it looks like the boat is making the graph.
However, currently, instead of displaying the entire image, only the first line is displayed.
For example, if I draw 1 line in the window like this:
it is animated onto the graph like this:
(which is what i want, but it doesn't work with more lines)
For example if i draw more lines and use different colours, so a boat for example (like the user would in my app)
Then this is what is displayed on the graph:
How would I make it so all the lines (and any additional colours?) are displayed on the graph?
The code for the app with the drawing feature:
classdef draw_demoAK < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
MATLABDrawingAppUIFigure matlab.ui.Figure
ClearButton matlab.ui.control.Button
DoneButton matlab.ui.control.Button
DrawButton matlab.ui.control.Button
end
properties (Access = private)
ax
my_lines = gobjects(1,0);
is_drawing = false;
end
methods (Access = private)
% button motion function
function bmf(app,~,~)
% return early if not currently in drawing mode
if ~app.is_drawing
return
end
% get cursor position in axes data units
[xy,on_axes] = get_cp_xy(app);
if ~on_axes
% return early if the cursor is not on the axes
return
end
% add the new point to the last line
app.my_lines(end).XData(end+1) = xy(1);
app.my_lines(end).YData(end+1) = xy(2);
end
% button down function
function bdf(app,f,~)
% get cursor position in axes data units
[xy,on_axes] = get_cp_xy(app);
if ~on_axes
% return early if the cursor is not on the axes
return
end
% black line for left click, red for right
switch f.SelectionType
case 'normal'
c = 'k';
case 'alt'
c = 'r';
otherwise
return
end
% make a new line with one point (the point that was just clicked on)
app.my_lines(end+1) = line('Parent',app.ax,'XData',xy(1),'YData',xy(2),'Color',c);
% enter drawing mode
app.is_drawing = true;
end
% button up function
function buf(app,~,~)
% exit drawing mode
app.is_drawing = false;
end
% helper function: get cursor position in axes data units
function [xy,on_axes] = get_cp_xy(app)
cp = app.MATLABDrawingAppUIFigure.CurrentPoint;
pos = getpixelposition(app.ax,true);
% compare current point with axes position to see if cursor is on the axes
on_axes = cp(1) >= pos(1) && cp(1) <= pos(1)+pos(3) ...
&& cp(2) >= pos(2) && cp(2) <= pos(2)+pos(4);
if ~on_axes
% return early if the cursor is not on the axes
xy = [];
return
end
% convert cursor position to axes data units
% (normal X+YDir and linear X+YScale assumed)
xl = app.ax.XLim;
yl = app.ax.YLim;
lim = [xl(1) yl(1) xl(2)-xl(1) yl(2)-yl(1)];
xy = (cp-pos([1 2]))./pos([3 4]).*lim([3 4])+lim([1 2]);
end
end
% Callbacks that handle component events
methods (Access = private)
% Code that executes after component creation
function startupFcn(app)
app.ax = axes(app.MATLABDrawingAppUIFigure, ...
'Units','pixels', ...
'Position',[200 200 250 250], ...
'Box','on', ...
'XLim',[0 1], ...
'YLim',[0 1], ...
'XTick',[], ...
'YTick',[]);
try %#ok<TRYNC>
app.ax.Toolbar.Visible = 'off';
end
end
% Button pushed function: DrawButton
function bpf_Draw(app, event)
app.MATLABDrawingAppUIFigure.WindowButtonMotionFcn = @app.bmf;
app.MATLABDrawingAppUIFigure.WindowButtonDownFcn = @app.bdf;
app.MATLABDrawingAppUIFigure.WindowButtonUpFcn = @app.buf;
end
% Button pushed function: DoneButton
function bpf_Done(app, event)
app.is_drawing = false;
app.MATLABDrawingAppUIFigure.WindowButtonMotionFcn = [];
app.MATLABDrawingAppUIFigure.WindowButtonDownFcn = [];
app.MATLABDrawingAppUIFigure.WindowButtonUpFcn = [];
lineData = app.my_lines;
save('shapeData.mat','lineData')
%exportgraphics(app.ax, 'image.png')
set(app.MATLABDrawingAppUIFigure, 'WindowButtonDownFcn', @(src, event)[]); % Disable mouse interaction once the boat is drawn and the user presses done
app.ClearButton.Enable = "off";
app.DrawButton.Enable = "off";
end
% Button pushed function: ClearButton
function bpf_Clear(app, event)
delete(app.my_lines);
app.my_lines = gobjects(1,0);
end
end
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create MATLABDrawingAppUIFigure and hide until all components are created
app.MATLABDrawingAppUIFigure = uifigure('Visible', 'off');
app.MATLABDrawingAppUIFigure.Position = [100 100 640 480];
app.MATLABDrawingAppUIFigure.Name = 'MATLAB Drawing App';
% Create DrawButton
app.DrawButton = uibutton(app.MATLABDrawingAppUIFigure, 'push');
app.DrawButton.ButtonPushedFcn = createCallbackFcn(app, @bpf_Draw, true);
app.DrawButton.Position = [33 362 100 23];
app.DrawButton.Text = 'Draw';
% Create DoneButton
app.DoneButton = uibutton(app.MATLABDrawingAppUIFigure, 'push');
app.DoneButton.ButtonPushedFcn = createCallbackFcn(app, @bpf_Done, true);
app.DoneButton.Position = [33 327 100 23];
app.DoneButton.Text = 'Done';
% Create ClearButton
app.ClearButton = uibutton(app.MATLABDrawingAppUIFigure, 'push');
app.ClearButton.ButtonPushedFcn = createCallbackFcn(app, @bpf_Clear, true);
app.ClearButton.Position = [33 292 100 23];
app.ClearButton.Text = 'Clear';
% Show the figure after all components are created
app.MATLABDrawingAppUIFigure.Visible = 'on';
end
end
% App creation and deletion
methods (Access = public)
% Construct app
function app = draw_demoAK
% Create UIFigure and components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.MATLABDrawingAppUIFigure)
% Execute the startup function
runStartupFcn(app, @startupFcn)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.MATLABDrawingAppUIFigure)
end
end
end
and the code for the app with the graph:
classdef testing_graph_animation_AK < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure
TypeyourAnswerHereLabel matlab.ui.control.Label
CheckyourAnswerButton matlab.ui.control.Button
Answer matlab.ui.control.EditField
NextQuestionButton matlab.ui.control.Button
ClicktostartButton matlab.ui.control.Button
UIAxes matlab.ui.control.UIAxes
end
% Callbacks that handle component events
methods (Access = private)
% Callback function
function ClicktostartButtonPushed(app, event)
app.UIAxes.Visible = "on";
app.Answer.Visible = "on";
app.TypeyourAnswerHereLabel.Visible = "on";
app.CheckyourAnswerButton.Visible ="on";
app.ScoreLabel.Visible ="on";
app.ClicktostartButton.Visible = "off";
% Disable mouse interaction when graph is being animated and after it has been drawn
set(app.UIFigure, 'WindowButtonDownFcn', @(src, event)[]);
% Create an animated line object
animLine = animatedline(app.UIAxes);
% Set the x-axis limits
xlim(app.UIAxes, [0, 2*pi]);
ylim(app.UIAxes, [-1, 1]);
% Animation loop
for x = linspace(0, 2*pi, 100)
% Calculate the y-value for the sine function
y = sin(x);
% Add the new point to the animated line
addpoints(animLine, x, y);
% Update the plot
drawnow
% Pause for a short duration to control the animation speed
pause(0.02);
end
end
% Button pushed function: NextQuestionButton
function NextQuestionButtonPushed(app, event)
app.Answer.Value = ''; % clears the 'Answer' component
app.CheckyourAnswerButton.Text = 'Check your Answer'; % changes the text of the button so that it returns to original text
% Disable mouse interaction with the graph at all times
set(app.UIFigure, 'WindowButtonDownFcn', @(src, event)[]);
% Clear the axes of the graph from the previous question
cla(app.UIAxes);
% Create an animated line object
animLine = animatedline(app.UIAxes);
% Set the x-axis limits
xlim(app.UIAxes, [0, 2*pi]);
ylim(app.UIAxes, [-1, 1]);
% Animation loop
for x = linspace(0, 2*pi, 100)
% Calcu[-late the y-value for the sine function
y = cos(x);
% Add the new point to the animated line
addpoints(animLine, x, y);
% Update the plot
drawnow
% Pause for a short duration to control the animation speed
pause(0.02);
end
end
% Button pushed function: CheckyourAnswerButton
function CheckyourAnswerButtonPushed(app, event)
userInput = app.Answer.Value;
if strcmp(userInput,'sin(x)')
app.CheckyourAnswerButton.Text = 'Correct!';
elseif strcmp(userInput, 'sinx')
app.CheckyourAnswerButton.Text = "Don't Forget Brackets!";
else
app.CheckyourAnswerButton.Text = 'Try Again!';
end
end
% Button pushed function: ClicktostartButton
function ClicktostartButtonPushed2(app, event)
app.UIAxes.Visible = "on";
app.Answer.Visible = "on";
app.TypeyourAnswerHereLabel.Visible = "on";
app.CheckyourAnswerButton.Visible ="on";
app.ClicktostartButton.Visible = "off";
% Disable mouse interaction when graph is being animated and after it has been drawn
set(app.UIFigure, 'WindowButtonDownFcn', @(src, event)[]);
% Create an animated line objects
animLine = animatedline(app.UIAxes);
animShape = animatedline(app.UIAxes);
% Read shape data & rescale
load shapeData.mat
xShape = lineData.XData;
yShape = lineData.YData;
% Optional rescaling of shape
% xShape = rescale(xShape,0,0.5,"InputMax",1,"InputMin",0);
% yShape = rescale(yShape,0,0.5,"InputMax",1,"InputMin",0);
% Set the x-axis limits
xlim(app.UIAxes, [0, 2*pi]);
ylim(app.UIAxes, [-1, 1]);
% Read and display the image on the UIAxes
% imageData = imread('image.png');
% imageHandle = image(app.UIAxes, 'XData', [0 2*pi], 'YData', [-1 1], 'CData', imageData);
% image(app.UIAxes, imread('image.png'));
%
% % Get the handle of the image
% imageHandle = findobj(app.UIAxes, 'Type', 'image');
% Animation loop
for x = linspace(0, 2*pi, 100)
% Calculate the y-value for the sine function
y = sin(x);
% Add the new point to the animated line
addpoints(animLine, x, y);
clearpoints(animShape)
addpoints(animShape, xShape+x-0.5, yShape+y-0.5);
% % Calculate appropriate x-coordinate for the image
% xImage = linspace(0, 2*pi, size(imageData, 2));
% xImage = interp1(xImage, linspace(1, numel(xImage), size(imageData, 2)), x, 'linear', 'extrap');
%
% % Update the position of the image
% set(imageHandle, 'XData', xImage);
% % Update the position of the image
% set(imageHandle, 'XData', x, 'YData', y);
% Pause for a short duration to control the animation speed
pause(0.02);
% Update the plot
drawnow
% Pause for a short duration to control the animation speed
pause(0.02);
end
end
end
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create UIFigure and hide until all components are created
app.UIFigure = uifigure('Visible', 'off');
app.UIFigure.Position = [100 100 640 480];
app.UIFigure.Name = 'MATLAB App';
% Create UIAxes
app.UIAxes = uiaxes(app.UIFigure);
title(app.UIAxes, 'What is this Graph?')
xlabel(app.UIAxes, 'X')
ylabel(app.UIAxes, 'Y')
zlabel(app.UIAxes, 'Z')
app.UIAxes.FontName = 'Ink Free';
app.UIAxes.FontSize = 18;
app.UIAxes.Visible = 'off';
app.UIAxes.Position = [83 144 464 279];
% Create ClicktostartButton
app.ClicktostartButton = uibutton(app.UIFigure, 'push');
app.ClicktostartButton.ButtonPushedFcn = createCallbackFcn(app, @ClicktostartButtonPushed2, true);
app.ClicktostartButton.BackgroundColor = [0.7176 0.2745 1];
app.ClicktostartButton.FontName = 'Ink Free';
app.ClicktostartButton.FontSize = 20;
app.ClicktostartButton.FontWeight = 'bold';
app.ClicktostartButton.Position = [241 242 148 83];
app.ClicktostartButton.Text = 'Click to start!';
% Create NextQuestionButton
app.NextQuestionButton = uibutton(app.UIFigure, 'push');
app.NextQuestionButton.ButtonPushedFcn = createCallbackFcn(app, @NextQuestionButtonPushed, true);
app.NextQuestionButton.FontName = 'Ink Free';
app.NextQuestionButton.FontSize = 18;
app.NextQuestionButton.FontWeight = 'bold';
app.NextQuestionButton.Visible = 'off';
app.NextQuestionButton.Position = [433 41 134 40];
app.NextQuestionButton.Text = 'Next Question';
% Create Answer
app.Answer = uieditfield(app.UIFigure, 'text');
app.Answer.FontSize = 16;
app.Answer.Visible = 'off';
app.Answer.Position = [356 108 100 25];
% Create CheckyourAnswerButton
app.CheckyourAnswerButton = uibutton(app.UIFigure, 'push');
app.CheckyourAnswerButton.ButtonPushedFcn = createCallbackFcn(app, @CheckyourAnswerButtonPushed, true);
app.CheckyourAnswerButton.FontName = 'Ink Free';
app.CheckyourAnswerButton.FontSize = 18;
app.CheckyourAnswerButton.FontWeight = 'bold';
app.CheckyourAnswerButton.Visible = 'off';
app.CheckyourAnswerButton.Position = [223 41 184 40];
app.CheckyourAnswerButton.Text = 'Check your Answer';
% Create TypeyourAnswerHereLabel
app.TypeyourAnswerHereLabel = uilabel(app.UIFigure);
app.TypeyourAnswerHereLabel.FontName = 'Ink Free';
app.TypeyourAnswerHereLabel.FontSize = 18;
app.TypeyourAnswerHereLabel.FontWeight = 'bold';
app.TypeyourAnswerHereLabel.Visible = 'off';
app.TypeyourAnswerHereLabel.Position = [166 109 183 22];
app.TypeyourAnswerHereLabel.Text = 'Type your Answer Here';
% Show the figure after all components are created
app.UIFigure.Visible = 'on';
end
end
% App creation and deletion
methods (Access = public)
% Construct app
function app = testing_graph_animation_AK
% Create UIFigure and components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.UIFigure)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFigure)
end
end
end

Answers (1)

Ayush Aniket
Ayush Aniket on 6 May 2024
Hi Gabriela,
The reason you only see a single line in your Graph App is because it only processes one 'Line' object information in the callback function 'ClicktostartButtonPushed2'.
When you are drawing a figure in your Drawing App, the different strokes are stored as an array of various 'Line' objects in the 'app.my_lines' variable. Hence, in the Graph App you need to add all of these information to the 'animShape' variable attached to the axes. However, the 'addpoints' function doesnot allow color information. To include mutli color figures, you will have to use an array of 'AnimatedLine' objects which inherit the color of the various lines in the figure as shown below:
function ClicktostartButtonPushed2(app, event)
app.UIAxes.Visible = "on";
app.Answer.Visible = "on";
app.TypeyourAnswerHereEditFieldLabel.Visible = "on";
app.CheckyourAnswerButton.Visible ="on";
app.ClicktostartButton.Visible = "off";
% Disable mouse interaction when graph is being animated and after it has been drawn
set(app.UIFigure, 'WindowButtonDownFcn', @(src, event)[]);
%load shape data
load shapeData.mat
% Create animated line and shape objects
animLine = animatedline(app.UIAxes);
animShape = gobjects(size(lineData));
for idx = 1:length(lineData)
animShape(idx) = animatedline(app.UIAxes,'Color',lineData(idx).Color);
end
% Set the x-axis limits
xlim(app.UIAxes, [0, 2*pi]);
ylim(app.UIAxes, [-1, 1]);
% Animation loop
for x = linspace(0, 2*pi, 100)
% Calculate the y-value for the sine function
y = sin(x);
% Add the new point to the animated line
addpoints(animLine, x, y);
for idx = 1:length(lineData)
clearpoints(animShape(idx));
% Extract the current segment
xShape = lineData(idx).XData;
yShape = lineData(idx).YData;
% Draw the segment at its new position
addpoints(animShape(idx), xShape+x-0.5, yShape+y-0.5);
end
% Update the plot
drawnow
% Pause for a short duration to control the animation speed
pause(0.02);
end
end
The 'gobjects' function is used to pre-allocate memory for Graphics objects. Refer to the documentation links below to read more about memory allocation for graphics object and 'Line' object properties:
Hope it helps!

Categories

Find more on Specifying Target for Graphics Output in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!