Search code examples
rplotvariadic-functionsgetter-setter

How to getPar and setPar to access the guts of par()


I am working on some generic accessor functions for the par() option in R.

getPar

getPar = function(key)
    {
    par()[[key]];   
    }

This works as expected.

getPar("mar");

setPar

# save memory ... restoreState ... pdf 
setPar = function(key, val)
    {
    # par(mar=c(0.25, 0.25, 0.25, 0.25)
    # R.O. indicates read-only arguments: These may only be used in queries and cannot be set. ("cin", "cra", "csi", "cxy", "din" and "page" are always read-only.)
    # https://www.rdocumentation.org/packages/graphics/versions/3.6.2/topics/par
    pnames = names( par(no.readonly = TRUE) );
    if(is.element(key, pnames))
        {
        par()[[key]] = val;
        }
    }

This one does not work:

mar = c(0.25, 0.25, 0.25, 0.25);
setPar("mar", mar);

And throws an error:

Error in par()[[key]] = val : invalid (NULL) left side of assignment

Any ideas on how I can write a setter function as outlined?

Yes, I understand, I can pass par(mar = c(0.25, 0.25, 0.25, 0.25)) directly to "set" the value. I am specifically looking for a solution that will work inside this simple setter function. A variadic approach.


Solution

  • The assignment to lists (i.e., [<- and [[<-) requires an object on the LHS of the assignment, not an expression that produces the list. Similarly,

    A <- list(a=1)
    A$b <- 2
    A
    # $a
    # [1] 1
    # $b
    # [1] 2
    list(a=1)$b <- 3
    # Error in list(a = 1)$b <- 3 : 
    #   target of assignment expands to non-language object
    

    I suggest you change setPar to actually set the value using par, not try to operate on the list.

    setPar = function(key, val)
        {
        # par(mar=c(0.25, 0.25, 0.25, 0.25)
        # R.O. indicates read-only arguments: These may only be used in queries and cannot be set. ("cin", "cra", "csi", "cxy", "din" and "page" are always read-only.)
        # https://www.rdocumentation.org/packages/graphics/versions/3.6.2/topics/par
        pnames = names( par(no.readonly = TRUE) );
        if(is.element(key, pnames))
            {
            par(setNames(list(val), key))
            }
        }
    
    par("mar")
    # [1] 5.1 4.1 4.1 2.1
    setPar("mar", 1:4)
    par("mar")
    # [1] 1 2 3 4