How can I get R to follow symbolic links in Windows 10? - r

I have multiple RStudio projects, each in its own working directory. All of the projects draw data from the same series of CSV files.
I would like to place the CSV files in a separate "data" directory, then put a Windows shortcut inside each project directory pointing to the data directory. The directory structure would thus be:
/data
/project-1
/project-1/data = Windows shortcut pointing to /data
/project-2
/project-2/data = Windows shortcut pointing to /data
etc.
However, when I attempt to access the "data" directory via the shortcut from e.g. project-1, R generates the following error:
> write.csv(df, "data/df.csv")
Error in file(file, ifelse(append, "a", "w")) :
cannot open the connection
In addition: Warning message:
In file(file, ifelse(append, "a", "w")) :
cannot open file 'data/df.csv': No such file or directory
What am I doing wrong?

I didn't know this, because I've spent the past 10 years using Linux instead of Windows, but:
In Windows, "shortcuts" are not symbolic links. To create an actual symbolic link, you have to open a command prompt as administrator (!?! - or activate developer mode) then create a link using mklink. RStudio does correctly follow symbolic links created that way.
Sadly, Windows Explorer does not correctly follow symbolic links created that way. And you can't create hard links to directories. So either way, it is only half functional. Bloody Windows.

I know this is an old question but solution was never posted.
Solution:
Create a soft link in windows.
To do that, open command line as and admin.
use "mklink" command. The best approach is to use full path to both locations.
mklink works like this:
mklink LinkLocation PathToFile
If you want to do directory use "/D".
For example: "mklink /D C:\myNewLink F:\LocationOfMyDirectorry
Such links should work in R with no trouble (like regular folder/file).
Important to add that soft link can point to soft link :D

Nice thinking! I actually had a similar idea not too long ago: the use of Windows shortcuts (.lnks) would let one refer to resources without redundancy, and seamlessly point (or redirect) to various locations...all with a few mouse-clicks in Windows File Explorer!
Where You Went Wrong
Consider this situation for /project-1. When you create a shortcut (to /data) within the /project-1 directory, you are not creating a subdirectory named data
.
├── project-1.Rproj
├── data # A subdirectory.
│ └── …
└── …
but rather a shortcut (.lnk) file named data:
.
├── project-1.Rproj
├── data.lnk # A shortcut.
└── …
As such, R
cannot open file 'data/df.csv'
because the ./data directory does not exist under /project-1:
No such file or directory
Solutions
For my own project, my search turned up two lifesaving packages: fs (in the tidyverse) and R.utils.
Now fs does have the benefit of stability and consistency with the tidyverse. It provides a standardized interface to create symbolic links, and its fs::link_path() will let you read those links.
🚨🚨🚨 However, Windows shortcuts are NOT symbolic links. 🚨🚨🚨
As such, I much prefer the superior power and relevance of R.utils::filePath(). For one thing, it can actually expand Windows shortcuts (.lnks) specifically. For another, it will let you treat the shortcut to a directory as a directory:
# Refers to 'data.lnk' shortcut ↴
# |--|
R.utils::filePath("./project-1/data")
#> "/data"
# Refers to 'data.lnk' shortcut ↴
# |--|
R.utils::filePath("./project-1/data/my_data.csv")
#> "/data/my_data.csv"
Indeed, you can chain together an arbitrary number of such shortcuts by name, as if they were directories! That is, given a structure like
# Current working directory.
.
| # Shortcut (named 'd2') to a directory.
├── d2.lnk |►───┐
└── … |
|
|
path/to/dir_2 ◄─┘
├── subdir
| | # Shortcut (named 'd3') to a directory.
│ ├── d3.lnk |►─┐
| └── … |
└── … |
|
|
path/to/dir_3 ◄───┘
| # Normal CSV file.
├── foo.csv
| # Shortcut (named 'bar') to a file.
├── bar.lnk |►─────────┐
└── … |
|
|
path/to/dir_4 |
| # Normal text file. |
├── qux.txt ◄──────────┘
└── …
you can "unwrap" the paths to foo.csv and qux.txt like so:
R.utils::filePath("./d2/subdir/d3")
#> "path/to/dir_3"
R.utils::filePath("./d2/subdir/d3/foo.csv")
#> "path/to/dir_3/foo.csv"
# No '.lnk' extension needed ↴
R.utils::filePath("./d2/subdir/d3/bar")
#> "path/to/dir_4/qux.txt"

Related

File download in Voila from Jupyter Notebook

