16

I would like to be able to modify a hidden function inside an R package in an "automated" way, like using fixInNamespace, but where I can write the code in advance, and not in an "edit" window which fixInNamespace does. I think assignInNamespace could do the job, but currently it's not working. Here's an example of the problem.

require(quantmod)

getSymbols("AAPL")

chartSeries(AAPL)  # Works fine up to here. 

Now say I want to yaxis ticks to be drawn on the left side of the plot, instead of the right. This can be done by modifying the source code in the quantmod package. The relevant code for modifying the plot layout is in a hidden quantmod function called chartSeries.chob.

This could be done by doing this:

fixInNamespace("chartSeries.chob", ns = "quantmod")

and in the edit window, manually modify line 117 from axis(4) to axis(2), click OK, and again run chartSeries(AAPL) (now the y axis labels will plot on the left side of the plot). Everything is good, the plot is generated as expected, no problems.

But ... now suppose I want to modify chartSeries.chob in advance (in an automated way), presumably by sourcing a modified version of the chartSeries.chob function, without using the edit window. I might want modify dozens of lines in the function for example, and opening the edit window each time for a new R session is not practical.

How can I do this?

Right now I am doing this, which is not working:

assignInNamespace("chartSeries.chob", value = chartSeries.chob2, ns = "quantmod")

where I source from the console a full copy of chartSeries.chob with the modified code on line 117.

chartSeries.chob2 <- function (x) 
{
old.par <- par(c("pty", "mar", "xpd", "bg", "xaxs", "las", 
                   "col.axis", "fg"))
  on.exit(par(old.par))
....

[Edit On 117:] axis(2)
...
}

When I run from the console:

chartSeries(AAPL)

or

quantmod:::chartSeries(AAPL)

I get errors -- the calls to other functions in quantmod from within the chartSeries.chob function are not found, presumably because the edited chartSeries.chob function is not in the quantmod namespace?

I notice that when typing quantmod:::chartSeries.chob from the console after the assignInNamespace command, there is no environment: namespace:quantmod at the end of the function definition.

But if I do the fixInNamespace modification approach, when I type quantmod:::chartSeries.chob, then I do see environment: namespace:quantmod appended to the end of the function definition.

FXQuantTrader
  • 6,821
  • 3
  • 36
  • 67

1 Answers1

21

Since fixInNamespace calls assignInNamespace you should be able to get it to work, the problem is probably that the environment is not the same and possibly some other attributes. If you change those to match then I would expect it to work better, possibly using code like:

tmpfun <- get("chartSeries.chob", envir = asNamespace("quantmod"))
environment(chartSeries.chob2) <- environment(tmpfun)
attributes(chartSeries.chob2) <- attributes(tmpfun)  # don't know if this is really needed
assignInNamespace("chartSeries.chob", chartseries.chob2, ns="quantmod")

Another option for some changes would be to use the trace function. This would make temporary changes and would be fine for inserting code, but I don't know if it would be reasonable for deleting commands or modifying in place (specifying an editor that changed the code rather than letting you change it might make this possible).

Greg Snow
  • 48,497
  • 6
  • 83
  • 110
  • tmpfun <- get("chartSeries.chob", envir = "quantmod") doesn't work because chartSeries.chob is a hidden function in the quantmod package. If I wanted to get a copy of a visible function, like "chartSeries", then tmpfun <- get("chartSeries.chob", envir = "quantmod") would work. How can I get a copy of this invisible function? – FXQuantTrader Apr 24 '14 at 22:07
  • 2
    @FXQuantTrader, sorry that was a typo that I have now fixed, it should be `envir` instead of `ns` and you need the `asNamespace`, I copied the wrong part from the code of `fixInNamespace`. – Greg Snow Apr 24 '14 at 22:09
  • 3
    Ah now it works! Excellent. The secret sauce was to set envir = asNamespace("quantmod"), rather than something like envir = as.environment("package:quantmod"). A bit confusing but your solution works. Thank you! And in case any one down the track is interested, attributes(chartSeries.chob2) <- attributes(tmpfun) doesn't seem necessary to get assignInNamespace to work right. – FXQuantTrader Apr 24 '14 at 23:01
  • 2
    I try to do this with a visible function from the package fame, but whenever I run `assignInNamespace("getfame", getfame2,ns = "fame")` or `assignInNamespace("getfame", getfame2,ns = asNamespace("fame"))` II get the old package default in return when i type `getfame`. – Matt Bannert Feb 25 '15 at 18:04
  • 1
    @Matt Bannert Try putting the package namespace in front of the function call for visible functions. e.g. fame:::getfame . Then it should work; by default R is going to still pick the original function. If I recall correctly, I think if you unload the package, fix in namespace, then reload the package, you may not need to put the namespace in front too. – FXQuantTrader Feb 26 '15 at 00:59
  • 1
    @FXQuantTrader the problem is that `getfame` is kinda low level and typically don't call it on my own. It's been called by various function from another package author (whom I talked to but need a solution til the fix is up) . In the meantime I even made direct calls without the `fame::` but dependent package still call the old function even though they DON'T have `fame::` in their calls. If they had would ot have to do this cause my problems are caused by masking these functions. – Matt Bannert Feb 26 '15 at 07:41
  • 1
    @Matt Bannert Hm in your case I would just edit the source code of the original package and recompile it with your fixes, rather than do the temporary code fixes as in this question – FXQuantTrader Feb 26 '15 at 20:39