MATLAB Answers

Function overwrites output with a different number

17 views (last 30 days)
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

Show 1 older comment
Claudius Simon Appel
Claudius Simon Appel on 22 Mar 2020
@John D'Errico, as a response to your comment:
Ok, I`ve done that. I've set breakpoints on line 33, 271 and 272. 37 marks the line for the Fourier-fits. If you choose Fourier3, the code then goes to line 46, where it defines "LPfittypeindx=14". Afterwards, it goes to line 57. This line contains the "end" of the Fourier-case-switch (Fourier 1-8) and is part of the switch on line 40.
After line 57, it goes straight to 271, the "end" of the switch controlling the general overview of different fit types (poly, exponential, fourier, etc.). It then goes to the next breakpoint at 272, where I put in a message to be displayed when the code reaches it. It then goes to the breakpoint at the very last line, the "end" of the function itself. Until now, this end has not been run, and the LPfittypeindx is still on the correct number 14. If I NOW click on continue, as far as I understand it, the function should just finish and, as I called for the output LPfittypeindx, give me that variable LPfittypeindx.
However, when I click on continue to run the last line, it redefines LPfittypeindx as 4. (Note, when doing the same thing with other groups of fittype, it can redefine as other numbers. Doing it with Sum of Sines (any of them) redefines it as 3 in the end. I haven't tested all possibilities yet.
I am not sure, honestly this confuses me even more.the function itself has reached its end, how can anything possibly be defined again?
I have attached the file with added breakpoints at every step of the function.
Guillaume
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
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.

Sign in to comment.

Accepted Answer

dpb
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

Guillaume
Guillaume on 22 Mar 2020
As it looks like the whole purpose of the function is to navigate the user through a tree of questions and as long as we're talking about refactoring, I would suggest a completely different design:
Store the question tree inside one variable. Exact storage format to be defined, probably a cell array where a row is dialog title, dialog size, question title and then a cell per possible option where each cell might be the option text and then the same again a cell array with dialog title, dialog size, etc... so nested cell arrays until a leaf of the question tree is reached in which case the cell stores the desired LPfittypeIndx for this option.
The code is then completely generic, it doesn't care about what the actual question tree is. It just prompts the top-level question and navigate the tree appropriately until a leaf is reached. It could even allow backtracking through the tree if the user realise they've chosen the wrong option. There would be no switch at all, probably just a while loop. It could even be implemented through recursion.
One major advantage of this design is that if the choice is to be changed in the future, the code wouldn't need to be modified. The only modification required would be the addition/removal/editing of the cells of the tree array.
Claudius Simon Appel
Claudius Simon Appel on 24 Mar 2020
Hello,
thank you two, I am sorry for answering so late, but I haven't been able to sit down recently. How would I create and store that question tree/its outputs, Guillaume? I got rid of the shenanigans inside that function that you pointed out and implemented your suggestion about typeindices. I also tidied up what I actually needed out of the function as actual output. And a whole lot of other crap that needed reworking.
However, I am curious about how to set up that question tree if only for the possibility to go backwards. Right now, misclicking once or misdefining a matrix-line in the beginning (not this function) basically results in the entire thing running into a wall. So being able to go back and redo a previous step (goto hehe, no worries) that was done wrong would be nice. I tried looking for stuff regarding that when it was mentioned here, but couldn't really find something. Maybe I was looking for the wrong things, I dunno.
As the entire purpose of this project is to do nothing more than call a function, misclicking would result in either having to know the name of the respective subfunction and how to call it, or running the entire thing again (which is still faster than coding all of that from the ground up everytime, but mistakes can happen). So I am interested in how to implement backtracking at certain points.
I am a bit unsure about how to show code when asking questions from here on onwards, as the entire thing now spans 10, soon 11 functions and about 800 lines of code right now. Sharing all of it, which would be somewhat necessary to explain what I am going for, or even if I'd wanted someone who has more experience with matlab and coding to give it a look over for big red flags seems increasingly hard. This thing has been reworked from the ground up four times at different stages due to stuff mentioned by someone that I didn't even know were a thing.
Still, thank you.

Sign in to comment.

More Answers (1)

Guillaume
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

Show 2 older comments
Claudius Simon Appel
Claudius Simon Appel on 25 Mar 2020
I have two questions:
1) May I use this script of yours in my little project? I am not sure whether or not I will upload that whole thing once it is complete. I wouldn't do so without permission obviously.
2) Could this also be implemented for something like this function? I assume I'd just have to split this up into several functions to be called whenever one arrives at their respective point. It defines 2/4 matrices of rowlength "LPNofRepeatsXY" to be set up into matrices which are used later on for pretty much everything. One problem with this approach is that if the user makes two rows of unequal length, the function runs into a wall, and one has to recall it again. Would it be possible to make each step in which a matrix is defined retraceable in the case one ducks up? Also, the first implementation works now.
function [LPErrorbarflag,LPmatx,LPmaty,LPmaterrorx,LPmaterrory] = LPDefinefun
InputCheckFinished=1;
for InputCheck=1:1:InputCheckFinished
answer = inputdlg('How many X/Y are plotted?:',...
'Sample', [1 50]);
LPNofRepeatsXY= str2double(answer{1});
LPErrorbar_Flag=questdlg('Wanna show how bad you are?','Errorbars?','Yes.','NO!','NO!'); %Want Errorbars?
end
switch LPErrorbar_Flag %this Flag triggers the definition and use of Errorbars later on, as well as the LPplotfun not plotting the datapoints themselves in case of existing errorbars (as those already do that by design).
case 'Yes.'
LPErrorbarflag=1;
case 'NO!'
LPErrorbarflag=0;
end
for j=1:1:LPNofRepeatsXY %creates the matrix of y-vectors (usually setting data) line for line
answer = inputdlg('Enter x-Vector with spaces line by line, 1 iteration=1 vector later on:',...
'Sample', [1 100]);
LPx_vector= str2num(answer{1});
LPmatx(j,:)=LPx_vector;
end
for j=1:1:LPNofRepeatsXY %creates the matrix of y-vectors (usually measurement data) line for line
answer = inputdlg('Enter y-Vector with spaces line by line, 1 iteration=1 vector later on:',...
'Sample', [1 100]);
LPy_vector= str2num(answer{1});
LPmaty(j,:)=LPy_vector;
j=j+1;
end
if LPErrorbarflag==1
for j=1:1:LPNofRepeatsXY
answer = inputdlg('Enter X-uncertainty with spaces line by line, 1 iteration=1 vector later on:',...
'Sample', [1 100]);
LPx_uncertainty= str2num(answer{1});
LPmaterrorx(j,:)=LPx_uncertainty;
end
for j=1:1:LPNofRepeatsXY
answer = inputdlg('Enter Y-uncertainty with spaces line by line, 1 iteration=1 vector later on:',...
'Sample', [1 100]);
LPy_uncertainty= str2num(answer{1});
LPmaterrory(j,:)=LPy_uncertainty;
end
else %if LPErrorbarflag=0
LPx_uncertainty=1;
LPy_uncertainty=1;
LPmaterrorx=1;
LPmaterrory=1;
end
end
Guillaume
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.
Claudius Simon Appel
Claudius Simon Appel on 26 Mar 2020
Hmm, I suppose I will loom into the App Designer next then :) On the one hand I am happy this project never seems to end, there is so much stuff you can learn ^^

Sign in to comment.

Sign in to answer this question.

Tags

Products


Release

R2019b

Translated by