There are many questions with great answers about downloading a file from a Jupyter Notebook. Here's one I added to earlier. That works, but I am unable to click and download that file for a server started with Voila.
Originally I realized I could not download the basic case when clicked through Voila.
from IPython.display import display, FileLink
local_file = FileLink('./demo.xlsx', result_html_prefix="Click here to download: ")
display(local_file)
That is from my notebook. I am able to click on the link and download the file. When I start my notebook with Voila it looks more like this..
Clicking the link give a 404 ☝️ for a voila server started with
voila mynotebook.ipynb
Since the file clearly isn't being served... I found this link here and tried:
voila mynotebook.ipynb --VoilaConfiguration.file_whitelist="['demo.xlsx']"
which unfortunately didn't work.
I saw static content can be served in voila.. I'll keep playing down this road. Has anyone done this before?
I was able to make it work by hosting my file to download as static content as I was trying before. All of this is for a Mac, but it'll be similar for other platforms.
I had to define a custom template in order to get files at static_root so they could be served. Relevant documentation is here for setting up a custom template.
It isn't difficult.. you essentially create a directory where it's expected, copy over some of the default files, then add/change what you will. terminal record might look something like this:
cd ~/Library/Jupyter/voila/templates/
mkdir foobar
export DEFAULT_TEMPLATE_PATH=~/anaconda3/envs/voilatest/share/jupyter/voila/templates/default
export TEMPLATE_PATH=~/Library/Jupyter/voila/templates/foobar
cp -r $DEFAULT_TEMPLATE_PATH/nbconvert_templates $TEMPLATE_PATH
cp -r $DEFAULT_TEMPLATE_PATH/templates $TEMPLATE_PATH
to which the tree will look like this in my new custom template:
{~/Library/Jupyter/voila/templates/foobar}$ tree .
.
├── nbconvert_templates
│   ├── base.tpl
│   ├── lab.tpl
│   └── voila.tpl
├── static
│   └── demo.xlsx
└── templates
├── 404.html
├── browser-open.html
├── error.html
├── page.html
└── tree.html
3 directories, 9 files
notice the static directory with demo.xlsx. I added that in. That is the file I wanted to download via the link.
Starting voila like this...
voila mynotebook.ipynb --template=foobar
Now.. in mynotebook.ipynb
Use an HTML Anchor tag to do the download. At least FileLink fails for me with the following error.
Path (/voila/static/demo.xlsx) doesn't exist. It may still be in the process of being generated, or you may have the incorrect path.
which isn't much of a surprise since the actual path the file is stored at isn't that. It just happens to be the static content uri.
%%html
Download Excel Sheet
Using an anchor will make it hardcoded and I didn't have any issues. I'll also be able to style the anchor more anyways. One catch.. This doesn't work in a regular notebook anymore since it's a URI to a served resource under voila.

R CMD check note: Non-standard files/directories found at top level (PNG file) [duplicate]

I have a package with a README.Rmd that I pass to rmarkdown::render()
producing README.md and a directory README_files, which contains images in README.md. This looks like the tree below.
README_files is not a standard package directory, so if it isn't in .Rbuildignore, checking the package with R CMD check shows a note:
* checking top-level files ...
NOTE Non-standard file/directory found at top level: README_files
But including the directory in .Rbuildignore leads to a warning, if and only if checking the package --as-cran. IIUC Pandoc tries to generate HTML from README.md, but the images are unavailable, in the ignored README_files directory.
Conversion of ‘README.md’ failed:
pandoc: Could not fetch README_files/unnamed-chunk-14-1.png
README_files/unnamed-chunk-14-1.png: openBinaryFile: does not exist (No such file or directory)
Is there any way to get a clean check --as-cran here?
├── README_files
│   └── figure-markdown_github
│   ├── unnamed-chunk-14-1.png
│   ├── unnamed-chunk-15-1.png
│   ├── unnamed-chunk-16-1.png
│   ├── unnamed-chunk-26-1.png
│   └── unnamed-chunk-27-1.png
├── README.md
├── README.Rmd
The current preferred solution (at least as used by ggplot2) is to store the images in man/figures/. So in the README.Rmd file, include something like the following setup chunk.
```{r, echo = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-"
)
```
That keeps the images tucked away in a place that won't generate cran check errors, but they are still part of the package. So you don't have to store them elsewhere or use calls to png::readPNG.
There are a few options. Update: I think Rob Hyndman's solution is now better than the things I list here.
Store the image online somewhere, and include the URL in the README.
As #Axeman noted, you can follow the ggplot2 approach of storing the images at the top level, and mentioning them in .Rbuildignore.
You can store them in inst/image, and use png::readPNG(system.file("image/yourpic.png", package = "yourpkg")) to read it. Then show it in the README using a plot.
I followed http://r-pkgs.had.co.nz/release.html. same error when putting them in top level and add to .Rbuildignore.
As Richie suggested, after adding images to inst/image, and refer to as ![](inst/image/README-unnamed-chunk-1-1.png)

