Manipulate function with variable number of controls - r

My objective is to have a function that can be called with an array of n datasets. This function will call manipulate and create a plot with a control box. This box will have as many checkboxes as there are datasets (i.e. n). Each checkbox will allow to show/hide the corresponding dataset on the plot.
For the purpose of keeping it simple, I will assume each dataset is a simple string instead.
manipulate works fine when the controls are known. Here, for a single control:
manipulate(plot(0,0,main=b), b=checkbox(TRUE, 'bool'))
However, in my case I need a variable number of controls. I'm able to create a list of controls like so:
dataList = c('a', 'b', 'c')
ctrls = list()
for(data in dataList) {
ctrls[[data]] = checkbox(TRUE, data)
}
manipulate(plot(0,0), ctrls)
Now let's see a minimal use case : a function that will create a plot. Its title will be the concatenation of all dataset names which have the value TRUE.
My initial idea was to pass the list of controls to the function, so I can access each control there.
foo <- function(dataList, ctrls) {
print(dataList)
title = ''
for(data in dataList) {
if (ctrls[[data]]) { # this fails
title=cat(title, data)
}
}
plot(0,0,main=title)
}
manipulate(foo(dataList, ctrls), ctrls)
The above fails because ctrls[[data]] is not the value of the control.
Is there a way to access the current value of a control when it's given to manipulate inside a list?

After some fiddling around I found that I could utilize the get function to retrieve the variables' values from the scope before calling foo.
Firstly, I prepare the list of controls
series = list('a', 'b', 'c')
controls = list()
for(data in series) {
controls[[data]] = checkbox(TRUE, data)
}
Then we have the callback function which takes a list as argument
foo <- function(data, bools) {
t=""
for(i in seq_along(data)) {
if(bools[[i]]) t = c(t, data[[i]])
}
plot(0,0,main=t)
}
Finally there's the call to manipulate. Notice I'm mapping the list of series names with their corresponding checkbox's state (TRUE or FALSE).
manipulate(
foo(lapply(series, function(e) get(e))),
controls
)

Related

GMS2 returns instance_create_layer :: specified layer "text_layer" does not exist even though the layer exists how do i fix this?

