Modifying an R package function for current R session; assignInNamespace not behaving like fixInNamespace? - r

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.

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).

Related

ProgressBar in IJulia printing every new line

I am currently learning Julia and have been practicing in the Jupyter notebook environment. However, the ProgressBar package (similar to TQDM in python) is updated every new line instead of updating on the same line (picture attached). Is there any way to fix this? Thanks.
UPDATE : Here is the full function that I wrote.
function spike_rate(raw_dat, width)
N = size(raw_dat)[1]
domain = collect(1:N);
spike_rat = zeros(N);
for i in ProgressBar(1:N)
dx = i .- domain;
window = gaussian.(dx, width);
spike_rat[i] = sum(window .* raw_dat) ./ width;
end
return spike_rat;
end
This seems to be a known issue with ProgressBars.jl, unfortunately. It's not clear what changed to make these progress bars not work properly anymore, but the maintainer's comment says that tqdm uses "a custom ipywidget" to make this work for the Python library, and that hasn't been implemented for the Julia package yet.
To expand on #Zitzero's mention of ] up, that calls Pkg.update() which also prints a progress bar - so the suggestion is to use the mechanism Pkg uses for it. Pkg has an internal module called MiniProgressBars which handles this output.
Edit: Tim Holy's ProgressMeter package seems well-maintained, and is a much better option than relying on an internal non-exported Pkg submodule with no docs. So I'd recommend ProgressMeter over the below.
The Readme mentions a caveat regarding printing additional information with the progress bar when in Jupyter, which likely applies to MiniProgressBar as well. So, using ProgressMeter, and separating the progress output vs other relevant output to different cells, seems like the best option.
(not recommended)
using Pkg.MiniProgressBars
bar = MiniProgressBar(; indent=2, header = "Progress", color = Base.info_color(),
percentage=false, always_reprint=true)
bar.max = 100
# start_progress(stdout, bar)
for i in 1:100
sleep(0.05) # replace this with your code
# print_progress_bottom(stdout)
bar.current = i
show_progress(stdout, bar)
end
# end_progress(stdout, bar)
This is based on how Pkg uses it, from this file. The commented out lines (with start_progress, print_progress_bottom, and end_progress) are in the original usage in Pkg, but it's not clear what they do and here they just seem to mess up the output - maybe I'm using them wrongly, or maybe Jupyter notebooks only support a subset of the ANSI codes that MiniProgressBars uses.
There is a way, the package module does that as far as I know when you do:
] up
Could you share a little of your code?
For example, where you define what is written to the console.
One guess is that
print("text and progressbar")
instead of
println("text and progressbar")
could help, because println() always creates a new line, while print() should just overwrite you current line.

Editing a function in R using trace?

I noticed there is a bug in a function from a package I want to use. An issue has been made on GitHub, but the creator hasn't adressed this yet, and I need the function as soon as possible.
Therefore I want to edit the code. Apparently this is possible by editing the source, repacking and installing the entire package, I can rewrite the function and reassign the namespace, but also possibly by just editing the function in the current session using trace().
I already found out I can do:
as.list(body(package:::function_inside_function))
The line I want to edit is located in the second step of the function.
Specifically, it is this line in the code I need to edit. I have to change ignore.case to ignore.case=TRUE. An example in case the link dies:
functionx(){if{...} else if(grepl("miRNA", data.type, ignore.case)) {...}}
I haven't really found a practical example on how to proceed from here, so can anyone show me an example of how to do this, or lead me to a practical example of using trace? Or perhaps reassigning the function to the namespace?
For your specific case, you could probably indeed work around it using trace.
From the link you provide I don't know why you speak of a function inside a function, but this should work:
# example
trace("grepl", tracer = quote(ignore.case <- TRUE))
grepl("hi", "Hi")
## Tracing grepl("hi", "Hi") on entry
## [1] TRUE
# your case (I assume)
trace("readTranscriptomeProfiling", tracer = quote(ignore.case <- TRUE))
Note that this would be more complicated if the argument ignore.case that you want to fix wasn't already at the right position in the call.
I faced a similar problem once and solved it using assignInNamespace(). I don't have your package installed so I cannot be sure this will work for you, but I think it should. You would proceed as follows:
Make the version of the function you want, as edited:
# I would just copy the function off github and change the offending line
readTranscripttomeProfiling <- function() {"Insert code here"}
# Get the problematic version of the function out of the package namespace
tmpfun <- get("readTranscripttomeProfiling",
envir = asNamespace("TCGAbiolinks"))
# Make sure the new function has the environment of the old
# function (there are possibly easier ways to do this -- I like
# to get the old function out of the namespace to be sure I can do
# it and am accessing what I want to access)
environment(readTranscripttomeProfiling) <- environment(tmpfun)
# Replace the old version of the function in the package namespace
# with your new version
assignInNamespace("readTranscripttomeProfiling",
readTranscripttomeProfiling, ns = "TCGAbiolinks")
I found this solution in another StackOverflow response, but cannot seem to find the original at the moment.

How to call plot.xts when using RScript

