Function overwrites output with a different number

1 回表示 (過去 30 日間)
Claudius Simon Appel
Claudius Simon Appel 2020 年 3 月 22 日
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 件のコメント
Guillaume
Guillaume 2020 年 3 月 22 日
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 2020 年 3 月 22 日
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.

サインインしてコメントする。

採用された回答

dpb
dpb 2020 年 3 月 22 日
編集済み: dpb 2020 年 3 月 22 日
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 件のコメント
dpb
dpb 2020 年 3 月 22 日
+23! :)
Claudius Simon Appel
Claudius Simon Appel 2020 年 3 月 24 日
編集済み: Claudius Simon Appel 2020 年 3 月 24 日
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.

サインインしてコメントする。

その他の回答 (1 件)

Guillaume
Guillaume 2020 年 3 月 24 日
編集済み: Guillaume 2020 年 3 月 24 日
"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 件のコメント
Guillaume
Guillaume 2020 年 3 月 26 日
"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 2020 年 3 月 26 日
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 ^^

サインインしてコメントする。

カテゴリ

Help Center および File ExchangeLoops and Conditional Statements についてさらに検索

タグ

製品


リリース

R2019b

Community Treasure Hunt

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

Start Hunting!

Translated by