How to tar all files in current directory using tar but without inputing names of tar file and all files?

ENV:
macOS Sierra 10.12.6
Raw input(example):
.
├── f1.md
├── f2.md
├── f3.md
├── f4.txt
├── f5.csv
└── f6.doc
0 directories, 6 files
In a test folder, there are 6 files.
Expected output:
.
├── all.tar
├── f1.md
├── f2.md
├── f3.md
├── f4.txt
├── f5.csv
└── f6.doc
0 directories, 7 files
Trying and Problem
tar -cvf all.tar f1.md f2.md f3.md f4.txt f5.csv f6.doc
Though I get the result from the above method but I have to inputing all file names and the compressed file name, which is inconvenient. For example , I can select all files and right click, then choose compressed option without inputing all.tar (I don't mind the .tar filenames.)
Hope
command-line method without inputing specific file names.
In case you want all files, including those in the subdirectories (or if you have no subdirectories), you would run:
tar -cvf all.tar *
Then, bash would expand * into the list of all files in the current directory, including subdirectories.
In case you want only those files in the current directory, but NOT in the subdirectories, then you would have to use find, in a more complicated command. Let me know if this is the case for you, and I can take the time to find that combination of commands for you.

One shared settings section for multiple tests and suits?

I woud like to make a Robot Framework project with multiple (levels of) test suits and test cases.
Is it possible to define a list of settings, specifically importing of libraries, resources and global variable (.py files), only once in one place?
As far as I'm aware this is not possible. You have to import libraries, resources and variable files explicitily in each .robot test case file that uses them. The init file in a directory can only be used for other settings, not imports.
But I would like to keep things DRY and import resourse that I use everywhere only once and in one place.
Is this not possible, or am I missing something?
Note: I'm still a RF newbie.
Thanks!
It's easily doable, and quite a common pattern - have a resource file, that has all the common keywords, variables, imports of other robot or py files, etc, and in every test suite - import it.
Say your project's directory structure is like this:
root_folder/
├── resources/
│ ├── common_resource.robot
│ ├── helpers.robot
│ ├── specific_page.robot
└── suites/
├── login_page.robot
└── specific_page.robot
The file resources/common_resource.robot has all those common elements - say, imports helpers.robot as a resource.
Every suite file imports the common file; e.g. both login_page.robot and specific_page.robot start-off with (path-relative) imports:
*** Settings ***
# other imports, documentation, etc
Resource ../resources/common_resource.robot
On top of that, each suite imports any other specific keyword files - like resources/specific_page.robot.
It's a convention, that once established ("every suite must import common_resource.robot") is easy to follow.
If there is a new keyword, variable or library that has to be used in all - or most - suites, just add it to the common file, and it will be instantly accessible.

`man` can't access custom manpages

I followed these instructions to add some manpages on my computer, but I still can't open it with man.
I set $MANPATH to /usr/local/man (export MANPATH=/usr/local/man in my ~/.zshrc, and sourced it) and copied my manpage files to /usr/local/man/man3. Yet man doesn't find the pages I want to access :
$ echo $MANPATH
/usr/local/man
$ tree /usr/local/man
/usr/local/man
└── man3
├── mlx.1
├── mlx_loop.1
├── mlx_new_image.1
├── mlx_new_window.1
└── mlx_pixel_put.1
1 directory, 5 files
$ man mlx
No manual entry for mlx
$ man 3 mlx
No manual entry for mlx in section 3
Why do I get this error and what could I do?
It seems that the files are either in the wrong directory or have an incorrect extension.
The directory name indicates that it contains manpages for section 3 (Library calls) but the filename extensions suggest that the manpages belong to section 1 (Executable programs or shell commands).
You should be able to check which is the case - for example for mlx.1 - with the following command
man /usr/local/man/man3/mlx.1
This should show the name of the manpage (probably in uppercase) followed by the section number in parentheses at the very beginning.
If it shows MLX(1) move the file mlx.1 into the directory /usr/local/man/man1 (or just rename man3 if all files belong to section 1). If it shows MLX(3), just rename the file to mlx.3.

Resources