UPDATE: Thanks to Joshua's comment I realized the problem wasn't being inside a function, but inside a script. So I've edited the question and also provided my own answer.
When I use plot.xts() interactively it pops up a graphics window. I just tried it from inside a function (I'm troubleshooting a unit test and wanted some visual help) but nothing appeared. Aha, says I, I know the trick, just use print.
But print(plot.xts(x)) still shows no chart and instead prints my xts object! I.e. it does exactly the same as print(x).
The script I use to run unit tests is:
#!/usr/bin/Rscript --slave
library('RUnit')
options(warn=2) #Turn warnings into errors
#By naming the files runit.*.R, and naming the functions test*(), we can use
# all the defaults to defineTestSuite().
#NOTE: they have a weird default random number generator, so changed here
# to match the R defaults instead.
test.suite=defineTestSuite('tests',dirs=file.path('tests'),
rngKind = "Mersenne-Twister", rngNormalKind = "Inversion")
test.result <- runTestSuite(test.suite)
printTextProtocol(test.result)
The script below does two things:
plot to a device file, as you would in headless setting such as a webserver,
plot a screen device, I use x11() but you could use win().
There is no limitation imposed by Rscript. And this has nothing to do with xts as you could just as easily plot an xts object.
#!/usr/bin/Rscript
set.seed(42)
x <- cumsum(rnorm(100))
png("/tmp/darren.png")
plot(x)
dev.off()
x11()
plot(x)
Sys.sleep(3) # could wait for key pressed or ...
You cannot use graphics (or input functions like readline) when using RScript. However an RScript is still just R, so when you want to add something interactive (e.g. for troubleshooting) start R, then type:
source('run_tests.R')
When run this way, a line like this shows the chart:
plot(x$High);cat("Press a key");readline()
When run directly from the commandline with ./run_tests.R that line gets quietly ignored.

Plotting with gWidgetstcltk

I've made a gui with a button, the handler of which executes a plot method of a class I made, it uses ggplot2 and grid/gridExtra in a normal R session to put together the plot. It works fine using the plot() function in console. My button/handler is below:
Plotbutton <- gbutton("Plot!", container=MainWindow,
handler=function(h,...){
plot(analysis, linesplot=svalue(linecheck), lineplot.legend=svalue(linelegcheck), baseannotate=svalue(bpcheck), bpfreq=as.numeric(svalue(bpspin)), mosaic.bars=svalue(mosaiccheck), mosaic.scale=as.numeric(svalue(mosaicspin)), combine.plots=svalue(combinecheck), condense.mosaics=svalue(condensecheck), labfontsize=as.numeric(svalue(fontspin1)), legfontsize=as.numeric(svalue(fontspin2)))
})
I'm not sure of the reason, but loading gWidgets, gWidgetstcltk, and the package required for my plot method, and then clicking the button, nothing is plotted to the R graphics environment, however in RStudio the plot panel is not updated until the GUI is exited. The graphic does appear in a window in the normal Windows RGui though.
Can anyone suggest why this is happening?
The reason why it works from the R-console and not from a function is that the R-console will invoke print() automatically if nothing else is stated. Within a function R does not do this, so if you want to print a graph, you must explicitly state print(graph). Try
print(plot(analysis, linesplot=svalue(linecheck), lineplot.legend=svalue(linelegcheck), baseannotate=svalue(bpcheck), bpfreq=as.numeric(svalue(bpspin)), mosaic.bars=svalue(mosaiccheck), mosaic.scale=as.numeric(svalue(mosaicspin)), combine.plots=svalue(combinecheck), condense.mosaics=svalue(condensecheck), labfontsize=as.numeric(svalue(fontspin1)), legfontsize=as.numeric(svalue(fontspin2)))

How to preserve changes to function with fix() between R sessions?

If I edit a function with R v2.14.0 using fix(), those fixes are applied during the session.
For example, I might make the following edit to get a white background in a hive plot:
> library(HiveR)
> fix(plotHive)
... :%s/black/white/g
... :w
... :q
> plotHive(myHiveData)
I then get a white background in the hive plot, as expected.
But if I quit and reopen R, I have lost those changes, and the plot has a black background again.
How do I preserve the edits I make with fix() between R sessions?
EDIT
If I source() the modified plotHive() function, I get the following error:
> modifiedPlotHive <- source("modifiedPlotHive.R")
Error in source("modifiedPlotHive.R") :
modifiedPlotHive.R:1160:1: unexpected '<'
1159: }
1160: <
^
In addition: Warning message:
In readLines(file) : incomplete final line found on 'modifiedPlotHive.R'
The final line in the modified plotHive() function is:
<environment: namespace:HiveR>
If I remove this line before source()-ing, then the function no longer works.
Sorry I missed this when it came out, but the latest version of HiveR has the option to control the background color (available on CRAN 0.2-1) Bryan
Here's the safer way of doing what you want, referenced by #joran.
The sink/source pair is fine for dealing with R code files. But saving to text files and then reading back in other types of objects can strip them of important attributes, especially those relating to environments. That's what you just experienced.
The save/load pair stores objects in R's own binary format, so is much less liable to lose important information/environments attached to functions.
In this example, I define a personal version of ls, which differs from the base function in that it by default lists objects that start with a dot/period:
my_ls <- ls
fix(my_ls)
# 1) On the first line, change 'all.names=FALSE' to 'all.names=TRUE'
# 2) Say "Yes", I want to save the changes
save("my_ls", file="my_ls.Rdata")
# Then, in a later session, test that it works
load("my_ls.Rdata")
.TrysToHide <- 99
my_ls()
# [1] ".TrysToHide" "my_ls"
One more note: it's much cleaner to give your modified function a name of its own. To really edit a packaged function, and have the changes persist, you'd need to edit the sources and recompile the package. But if you do that, beware, as you may well break the function for other packaged functions that depend on it.
There are a couple of options:
Save your workspace before quiting and load it again when you reopen R.
Save the modified function to script file and source it:
sink("modified_plotHive.r")
plotHive
sink()
In the next session:
plotHive <- source("modified_plotHive.r")
HTH

Resources