Function overwrites output with a different number
3 views (last 30 days)
Show older comments
Claudius Simon Appel
on 22 Mar 2020
Commented: Claudius Simon Appel
on 26 Mar 2020
Hello,
This function is outputting a variable called LPfittypeindx that is used to navigate inside the fitting function. Every single fittype is referred to by this. My problem is that for some reason, it first does assign the correct number, but then immediately overwrites it with the casenumber of the specific list. For example, if you choose Fourier --> Fourier 7, it will assign assign LPfittypeindx=7, instead of retaining the 18 as it should. This happens for all options. I have zero clue why this happens, as there is exactly one instance in there that assigns 1 to the indx, that being if you choose poly1. What am I missing?
Below is the function, which is called with LPfittypeindx=LPFitlistfun:
function [LPFitindx,LPFitindxGeneral,LPFitlist,LPFitlistGeneral,LPtf1,LPtf2,LPfittypeindx] = LPFitlistfun
%UNTITLED2 Summary of this function goes here
% Detailed explanation goes here
LPFitlistGeneral={'PolyX','ExponentialX','FourierX','GaußianX','PowerX','RationalX_X','Weibull','InterpolantX','Sum of SineX','Custom_not_working'};
[LPFitindxGeneral,LPtf1]=listdlg('ListString',LPFitlistGeneral,'PromptString','Select Degree','Name','PolyX','SelectionMode','single','ListSize',[160 145])
switch LPFitindxGeneral
case 1 %PolyX
LPFitlist={'Poly1','Poly2','Poly3','Poly4','Poly5','Poly6','Poly7','Poly8','Poly9'};
[LPFitindx, LPtf2]=listdlg('ListString',LPFitlist,'PromptString','Select Fittype','Name','Fittype-Selection','SelectionMode','Single','ListSize',[160 130]);
switch LPFitindx
case 1
LPfittypeindx=1
case 2
LPfittypeindx=2
case 3
LPfittypeindx=3
case 4
LPfittypeindx=4
case 5
LPfittypeindx=5
case 6
LPfittypeindx=6
case 7
LPfittypeindx=7
case 8
LPfittypeindx=8
case 9
LPfittypeindx=9
end
case 2 %ExponentialX
LPFitlist={'Exponential_1','Exponential_2'};
[LPFitindx, LPtf2]=listdlg('ListString',LPFitlist,'PromptString','Select Fittype','Name','Fittype-Selection','SelectionMode','Single','ListSize',[160 130])
switch LPFitindx
case 1
LPfittypeindx=10
case 2
LPfittypeindx=11
end
case 3 %FourierX
LPFitlist={'Fourier1','Fourier2','Fourier3','Fourier4','Fourier5','Fourier6','Fourier7','Fourier8'};
[LPFitindx, LPtf2]=listdlg('ListString',LPFitlist,'PromptString','Select Fittype','Name','Fittype-Selection','SelectionMode','Single','ListSize',[160 130])
switch LPFitindx
case 1
LPfittypeindx=12
case 2
LPfittypeindx=13
case 3
LPfittypeindx=14
case 4
LPfittypeindx=15
case 5
LPfittypeindx=16
case 6
LPfittypeindx=17
case 7
LPfittypeindx=18
case 8
LPfittypeindx=19
end
case 4 %GaussianX
LPFitlist={'Gaussian1','Gaussian2','Gaussian3','Gaussian4','Gaussian5','Gaussian6','Gaussian7','Gaussian8'};
[LPFitindx, LPtf2]=listdlg('ListString',LPFitlist,'PromptString','Select Fittype','Name','Fittype-Selection','SelectionMode','Single','ListSize',[160 130])
switch LPFitindx
case 1
LPfittypeindx=20
case 2
LPfittypeindx=21
case 3
LPfittypeindx=22
case 4
LPfittypeindx=23
case 5
LPfittypeindx=24
case 6
LPfittypeindx=25
case 7
LPfittypeindx=26
case 8
LPfittypeindx=27
end
case 5 %PowerX
LPFitlist={'Power1','Power2'};
[LPFitindx, LPtf2]=listdlg('ListString',LPFitlist,'PromptString','Select Fittype','Name','Fittype-Selection','SelectionMode','Single','ListSize',[160 130])
switch LPFitindx
case 1
LPfittypeindx=28
case 2
LPfittypeindx=29
end
case 6 %RationalX_X
LPFitlist={'0','1','2','3','4','5'};
[LPFitindx, LPtf2]=listdlg('ListString',LPFitlist,'PromptString','Select Numerator Degree','Name','Rational Numerator','SelectionMode','Single','ListSize',[160 130])
switch LPFitindx
case 1 %0
Denominatorlist={'1','2','3','4','5'};
[Denominatorindx, tf3]=listdlg('ListString',Denominatorlist,'PromptString','Select Denominator Degree','Name','Rational Denominator','SelectionMode','Single','Listsize',[160 130])
answer=questdlg('"You`re still here?"')
clear answer
switch Denominatorindx
case 1
LPfittypeindx=30
case 2
LPfittypeindx=31
case 3
LPfittypeindx=32
case 4
LPfittypeindx=33
case 5
LPfittypeindx=34
end
case 2 %1
Denominatorlist={'1','2','3','4','5'};
[Denominatorindx, tf3]=listdlg('ListString',Denominatorlist,'PromptString','Select Denominator Degree','Name','Rational Denominator','SelectionMode','Single','Listsize',[160 130])
answer=questdlg('"A feeling of dread hangs over you... But you stay determined."')
clear answer
switch Denominatorindx
case 1
LPfittypeindx=35
case 2
LPfittypeindx=36
case 3
LPfittypeindx=37
case 4
LPfittypeindx=38
case 5
LPfittypeindx=39
end
case 3 %2
Denominatorlist={'1','2','3','4','5'};
[Denominatorindx, tf3]=listdlg('ListString',Denominatorlist,'PromptString','Select Denominator Degree','Name','Rational Denominator','SelectionMode','Single','Listsize',[160 130])
answer=questdlg('"The waterfall here seems to flow from the ceiling of the cavern.Occasionally, a piece of trash will flow through and fall into the bottomless abyss below. Viewing this endless cycle of worthless garbage. It fills you with determination."')
clear answer
switch Denominatorindx
case 1
LPfittypeindx=40
case 2
LPfittypeindx=41
case 3
LPfittypeindx=42
clear answer
answertoallquestions=questdlg('Is this the answer to all questions?','42');
switch answertoallquestions
case 'Yes'
disp('I see...')
clear answertoallquestions
disp('You have chosen ......')
disp('wisely')
pause(10)
case 'No'
clc;
clear all
close all
disp('wrong answer.')
case 'Cancel'
clc;
close all
answertoallquestions2=questdlg('Are you sure you wanna cancel? I''d rather agree if I''d be you','Is it the answer?')
switch answertoallquestions2
case 'Yes'
clear all
case 'No'
disp('...wise decision')
case 'Cancel'
disp('...wise decision')
end
end
case 4
LPfittypeindx=43
case 5
LPfittypeindx=44
end
case 4 %3
Denominatorlist={'1','2','3','4','5'};
[Denominatorindx, tf3]=listdlg('ListString',Denominatorlist,'PromptString','Select Denominator Degree','Name','Rational Denominator','SelectionMode','Single','Listsize',[160 130])
answer=questdlg('"Partaking in useless garbage fills you with determination."')
clear answer
switch Denominatorindx
case 1
LPfittypeindx=45
case 2
LPfittypeindx=36
case 3
LPfittypeindx=47
case 4
LPfittypeindx=48
case 5
LPfittypeindx=49
end
case 5 %4
Denominatorlist={'1','2','3','4','5'};
[Denominatorindx, tf3]=listdlg('ListString',Denominatorlist,'PromptString','Select Denominator Degree','Name','Rational Denominator','SelectionMode','Single','Listsize',[160 130])
answer=questdlg('"but you didn`t get this far by giving up, did you? that`s right. you have something called `determination´. so as long as you hold on.. so long as you do what`s in your heart.. i believe you can do the right thing."')
clear answer
switch Denominatorindx
case 1
LPfittypeindx=50
case 2
LPfittypeindx=51
case 3
LPfittypeindx=52
case 4
LPfittypeindx=53
case 5
LPfittypeindx=54
end
case 6 %5
Denominatorlist={'1','2','3','4','5'};
[Denominatorindx, tf3]=listdlg('ListString',Denominatorlist,'PromptString','Select Denominator Degree','Name','Rational Denominator','SelectionMode','Single','Listsize',[160 130])
answer=questdlg('"on days like these, kids like you... should be burning in hell."')
clear answer
switch Denominatorindx
case 1
LPfittypeindx=55
case 2
LPfittypeindx=56
case 3
LPfittypeindx=57
case 4
LPfittypeindx=58
case 5
LPfittypeindx=59
end
end
case 7 %Weibull
LPFitlist={'Weibull'};
[LPFitindx, LPtf2]=listdlg('ListString',LPFitlist,'PromptString','Select Fittype','Name','Fittype-Selection','SelectionMode','Single','ListSize',[160 50])
LPfittypeindx=60
case 8 %Interpolant
LPFitlist={'Nearest Neighbor','Linear','Cupic','Shape-Preserving (PCHIP)'};
[LPFitindx, LPtf2]=listdlg('ListString',LPFitlist,'PromptString','Select Fittype','Name','Fittype-Selection','SelectionMode','Single','ListSize',[160 60])
switch LPFitindx
case 1
LPfittypeindx=61
case 2
LPfittypeindx=62
case 3
LPfittypeindx=63
case 4
LPfittypeindx=64
end
case 9 %SumofSineX
LPFitlist={'1','2','3','4','5','6','7','8'};
[LPFitindx, LPtf2]=listdlg('ListString',LPFitlist,'PromptString','Select Number of terms','Name','NofTerms-Selection','SelectionMode','Single','ListSize',[160 118])
switch LPFitindx
case 1
LPfittypeindx=65
case 2
LPfittypeindx=66
case 3
LPfittypeindx=67
case 4
LPfittypeindx=68
case 5
LPfittypeindx=69
case 6
LPfittypeindx=70
case 7
LPfittypeindx=71
case 8
LPfittypeindx=72
end
case 10 %Custom
LPFitlist={'Simple','With fo in detailed code'};
[LPFitindx,LPtf2]=listdlg('ListString',LPFitlist,'PromptString','Select Degree of customosation','Name','Custom Fit','SelectionMode','Single','ListSize',[160 33])
answer=questdlg('Under construction. Need to find out how to create custom LPFits for_ single use, which will be deleted afterwards.')
switch LPFitindx
case 1
LPfittypeindx=73
disp ('This should be 73')
case 2
LPfittypeindx=74
end
end
end
When, for example, going for custom_not_working --> simple, it does output 73, along with the message "This should be 73" I put in, but then somehow LPfittypeindx is redefined as 1. Why does this happen?
Thank you for helping.
4 Comments
Guillaume
on 22 Mar 2020
Breakpoints are not part of an m file.
Opening your files, there are tons of orange lines in the right margin indicating potential problems with your code. You should endeavour to fix them all. A lot of them look like a lack of semicolon at the end of lines, but there may be other.
At the same time, you should get rid of the switch... case... LPfittypeindx = n and replace them all by array indexing. This will make your code much shorter and easier to read and edit. eg. replace:
switch LPFitindx
case 1
LPfittypeindx=12
case 2
LPfittypeindx=13
case 3
LPfittypeindx=14
case 4
LPfittypeindx=15
case 5
LPfittypeindx=16
case 6
LPfittypeindx=17
case 7
LPfittypeindx=18
case 8
LPfittypeindx=19
end
by
typeindices = 12:19;
LPfittypeindx = typeindices(LPFitindx);
Also, get rid of all the clear inside your function as that's a sure way of introducting bugs. Similarly, clc and close all shouldn't be found in a function.
dpb
on 22 Mar 2020
OBTW...I had a refactoring suggestion as well--put that long call and return stack of variables into a struct and pass it in/out instead.
Accepted Answer
dpb
on 22 Mar 2020
Edited: dpb
on 22 Mar 2020
Besides the refactoring and code mlint suggestions removal, I think the biggest problem is the function definition line
function [LPFitindx,LPFitindxGeneral,LPFitlist,LPFitlistGeneral,LPtf1,LPtf2,LPfittypeindx] = LPFitlistfun
returns variable LPFitindx as the first returned variable and LPfittypeindx as the last in a very long list of outputs. You define it (the latter) inside the function, but unless your calling statement has a place to assign all those outputs, everything except the first in the list will be thrown away and the first one the only one returned, and its value will be whatever is returned from listdlg.
"which is called with LPfittypeindx=LPFitlistfun:"
and so you have just assigned the value of LPFitindx from the function call to the variable LPfittypeindx in the calling function/workplace.
You've simply thrown away the value you're looking for by not having a place for it to be stored when you called the routine.
[~,~,~,~,~,~,LPfittypeindx] = LPFitlistfun;
will return the variable you're looking for instead.
Given that klunky syntax, I'd suggest rearranging the order of outputs such that the most common one(s) are listed first as default ans and the less-used towards the end.
Actually, probably the better route with so many that seemingly are all related to the user interface would be to place all of the variables as elements in an interface structure and pass the struct inself, not the individual variables.
3 Comments
More Answers (1)
Guillaume
on 24 Mar 2020
Edited: Guillaume
on 24 Mar 2020
"How would I create and store that question tree/its outputs"
There are many options, which one you'd choose would be up to you, you could store the tree in a cell array, or as a digraph (which you could navigate with predecessors and successors), or as a table, possibly in a containers.Map, etc. Similarly there are many options on what you store in your tree and how you actually create it. It requires some thinking as to what works best for your case.
Here, thinking of easy creation, the tree could be stored as a table so it can be imported directly. Each row of the table would an option. The one difficulty is differentiating leaves of the tree which terminate the navigation and sets the return value from the branches which have a title, dialog size, prompt, etc. for their successors. I'll just store them all as columns of the tables with some blank entries for the leaves and other blank entries for the branches. The nice thing is that the tree can be stored completely separately as a text file:
Node Parent IsLeaf Title Prompt Width Height ReturnValue
0 -1 0 "Main" "Select Main Fit" 160 145 0
1 0 0 "PolyX" "Selection Poly" 160 130 0
2 1 1 "Poly1" "" 0 0 1
3 1 1 "Poly2" "" 0 0 2
4 1 1 "Poly3" "" 0 0 3
5 1 1 "Poly4" "" 0 0 4
6 0 0 "ExponentialX" "Selection Exp" 160 130 0
7 6 1 "Exponent_1" "" 0 0 5
8 6 1 "Exponent_2" "" 0 0 6
9 0 0 "Option" "Select SubOption" 160 130 0
10 9 0 "SubOption1" "Select SubsubOpt" 160 130 0
11 10 1 "SubSub1" "" 0 0 7
12 10 1 "SubSub2" "" 0 0 8
13 9 1 "SubOption2" "" 0 0 9
I've amalgamated the option name and the Title of the dialog corresponding to that option under the same 'Title', that could be separate. The IsLeaf is not really necessary, it could be detected by the fact that the node is never a parent or by the ReturnValue of 0.
The above can easily be imported with:
tree = readtable('tree.txt'); %assuming it's saved as tree.txt of course
Now the function to navigate the tree could be:
function selection = TreePrompter(tree, allowbackup)
%tree: a table with variables Node, Parent, IsLeaf, Title, Prompt, Width, Height, ReturnValue
%allowbackup: optional flag (default true)
%selection: tree.ReturnValue of selected option or empty if cancelled
if nargin < 2
allowbackup = true;
end
%todo: validate inputs. May also want to check that the tree entries are consistent
%initialise navigation:
currentrow = find(tree.Node == 0);
selection = [];
%navigate the tree
while true
childrenrows = find(tree.Parent == tree.Node(currentrow)); %can't use logical array as we'll need to index into the children array
options = tree.Title(childrenrows);
if allowbackup && tree.Node(currentrow) ~= 0 %don't allow backup at root
options = [options; {'Back one level'}]; %#ok<AGROW>
end
selectedentry = listdlg('ListString', options, ...
'PromptString', tree.Prompt{currentrow}, ...
'Name', tree.Title{currentrow}, ...
'SelectionMode', 'single', ...
'ListSize', tree{currentrow, {'Width', 'Height'}});
if isempty(selectedentry)
return; %user cancelled
end
if selectedentry > numel(childrenrows) %can only be back up
currentrow = find(tree.Node == tree.Parent(currentrow)); %go back to parent
else
currentrow = childrenrows(selectedentry);
if tree.IsLeaf(currentrow) %navigation completed
selection = tree.ReturnValue(currentrow);
return;
end
end
end
end
The nice thing about this is that you can change the tree without having to change the code at all, or you can completely replace the UI without needing to touch the tree.
5 Comments
Guillaume
on 26 Mar 2020
"May I use this script of yours in my little project"
Anything posted on Answer is covered by the Creative Commons Attribution Share Alike 3.0 license, so yes as long as you comply with the license you can use and modify the code any way you want without any need to ask for permission. In term of credit, a link to my answer would be good enough.
"Could this also be implemented for something like this function? I assume I'd just have to split this up into several functions"
First question you need to answer is: is it worth the effort of refactoring? For just 4 questions, I'm not sure. If the same pattern is going to be repeated in this code or in other future code, it may be worth.
Second question is how flexible does this need to be. Here you have very different types of questions. Ideally, they would all be stored in the same tree (I'm not even sure it's a tree anymore!) but because they vary greatly in their structure (some are questdlg, some are listdlg, some are inputdlg) the information stored for each is very different. A table is probably no longer appropriate. If you store everything in just one tree, you would still have just one function that navigates the tree and prompt with the correct dialog.
But here, honestly, you may be better off going the full GUI route, using App Designer. Using UI tables for inputting vectors would certainly be kinder to your users than an inputdlg.
See Also
Categories
Find more on Matrix Indexing 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!