Search code examples
matlabmatlab-figure

MATLAB - Plot appearing in new figure?


I'm trying to plot a 3D figure(surf plot) inside a figure that I have already created but for some reason my new plot is created in a separate figure. The code consist of 2 scripts which I will be posting. The first script initializes the act frame I want to draw in and its callback (from the slider) draws my cylinder which for some reason appears inside a new frame leading to this mess:

enter image description here

Main script that creates the main figure I want to draw in.

%%
clf;
clear;
close all;
clc;
load('myHeatMap.mat','myHeatMap');
filename = ('C:\Users\Ali\Desktop\Documents\DataVis\Projekt\data\day\filenames.txt');
%This line simply gives us a table of all filenames in this file.
T = readtable(filename);
tsize = size(T);
tsize2 = size(T, 1);

filename = strcat('\Users\Ali\Desktop\Documents\DataVis\Projekt\data\day\', string(T{1,1}));
map100 = getCylinderHeatMap(filename);

%Figure/parent container (uifigure) properties%
App = uifigure('Scrollable','on','Name','Heatmap Plots','NumberTitle','off');
App_Width = 1000; App_Height = 500;
App.Position = [0 0 App_Width App_Height];

%Slider label (uilabel) properties%
Slider_Label = uilabel('Parent',App);
Slider_Label.Text = "Cylinder Number";
Slider_Label.Position = [25 20 200 100];

%Slider (uislider) properties%
Slider = uislider('Parent',App);
Slider.Limits = [1 1000];
Slider.Value = 1;
Slider_Width = App_Width - 500;
Margin = (App_Width - Slider_Width)/2;
Slider.Position = [Margin 50 Slider_Width 3];
Slider.MajorTicks = (1:100:1000);
Slider.FontSize = 6;
Red = 87; Green = 207; Blue = 220;
Slider.FontColor = [Red/255 Green/255 Blue/255];

%Plot (uiaxes) properties%
Heatmap_Cylinder_Plot = uiaxes('Parent',App);
Heatmap_Cylinder_Plot_X_Position = 100;
Heatmap_Cylinder_Plot_Y_Position = 100;
Heatmap_Cylinder_Plot_Height = 350;
Heatmap_Cylinder_Plot_Width = 400;
Heatmap_Cylinder_Plot.Position = [Heatmap_Cylinder_Plot_X_Position Heatmap_Cylinder_Plot_Y_Position Heatmap_Cylinder_Plot_Width Heatmap_Cylinder_Plot_Height];
Heatmap_Cylinder_Plot.GridColor = [0.15 0.15 0.15];
Heatmap_Cylinder_Plot.XGrid = 'on';
Heatmap_Cylinder_Plot.YGrid = 'on';
Heatmap_Cylinder_Plot.ZGrid = 'on';

%Image (uiimage) properties%
Heatmap_Image = uiimage('Parent',App);
Heatmap_X_Position = (App_Width/2) + 50;
Heatmap_Y_Position = 80;
Heatmap_Height = 350;
Heatmap_Width = 400;
Heatmap_Image.Position = [Heatmap_X_Position Heatmap_Y_Position Heatmap_Height Heatmap_Width];

%Callback function as the slider is moved%
Slider.ValueChangedFcn = @(Slider,event) Snap_Slider(Slider,Slider_Label,Heatmap_Cylinder_Plot,Heatmap_Image,T,...
    myHeatMap);

%%
%Callback function definition%
function [] = Snap_Slider(Slider,Slider_Label,Heatmap_Cylinder_Plot,Heatmap_Image,T,myHeatMap)
Slider.Value = round(Slider.Value);

filename = strcat('\Users\Ali\Desktop\Documents\DataVis\Projekt\data\day\', string(T{Slider.Value,1}));
map100 = getCylinderHeatMap(filename);
splitFileName = strsplit(string(T{Slider.Value,1}),'.');

Slider_Label.Text = "Time Stamp: " + splitFileName{1,1};

%Put plotting code here%
plot(Heatmap_Cylinder_Plot,createSurfCylinder(map100));

%Put image plotting code here%
Heatmap_Image.ImageSource = "";
colormap(myHeatMap);
end
%%

Script for drawing actual Cylinder.

function cylinder = createSurfCylinder(matrix) 
%Load heat map.
load('myHeatMap.mat','myHeatMap');

%%
%Cylinder creation
Sample_Range = 255 - 0;
Temperature_Range = 450 - 50;

Multiplier = Temperature_Range/Sample_Range;
map100 = matrix.*Multiplier + 50;


%Setting up the figure%
Radius = 1.5;
Number_Of_Data_Points = 360;
theta = linspace(0,2*pi,Number_Of_Data_Points);

%The xy values according to radius and number of points%
Z_Circle = Radius*cos(theta);
Y_Circle = Radius*sin(theta);

map100 = rot90(map100);

Height = 512;
Z_Circle = repmat(Z_Circle,Height,1);
Y_Circle = repmat(Y_Circle,Height,1);
X_Length = (1:512)';
X_Length = repmat(X_Length,1,Number_Of_Data_Points);

figure('Position', [10 10 800 800])

clf;
close;
cyl = surf(X_Length,Y_Circle,Z_Circle,'Cdata',map100); 
title("3D Cylinder Heatmap Plot");
zlabel("Z-Position");
ylabel("Y-Position");
xlabel("Length(Cm)");
set(gca,'Ydir','reverse')
colormap(myHeatMap);
colorbar;
shading interp

Maximum_Value = 450;
Minimum_Value = 50;
caxis([Minimum_Value Maximum_Value]);

%Show the image in the subplot and add custome color coding to it.
% subplot(1,3,3); imshow(rot90(map100));
% colormap(myHeatMap);
% caxis([Minimum_Value Maximum_Value]);
cylinder = cyl;
%%
end

Any one that knows how to make may cylinder appear in my original Uiframe? Any help would be much appreciated.


Solution

  • There are a few things you may want to note. First the closing-commands.

    • clf close (current) figure
    • clear clear all variables in the current workspace (this can the the base workspace in scripts or the workspace of the function, in which the command is called)
    • close all closes all open figure windows
    • clc clear command window.

    Although these are handy commands, the are meant to be used when working in the command window and one should think twice when using them in scripts and never use them in functions. Why so? You might forget that you have used them and consequently, you code behaves unexpected. In particular if you call multiple functions/scripts, which all manipulate the same windows or output.

    The command figure opens a new figure window. So every time this command is issued, a new window pops up and is set to "active", i.e. it is automatically the current figure. It returns its specific figure handle if you assign an output to it: fh = figure('Name','Figure A'). If you later what to activate a specific figure, you can call its handle: figure(fh). The function gcf always returns the handle of the current figure.

    Now, let's see for example, in function createSurfCylinder, you are calling

    figure('Position', [10 10 800 800])
    
    clf;
    close;
    

    This opens a figure, closes the current figure (that is the figure you have just opened) and closes the current figure (which is now the one that was open before you opened & closed the last figure...

    The plot()-function draws a line into the current axis (if not existing, it opens an axis). It can take as a first input a specific axis handle. The default is gca, which is a function meaning something like get current axis.

    So to have all control over your plots, keep track of the handles. I always go like this:

    fh1 = struct(); % create an empty struct
    fh1.fig = figure('Name','very important figure'); % open figure & keep its handle
    fh1.ax = subplot(1,1,1); % this opens a single axis & I keep the handle
    
    % plot
    plot(   fh.ax, [1,10],[2,5])
    ylabel( fh.ax, 'Amplitude Y / unit')
    xlabel( fh.ax, 'Measure of time x / unit')
    

    With the command subplot one can arrange multiple axes in one figure (here you need to be aware of the difference between a figure and an axis, and why there are two different types of handles). For example

    fh2 = struct(); % create a new empty struct
    fh2.fig = figure('Name','Multiple axes in one figure'); % open figure & keep its handle
    fh2.ax = cell(3,1);
    fh2.ax{1} = subplot(2,2,1); % this opens a single axis & keeps the handle
    fh2.ax{2} = subplot(2,2,2); % this opens a single axis & keeps the handle
    fh2.ax{3} = subplot(2,2,3:4); % this opens a single axis & keeps the handle
    
    % do plotting with your axis-handles
    

    figure window with 3 axes

    (yes, I usually first open all axes and than fill them with graphs/lines)