heres the code
var _obj;
if (instance_exists(obj_text)) _obj = obj_txt_queued; else _obj = obj_text;
with (instance_create_layer(0, 0, "text_layer", _obj))
{
msg = argument[0];
if (instance_exists(other)) originInstance = other.id else originInstance = noone;
if (argument_count > 1) background = argument[1]; else background = 1;
}
with (obj_phae)
{ if (state != scr_player_state_lock)
{
lastState = state;
state = scr_player_state_lock;
}
}
[layers](https://i.stack.imgur.com/9u9tD.png)
I tried removing any extra rooms that were not needed and I tried changing the layer name to something else.
I also tried using var instance_create_layer() but that obviously didn't work
I'm a bit confused at this part:
with (instance_create_layer(0, 0, "text_layer", _obj))
Especially the with(), as that function will go through every object in the room if it sees an object within the parameter, since you suggested to create a new object with it, I'm surprised it doesn't create an infinite loop. Maybe it works, I've never tried it myself, but I think there's a more logical way to assign variables from one object to a newly created object.
Assuming you want to use the With() statement to address the variables within the _obj, I think you can manage something similair through this function:
var object = instance_create_layer(0, 0, "text_layer", _obj)
object.msg = argument[0];
object.originInstance = id
if (argument_count > 1) object.background = argument[1]; else object.background = 1;
It's probably a given at this point, but double-check that this part of code can only run if it's in the same room that has a layer called "text_layer"
In the worst case, you may also try out instance_create_depth() and use the build-in depth variable from the object instead of the layer names. Using depth is more flexible, but less organised than layers.

Something like a Scala Option / Optional in R?

Is there something in R (either a package or base idiom) that is like an Option as found in Scala and other languages (see tag optional for details). Specifically, I'm looking for the following features some object that can:
signify the absence of a value but easily
hold attributes
return a default value in the face of having no contained value without requiring that the result of the default value be calculated unless it is actually needed
I'm sure there are a lot of other nice characteristics of Options that I haven't fully recognized as I'm relatively new to the idiom. Any answer that can provide more than the above listed features gets bonus points, especially if the additional features can be described well.
I tried writing a poor substitute using an R6 class (below). Anything that works better or is more idiomatically aligned with R would be greatly appreciated.
library(R6)
Option <- R6Class("Option",
public = list(
initialize = function(value=NULL) {
self$value <- value
}
,get = function() {
return(self$value)
}
,set = function(value) {
self$value <- value
return(value)
}
,getOrElse = function(...) {
if(self$isDefined()) {
return(self$value)
} else {
return(eval(...))
}
}
,isDefined = function() {
return(!all(is.null(self$value)) && !all(is.na(self$value)))
}
, value = NULL
)
,private = list()
,active = list()
) #end Option
Example:
bob <- Option$new()
bob$isDefined() == FALSE
bob$getOrElse("a") == "a"
bob$getOrElse({Sys.sleep(2);"b"})=="b"
bob$set(value = "a")
bob$isDefined() == TRUE
bob$getOrElse({Sys.sleep(2);"b"})=="a"

d3.js equivalent to columns in R dataframes

I have some data stored in this format (except many cases more):
var data = [
{"name":"John", "team":"team1"},
{"name":"Megan", "team":"team2"},
{"name":"Rupert", "team":"team2"},
{"name":"Albert", "team":"team1"}
];
I want to create this:
var colourScale = d3.scale.ordinal()
.range(a)
.domain(b)
"a" being an array of all levels of "team" (i.e. ["team1","team2"] in this case).
"b" being an array of ordinal colours of the same length as "a".
colourScale() should take the "team"-value as input and return a unique colour for each team.
How do I create "a" and "b"? Is there something equivalent to R's levels(data[ ,"team"]) in javascript or d3.js?
It's not exactly your solution as you don't explicitly find your specified a or b, but I found
var colourScale = d3.scale.category10();
function colour(d) { return d.team; }
and on the object you want to colour, bound to the appropriate data, chain
.style("fill", function(d) { return colourScale(colour(d)); });
has the effect that I assume you're searching for. Hope this helps.
I think there are some extra steps you need to do. You need first to create a 'unique' set of possible domain values. Then you can create a function that maps each value to a color. Something like this perhaps:
// A function to get unique values, can be optimized further
function unique(x) {
return x.reverse().filter(function (e, i, x) {return x.indexOf(e, i+1) === -1;}).reverse();
}
var data = [
{"name":"John", "team":"team1"},
{"name":"Megan", "team":"team2"},
{"name":"Rupert", "team":"team2"},
{"name":"Albert", "team":"team1"}
];
// An arbitrary set of colors
colors = ['#005824','#1A693B','#347B53','#4F8D6B','#699F83','#83B09B','#9EC2B3','#B8D4CB','#D2E6E3','#EDF8FB','#FFFFFF','#F1EEF6','#E6D3E1','#DBB9CD','#D19EB9','#C684A4','#BB6990','#B14F7C','#A63467','#9B1A53','#91003F']
//Create the ordinary scale based on your color set above
colorScale= d3.scale.ordinal()
.domain(unique(data.map(function(d){return d.team;})))
.range(colors)
Then you can access the color by:
.style("fill",function(d){return colorScale(d.team);})
Hope this helps.

Any alternative in R to encapsulate and pass data like objects do

The followings are the data to be passed:
get.member.x = function() {
return( list(info.file='x') )
}
get.member.y = function() {
return( list(info.file='y') )
}
I want to use the data in a function. I can pass these data in two ways: 1. Global variables 2. Argument passing.
This is how to pass the data using global variables:
test = function() {
print(get()$info.file)
}
main3 = function(){
get <<- get.member.x
test()
get <<- get.member.y
test()
}
This is how to pass the data using argument passing:
test2 = function(get) {
print(get()$info.file)
}
main2 = function(){
get = get.member.x
test2(get)
get = get.member.y
test2(get)
}
The result of executing the code is here:
> main2()
[1] "x"
[1] "y"
> main3()
[1] "x"
[1] "y"
Now, I wonder if there is any better alternative than these two ways to pass data. Both methods have some disadvantages.
Using global variables is dangerous, because it has side effects on other parts of the code.
Using argument passing is safe but it clutters the function arguments overall the code. In every function where I need these data members, I will have to pass the data as arguments to the caller and called functions.
If there was a way to encapsulate data members in objects, we could overcome these two issue.
Is there any better alternative way of solving this problem? Or do you think that the current way is better than encapsulating the data in objects?
Update:
What do I try to do with this?
My intention is to change the behaviour of functions without changing the code of the functions such that common code is reused. Consider the following code:
test.duplicate = function() {
result = common.fun.1()
result = common.fun.2()
}
common.fun.1 = function() {
# common steps
result = different.fun.1()
# common steps
}
common.fun.2 = function() {
# common steps
result = different.fun.2()
# common steps
}
Above, common.fun.1 and common.fun.2 have a lot of common code. But since one line is different, I have duplicated all the common code.
To prevent the duplication of common code, I can encapsulate the changing part into an external parameter injected into the function:
test.reuse = function() {
result = common.fun()
}
common.fun = function() {
# common steps
result = get()$different.fun()
# common steps
}
Now, in order to change the behaviour we need to change the injected parameter:
get.member.x = function() {
return( list(different.fun=different.fun.1) )
}
get.member.y = function() {
return( list(different.fun=different.fun.2) )
}
get <<- get.member.x
test.reuse()
get <<- get.member.y
test.reuse()
So, we eliminated the duplicated code while changing the behaviour of the function.

How use a variable name to point different data types with the same name?

I have 2 List one stores the name of filterable columns(of type DropDown) and another store the values to load in those filterable columns.
List<string> filterableFields = new List<string>() { "A_B", "C_D", "E_F" };
List<string> AB, CD , EF;
Now at the run time I get the data from web service and I have written a function to to extract values for these filterable fields and store the values to 2nd List.
private void prepareListForFilterableColumns(XDocument records)
{
foreach (var currentField in filterableFields)
{
var values = (from xml in records.Descendants(z + "row")
let val = (string)xml.Attribute("ows_" + currentField.Replace("_", "_x0020_"))
where val != ""
orderby val
select val
).Distinct();
switch (currentField)
{
case "A_B": AB = values.ToList(); break;
case "C_D": CD = values.ToList(); break;
}
}
}
Now I was thinking that instead of hard coding the assignment in swtich case block, If I could just use the first List name "A_B" and replace "_" from it to point to my 2nd List and assign values.ToList() to it.
I understand that c# is a static language, So not sure if we can achieve this, but IF I can it will make my function generic.
Thanks a lot in advance for time and help.
Vishal
You could use a dictionary of lists of strings instead of 3 lists to store the values.
Dictionary<string, List<string>> val lists = new Dictionary<string,List<string>>();
And make the keys of the dictionary equal to the filterables: "AB", "CD",..
then, instead of AB you would use valLists["AB"] and could then reference reach list based on a string key.
The other option would be to use reflection but that would be slower and unnecessarily a bit more complicated.

Resources