MATLAB uicontrol callback function handle output - function

This is a basic question, but I am having a hard time with it.
Basically, I have a callback-function assigned to the choices in a pop-up menu on a GUI. The code is as follows:
uicontrol(mainfigure, 'Style', 'popup',...
'String', 'A|B|C',...
'Position',[850 190 200 30],...
'Callback', #blockset);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [block] = blockset(hObj,evnt) %#ok<INUSD>
blockval = get(hObj,'Value');
if blockval == 1
block = 'A';
elseif blockval == 2
block = 'B';
elseif blockval == 3
block = 'C';
end
end
As you can see, it is simply assigning a string value to the different choices in the pop-up menu. I want to use these strings as input values to another function later in the script (which is also embedded in a uicontrol callback):
uicontrol(mainscreen, 'Style', 'pushbutton',...
'Position',[855 300 150 50],...
'String', 'START',...
'FontSize',10,'FontWeight','bold',...
'BackgroundColor', [.9 .9 .9],...
'CallBack', {#START_Callback, block});
The code as is doesn't work. But I can't figure out how to define the outputs for a uicontrol callback. I already defined "block" as the output for the blockset function, so how do I get the START_Callback to recognize it as input? Every time I try, it just tells me that "block" is an undefined function or variable.
Is there something I need to do with the " 'Callback', #blockset " line of code to get it to recognize the output from the function?
EDIT: Some cursory internet searching indicates that I probably have to use something like setappdata/getappdata, or another workaround method. However, I don't entirely understand the documentation on those. How do I use them in this situation?

the variable block would have to exist in the workspace when you do
uicontrol(mainscreen, 'Style', 'pushbutton',...
'Position',[855 300 150 50],...
'String', 'START',...
'FontSize',10,'FontWeight','bold',...
'BackgroundColor', [.9 .9 .9],...
'CallBack', {#START_Callback, block});
But it's the return value from your popup menu callback, so you can't do that, hence your matlab error.
To use setappdata and getappdata, you would need to store your popup menu's callback function's 'block' variable some figure's appdata property that would be visible to both callback functions, or if you want to be lazy, to the root figure.
e.g.
function [block] = blockset(hObj,evnt) %#ok<INUSD>
blockval = get(hObj,'Value');
if blockval == 1
block = 'A';
elseif blockval == 2
block = 'B';
elseif blockval == 3
block = 'C';
end
setappdata(0, 'block', block);
end
This will have stored the block variable to the root figure (that is, the main MATLAB window, denoted by 0), which really isn't a good thing to do as anything can change it as well. Instead you should try storing it to some handle graphics object that will be visible to both callbacks, such as your GUI figure. However, there's not enough information in your question for me to infer what you can use, so I'm using the root figure for illustrative purposes.
If you set the tag properties of your GUI objects, you can lookup their handles based on that, e.g. using h = findobj('Tag','my_tag') will give you the handle to the graphics object with the tag 'my_tag', which you can then set the appdata for via setappdata(h, 'var_name', var);. I would recommend using this instead of the root figure handle, as with the root figure you have no encapsulation.
With that said, then in your START_Callback function, instead of taking block as an input parameter, you'd use block = getappdata(0, 'block'); to get the root figure's block variable which you set in your blockset callback function. So your pushbutton declaration would become
uicontrol(mainscreen, 'Style', 'pushbutton',...
'Position',[855 300 150 50],...
'String', 'START',...
'FontSize',10,'FontWeight','bold',...
'BackgroundColor', [.9 .9 .9],...
'CallBack', #START_Callback);
and inside START_Callback:
function START_Callback(hObj,evnt)
block = getappdata(0, 'block');
%... other stuff
end

Related

Extracting color from complex function: " Cannot modify global variable 'cColor' in function."

I'd like to extract the "col" color value from this function to be used to paint plots or candle colors. But everything I try creates one error or another. I checked the Script Reference. Shouldn't there be some way to "return" a value, as is usually the case with most functions?
lset(l,x1,y1,x2,y2,col)=>
line.set_xy1(l,x1,y1)
line.set_xy2(l,x2,y2)
line.set_width(l,5)
line.set_style(l, line.style_solid)
line.set_color(l,y2 > y1 ? #ff1100 : #39ff14) //red : green
temp = line.get_price(l,bar_index) // another value to extract
The documentation is showing it like this:
line.new(x1, y1, x2, y2, xloc, extend, color, style, width) → series line
So in your code it's looking differently and also the "new" is missing.
Scrolling a bit up on the linked page shows that there exist indeed methods to retrieve some properties of the line object:
Lines are managed using built-in functions in the line namespace. They include:
line.new() to create them.
line.set_*() functions to modify the properties of an line.
line.get_*() functions to read the properties of an existing line.
line.copy() to clone them.
line.delete() to delete them.
The line.all array which always contains the IDs of all
the visible lines on the chart. The array’s size will depend on
the maximum line count for your script and how many of those you
have drawn. aray.size(line.all) will return the array’s size.
The most simple usage is to instantiate a line object with the correct values directly, like shown here:
//#version=5
indicator("Price path projection", "PPP", true, max_lines_count = 100)
qtyOfLinesInput = input.int(10, minval = 1)
y2Increment = (close - open) / qtyOfLinesInput
// Starting point of the fan in y.
lineY1 = math.avg(close[1], open[1])
// Loop creating the fan of lines on each bar.
for i = 0 to qtyOfLinesInput
// End point in y if line stopped at current bar.
lineY2 = open + (y2Increment * i)
// Extrapolate necessary y position to the next bar because we extend lines one bar in the future.
lineY2 := lineY2 + (lineY2 - lineY1)
lineColor = lineY2 > lineY1 ? color.lime : color.fuchsia
line.new(bar_index - 1, lineY1, bar_index + 1, lineY2, color = lineColor)
Getting the line color from outside is difficult or impossible though as there never exists a method to retrieve it while for other properties those methods exist.
So the most simple way is to create the same funcionality, to get the color that exists inside the line-object, outside too, or only outside.
currentLineColor = y2 > y1 ? #ff1100 : #39ff14
You could try to extend the line-object somehow like this:
line.prototype.get_color = function() {
return this.color;
};
console.log(line.get_color())
I'm not sure if the approach with the prototype is working but it's worth it to try if you need it.

Why one element of SubString Vector can not be tested into conditional evaluation if (Julia)?

I want to create a function in which, first, it filters one element of a dataframe in Julia. Second, it tests if the element is "missing". If the answer is rue, it return the value "0.0". My issue is that the control evaluation "if" does not work and I don t know why. If the element is "String" the control evaluation works, however, the element is a 1-element Vector{SubString{String}}: after filtering; thus, the control evaluation does not work. I would like to know why and it is possible to turn the vector element into a string object.
Note: "isequal", '==', '===' do not work either.
For example:
example_ped = DataFrame(animal = collect(1:1:11),
sire = [fill(0,5); fill(4,3); fill(5,3)],
dam = [fill(0,4); fill(2,4); fill(3,3)])
CSV.write("ped_example.txt",example_ped, header=true,delim='\t')
pedi = CSV.read("ped_example.txt",delim = '\t', header=true, missingstrings=["0"], DataFrame)
pedi[!,1]=strip.(string.(pedi[!,1]))
pedi[!,2]=strip.(string.(pedi[!,2]))
pedi[!,3]=strip.(string.(pedi[!,3]))
Part of the function
function computAddRel!(ped,animal_1,animal_2)
elder,recent = animal_1 < animal_2 ? (animal_1,animal_2) : (animal_2,animal_1)
sireOfrecent = ped.sire[ped.animal.==recent]
damOfrecent = ped[ped.animal.==recent,"dam"]
if elder==recent
f_inbreed = (sireOfrecent=="missing" || damOfrecent=="missing") ? 0.0 : 0.5*computAddRel!(ped,sireOfrecent,damOfrecent)
adiv = 1.0 + f_inbreed
return adiv
end
end
if the animal_1 and animal_2 are equal to 5
julia> sireOfrecent = pedi.sire[pedi.animal.==recent]
1-element Vector{Union{Missing, Int64}}:
missing
However, the control evaluation is false
julia> sireOfrecent=="missing"
false
julia> isequal(sireOfrecent,"missing")
false
Thank in advance for your time.
You should write:
ismissing(only(sireOfrecent))
The meaning of this:
only checks if you picked exactly one row (if not - you will get an error, as then there is ambiguity; if yes - you extract out the element from an array)
ismissing is a function that you should use to check if some value is missing.
Here are some examples:
julia> x = [missing]
1-element Vector{Missing}:
missing
julia> only(x)
missing
julia> ismissing(only(x))
true
julia> only([1, 2])
ERROR: ArgumentError: Collection has multiple elements, must contain exactly 1 element
julia> ismissing(only([1]))
false

Node-red - need a multi-input function for a number value

So I'm just getting to grips with node-red and I need to create a conditional global function.
I have two separate global.payloads set to a number value of either 0 or 1.
What I need to happen now is, if global.payload is equal to value 1 then follow this flow, if it is equal to value 0 then follow this one.
I'm just a little confused with the syntax for the function statement. Any help gratefully appreciated.
Since you haven't accepted the current answer, thought I'd give this a try.
I think this is what you need to handle inputs from two separate global contexts. I'm simulating them here with two separate inject nodes to demonstrate:
The checkconf inject node emits a 1 or a 0. Same for the meshstatus node. Substitute your real inputs for those inject nodes. The real work is done inside the function:
var c = context.get('c') || 0; // initialize variables
var m = context.get('m') || 0;
if (msg.topic == "checkconf") // update context based on topic of input
{
c = {payload: msg.payload};
context.set("c", c); // save last value in local context
}
if (msg.topic == 'meshstatus') // same here
{
m = {payload: msg.payload};
context.set('m', m); // save last value in local context
}
// now do the test to see if both inputs are triggered...
if (m.payload == 1) // check last value of meshstatus first
{
if (c.payload == 1) // now check last value of checkconf
return {topic:'value', payload: "YES"};
}
else
return {topic:'value', payload: "NO"};
Be sure to set the "topic" property of whatever you use as inputs so the if statements can discriminate between the two input. Good luck!
You can use the Switch node to do this, rather than a Function node.

AS3 Boolean seemingly not working

Ok, so this is obviously going to be something that I stupidly overlooked in my code, but I am having problems with a boolean check in as3. In the below if statement I set a boolean, I can confirm that the boolean is set in this if switch as I have run a trace to check that:
if(switchA && switchB){
if(Side == "LEFT"){
localAttachCoords.x = (-Parent.collision.SideLength - entity.collision.SideLength)/2
localAttachCoords.y = Parent.collision.SideLength/2 - (((TargNode-1)*8) + entity.collision.SideLength/2)
}
if(Side == "RIGHT"){
localAttachCoords.x = (Parent.collision.SideLength + entity.collision.SideLength)/2
localAttachCoords.y = -(Parent.collision.SideLength/2 - (((TargNode-1)*8) + entity.collision.SideLength/2))
}
if(Side == "UP"){
localAttachCoords.y = (Parent.collision.SideLength + entity.collision.SideLength)/2
localAttachCoords.x = -(Parent.collision.SideLength/2 - (((TargNode-1)*8) + entity.collision.SideLength/2))
}
if(Side == "DOWN"){
localAttachCoords.y = (-Parent.collision.SideLength - entity.collision.SideLength)/2
localAttachCoords.x = Parent.collision.SideLength/2 - (((TargNode-1)*8) + entity.collision.SideLength/2)
}
entity.attached = true
entity.Parent = Parent
}
This would all be well and good, but for the fact that in a function from another class, executed every frame, claims that the boolean was set to false, I confirmed this with another trace function.
This is the function, taken from the class whose instance is referred to as entity in the above switch:
public function update(){
if (physics) physics.update()
if (node && physics){
trace(attached)
if(attached){
physics.nodeUpdate()
}
}
}
This function claims in the trace that attached == false despite it being set true earlier with no other reference to the attached variable. Any help would be appreciated!
Pathing
There are some un-addressed variables in your issue, foremost being the pathing you're taking to check your variable. This is relevant because of namespaces/scope affect what each piece of code has access to.
If your functions and variables shared the same space (i.e., global/document/timeline), then any reference the the same named variable will always return the same value, unless (as LoremIpsum noted) it's being shadowed by a local variable by the same name.
Obviously, this is not the case since you're using public function which is a class-only declaration. If the boolean you're looking for is on the timeline, and the class wants to read that variable, you need to have a valid path to it. Instantiated classes that are DisplayObjects and have been added to the DisplayList have both parent and stage properties which you can use to access the timeline global namespace (thereby providing access to your boolean).
However, if the class is not a DisplayObject (e.g., it does not extend a Sprite, Shape, or MovieClip), then access to the timeline has to be provided manually, either by setting a property on the class, or passing an argument to a method on the class.
Further complicating the matter is if the Boolean exists in another class object (either instantiated or static), you'd then need a way to get between them. A case of A sees B, C sees B, but neither A or C see eachother.
Values
A boolean is always going to be false, even if the assigned value was null, so if your class is trying to reference a variable that it can't see, that value will always be false. For example...
var foo:Boolean = this["fiddlesticks"];
trace("foo = " + foo); // traces: "foo = false"
There is no property this.fiddlesticks, so while the resolved value is null, foo becomes false. Consider using hasOwnProperty(), which indicates whether an object has a specified property defined, and is a method available to all objects.
Switch
You don't have to manually create your own switch using if then else if, AS3 has its own switch statement.
switch (Side) {
case "LEFT":
// Do stuff for left
break;
case "RIGHT":
// Do stuff for right
break;
case "UP":
// Throw your hands up
break;
case "DOWN":
// Get down and boogie!
break;
}
I hope that all helps. I'd like to say exactly what's going on with the access to your Boolean, but there simply isn't enough information to say.
Cheers!

Scilab - calling another GUI within a GUI. Functions not working

I'm quite new to scilab, I have created two GUIs (see example below), with script 2 being called from script 1. However the function in script 2 don't seem to work. Can anyone help?
Script 1
'//////////
f=figure('figure_position',[0,0],'figure_size',[1250,650]);
//////////
delmenu(f.figure_id,gettext('File'))
delmenu(f.figure_id,gettext('?'))
delmenu(f.figure_id,gettext('Tools'))
toolbar(f.figure_id,'off')
handles.dummy = 0 ;
handles.exam=uicontrol(f,'unit','normalized','BackgroundColor', [0.5,1,1],'Enable','on','FontAngle','normal','FontName','helvetica','FontSize',[14],'FontUnits','points','FontWeight','bold','ForegroundColor',[0,0.5,0],'HorizontalAlignment','center','ListboxTop',[],'Max',[1],'Min',[0],'Position',[0.5,0.5,0.1,0.05],'Relief','flat','SliderStep',[0.01,0.1],'String','exam','Style','pushbutton','Value',[0],'VerticalAlignment','middle','Visible','on','Tag','obj102','Callback','exam_callback(handles)')
function exam_callback(handles)
close(f);
clear
exec('costs0-1.sce',-1) ;
endfunction`
Script 2
////////// Defining the figure (size, name etc)/////////////////////////////
f=figure('figure_position',[0,0],'figure_size',[1250,650],'auto_resize','on','background',[8]);
//////////
delmenu(f.figure_id,gettext('File'))
delmenu(f.figure_id,gettext('?'))
delmenu(f.figure_id,gettext('Tools'))
toolbar(f.figure_id,'off')
//Cabinet - TEXT
handles.obj17=uicontrol(f,'unit','normalized','BackgroundColor',[1,1,1],'Enable','on','FontAngle','normal','FontName','helvetica','FontSize',[12],'FontUnits','points','FontWeight','normal','ForegroundColor',[0,0,0],'HorizontalAlignment','center','ListboxTop',[],'Max',[1],'Min',[0],'Position',[0.15,0.93,0.1,0.05],'Relief','flat','SliderStep',[0.01,0.1],'String','Cabinet','Style','text','Value',[0],'VerticalAlignment','middle','Visible','on','Tag','obj17','Callback','')
// Cabinet - POP UP MENU
handles.service=uicontrol(f,'unit','normalized','BackgroundColor',[0.8,0.8,0.8],'Enable','on','FontAngle','normal','FontName','helvetica','FontSize',[12],'FontUnits','points','FontWeight','normal','ForegroundColor',[0,0.5,0],'HorizontalAlignment','center','ListboxTop',[],'Max',[1],'Min',[0],'Position',[0.25,0.93,0.15,0.05],'Relief','flat','SliderStep',[0.01,0.1],'String','1|2','Style','popupmenu','Value',[1],'VerticalAlignment','middle','Visible','on','Tag','service','Callback','service_callback(handles)')
// CALCULATE PUSHBUTTON
handles.Calculate=uicontrol(f,'unit','normalized','BackgroundColor',[0,0.8,0],'Enable','on','FontAngle','normal','FontName','helvetica','FontSize',[16],'FontUnits','points','FontWeight','bold','ForegroundColor',[0,0,0],'HorizontalAlignment','center','ListboxTop',[],'Max',[1],'Min',[0],'Position',[0.22,0.02,0.15,0.08],'Relief','raised','SliderStep',[0.01,0.1],'String','CALCULATE','Style','pushbutton','Value',[0],'VerticalAlignment','middle','Visible','on','Tag','Calculate','Callback','Calculate_callback(handles)')
// Resources- TEXT
handles.Resourcestxt=uicontrol(f,'unit','normalized','BackgroundColor',[1,1,1],'Enable','on','FontAngle','normal','FontName','helvetica','FontSize',[14],'FontUnits','points','FontWeight','bold','ForegroundColor',[0,0.5,0],'HorizontalAlignment','center','ListboxTop',[],'Max',[1],'Min',[0],'Position',[0.75,0.95,0.20,0.05],'SliderStep',[0.01,0.1],'String','Resources in hours','Style','text','Value',[0],'VerticalAlignment','middle','Visible','on','Tag','','Callback','')
// TOTAL hours - TEXT
handles.totalhourstxt=uicontrol(f,'unit','normalized','BackgroundColor',[1,1,1],'Enable','on','FontAngle','normal','FontName','helvetica','FontSize',[14],'FontUnits','points','FontWeight','bold','ForegroundColor',[0,0.5,0],'HorizontalAlignment','center','ListboxTop',[],'Max',[1],'Min',[0],'Position',[0.75,0.75,0.12,0.05],'SliderStep',[0.01,0.1],'String','Total Hours','Style','text','Value',[0],'VerticalAlignment','middle','Visible','on','Tag','','Callback','')
// hardware hours - text
handles.totalhours=uicontrol(f,'unit','normalized','BackgroundColor',[0.95,1,1],'Enable','on','FontAngle','normal','FontName','helvetica','FontSize',[14],'FontUnits','points','FontWeight','bold','ForegroundColor',[0,0.5,0],'HorizontalAlignment','center','ListboxTop',[],'Max',[1],'Min',[0],'Position',[0.88,0.75,0.08,0.05],'SliderStep',[0.01,0.1],'String','','Style','text','Value',[0],'VerticalAlignment','middle','Visible','on','Tag','totalhours','Callback','')
function Calculate_callback(handles)
if handles.service.value == 1 then
resource_hrs = 2
end
if handles.service.value == 2 then
resource_hrs = 10
end
set(handles.totalhours,'String',string(resource_hrs));
endfunction
Problem
It is a scoping problem. When function exam_callback() gets called it runs the other script with exec('costs0-1.sce',-1).
In that script you define the function Calculate_callback(handles). This goes out of scope and is deleted when exam_callback() is finished and as such can't be called when the button is pressed.
The second problem is that the handles are not globally affected, so when leaving exam_callback() the handles of the second Cost Gui are not added to handles.
Solution
You can move the generating of the GUI into a function createCostGui() and then load script2 at the start of script1 with exec('costs0-1.sce',-1);.
To make Calculate_callback(handles) function discard the handles argument and use the tags to find the handles
function Calculate_callback()
serviceHandle = findobj('tag','service');
if serviceHandle.value == 1 then
resource_hrs = 2
end
if serviceHandle.value == 2 then
resource_hrs = 10
end
totalHoursHandle = findobj('tag','totalhours');
set(totalHoursHandle,'String',string(resource_hrs));
endfunction
Further remarks
Text elements are generally static and thus don't need a Callback argument.
If you want an argument to stay at its default value, you don't need to specify them.
From the Scilab documentation:
h = uicontrol(PropertyName, PropertyValue,...) creates an uicontrol and assigns the specified properties and values to it. It assigns the default values to any properties you do not specify. The default uicontrol style is a "Pushbutton". The default parent is the current figure. See the Properties section for information about these and other properties.
Small remark on your question
Next time an error message could help with making your question more specific.