Making relative file paths for outputs - python-3.6

After looking at several similar questions on making relative file paths, I have some confusion on how to apply a relative file path for the outputs in my script. I have an application folder called "Master Map Change Report App" in which my script and outputs currently sit.
Right now this app sits on my local C: drive, but I need to move it to a shared drive so that other people can use it. I have all of the outputs going to 'reports' folder (see below). Currently the path to that folder looks like this:
report = "C:/Workspace/Sandbox/MapChangeProject/Master Map Change Report App/reports/map_change_report_{}.xls".format(today).
What I want is something like this:
report = ".../Master Map Change Report App/reports/map_change_report_{}.xls".format(today).
Of course, that doesn't quite work. What do I need to do here so that my outputs will always be within the 'Master Map Change ReportApp/reports' folder no matter where that folder is moved?

Your script is at "Master Map Change Report App". So your relative path for outputs should be "reports/map_change_report_{}.xls".format(today).
You may need:
import os
dirname = os.path.dirname(os.path.realpath('__file__'))
filename = os.path.join(dirname, 'reports','map_change_report_{}.xls'.format(today))

Related

How can I make a temporaty zip object downlaodable for user using Jupyter Notebook and Voila

I writing a jupyter notebook, which I would like to render using Voila to create a small web app/tool.
What the tool does is to get one Geojson file containing many polygons from the user and return a ZIP file containing many GeoJSON files (a file per polygon). For example, if the user uploads a GeoJSON file with 20 polygons (they are all in the same file), then the output should be a ZIP file containing 20 separate GeoJSON files - file per polygon.
I am able to do it locally and the ZIP file is saved as needed.
However, I would like to render it using Voila so that it can later work from anywhere, meaning the ZIP file will be created in-memory/on-the-fly/as-a-buffer (not sure which term is the accurate one) and then the user will be able to download the ZIP file, via automatic download, or by clicking on a button or with a pop-up window to download, it really does not matter here.
Here is a snippet of my code (let me know if it's not enough):
def on_button_clicked(event):
with output:
clear_output()
df = gpd.GeoDataFrame().from_features(json.loads(upload.data[0])) # if the file is geojson
display(HTML(f'<h4><left>There are {len(df)} polygons in the file</left></h4>'))
# make results.zip in temp directory
# https://gist.github.com/simonthompson99/362404d6142db3ed14908244f5750d08
tmpdir = tempfile.mkdtemp()
zip_fn = os.path.join(tmpdir, 'results.zip')
zip_obj = zipfile.ZipFile(zip_fn, 'w')
for i in range(df.shape[0]):
if len(field_names_col.value)==0:
field_name = f'field_{str(i+1)}'
else:
field_name = df[field_names_col.value][i]
output_name = f'{field_name}.{output_format.value.lower()}'
df.iloc[[i]].to_file(f'{tmpdir}\\{output_name}', driver=output_format.value)
for f in glob.glob(f"{tmpdir}/*"):
zip_obj.write(f, os.path.basename(f)) # add file to archive, second argument is the structure to be represented in zip archive, i.e. this just makes flat strucutre
zip_obj.close()
button_send.on_click(on_button_clicked)
vbox_result = widgets.VBox([button_send, output])
The important part is near the end:
for f in glob.glob(f"{tmpdir}/*"):
zip_obj.write(f, os.path.basename(f)) # add file to archive, second argument is the structure to be represented in zip archive, i.e. this just makes flat strucutre
zip_obj.close()
I iterate over the temporary separate files and create a temporary ZIP file (results.zip) stored in the zip_obj. How can I "push" this ZIP object to the user for download using Jupyter Notebook?
I tried using (just before or just after zip_obj.close()):
local_file = FileLink(os.path.basename(f), result_html_prefix="Click here to download: ")
display(local_file)
But I get an error when rendering it with Voila:
Path (results.zip) doesn't exist. It may still be in the process of
being generated, or you may have the incorrect path.
For example, to save it locally I did:
with zipfile.ZipFile('c:/tool/results.zip', 'w') as zipf:
for f in tmpdir.glob("*"):
zipf.write(f, arcname=f.name)
"I iterate over the temporary separate files and create a temporary ZIP file (results.zip) stored in the zip_obj. How can I "push" this ZIP object to the user for download using Jupyter Notebook?"
There's an example of making a download link that will show up in the Voila rendering here. (Learned of it from here, although the focus there was on file upload. The example covers downloading the results, too.) A simpler take on this is found at the bottom of this answer here, converted to your case:
%%html
Download the Resulting Files as an Archive
These two options are illustrated for a different type of file in the bottom section (everything below the line break presently there) of the answer here.

RStudio show directory contents in file tab display window

Is it possible to show a file directory using function/code? I find myself clicking through file structures to view a directory. I'd like to use some like this:
my_search_finding <- grep('search-pattern', list.files('~/some/long/directory/tree'))
new_function_to_view_files(my_search_finding)
Then the directory is opened in that viewer display and I can explore using the mouse.
Thanks
Under Windows, you can use choose.files:
path <- '~/some/long/directory/tree'
selected.files <- choose.files(default=paste0(path, "/*.*"))
the default argument allows you to display files in a particular directory with a fully qualified file mask, see documentation.

setwd() works weird inside a function?

I have a function for choosing files using file.choose(). When I call it inside a script I want it open certain directory where I wish to choose files. There is a cycle inside the function as I need to choose a bunch of files. First time it opens in the working directory, which is predictable. I put setwd() inside to make the needed directory as working directory so I can choose files there. But when dialog box opens next time it is again the old working directory. But next time it is the directory I need. If I choose different folders it works the same - next time the old directory but after that the new one. I wrote a short function that reproduces behavior:
foo <- function() {
files <- NULL
for (i in c(1,2,3,4,5)) {
x <- file.choose()
y <- dirname(x)
setwd(y)
print(y)
print(getwd())
}
}
Just call this function and try to choose files in different or same directories. You can see that directory name is new and getwd() says that new working directory is set but next file choice dialog opens in previous directory.
Please keep in mind that I need to use file.choose() function as it works on a headless OS, both Windows and Unix-like.
When I don't use setwd() it is always the old working directory.

How do I assign the working directory for rmarkdown/knitr interactive doc on shinyApps.io?

I have a fully functional interactive shiny doc using knitr/r markdwon.
However, when I try to publish (deploy) it to shinyApps.io, I get an error saying the .PNG file I try to incorporate into the doc (using readPNG from the png package) is unable to open.
I know the problem is related to working directories.
In my original code I assigned a working directory to my folder (i.e., "C:/Users/NAME/documents/...." that contains both my .rmd file and my .png file. However, obviously my folder doesn't exist on the shinyapps.io.
So how exactly do I set my working directory to open the .png file via my doc on shinyapps.io?
I can't find anywhere that explicitly walks through this process. Please help explain this simply/basically for me.
Example:
Assume I have a folder in "C:/Users/NAME/documents/Shiny" that contains 2 files: "shiny.rmd" and "pic.png". I want "pic.png" to be rendered in my shiny.rmd doc.
Currently I have:
---
title: "TroubleShoot"
output: html_document
runtime: shiny
---
```{r ,echo=FALSE,eval=TRUE}
library(png)
library(grid)
direct <- "C:/Users/NAME/documents/Shiny/"
img <- readPNG(paste0(direct,"pic.PNG"))
grid.raster(img)
```
How do I rewrite my code so it works on shinyApps.io?
Do I need to create and name folders in specific ways to place my 2 files into before deploying?
When you paste the c drive to direct, and read the direct into img, you are sending the app/markdown to your local drive. You need to use a relative path to the project. I would suggest something like:
direct <- "./"
Which uses the relative path, not the absolute path.
That said you might be able to skip that step entirely if the .png is in the same folder as the shiny object. just call the file name and format and leave it as that.
Also, check you use of ". Your syntax highlighting indicates your code won't run properly as it thinks some of your functions and variables are character strings because you've misplaced your quotes around read.png(). That's probably just a copy and paste typo though.
In summary, call the image via grid.raster("./pic.PNG"), and brush up on how working directories and relative paths work.
In the absence of knowing exactly how you're 'setting' your working directory:
In rStudio to correct and easiest approach is to make a 'New Project' for every New Project. You can do this as the first step in your project, or you can add a project file to an existing directory.
When you do this it automatically sets your working directory correctly. The way you seem to be doing it is not correct, you are merely supplying a 'path'. If you were to not want to use a project for some reason (I can't think of a case where that would be right), then you can always use setwd(), however, I believe this needs to be used in every session. A true project doesn't have that requirement.
This will then allow you to deploy your app properly as it will update the working directory to the one on the host machine at shinyapps.io when it is initialised there.
Finally, using the correct relative syntax "./path/to/my.file" to reference all your assets, images, data etc, should correct your issue as stated in the question.

Calling Skim from inside R

I'm making a simple line in r to automatically open my generated plots.
I output the plots to a file called "plots.pdf" in the same directory as my r file, and at the end i use this two lines to try to open it:
dir <- paste("/Applications/Skim.app/Contents/MacOS/Skim ",getwd(),"/plots.pdf",sep="")
system(dir)
Basically, dir concatenates the full path of the skim app and the full path of the generated plot.
If i run the string stored at dir in a shell it works perfect, it opens the pdf file in Skim, but when i run it with system() from inside R it doesn't work (Skim says 'The document “plots.pdf” could not be opened.').
I believe this is a very little mistake somewhere in the syntax regarding the absolute/relative paths, but haven't managed to find it... Any advice is welcome! (Or a better way to achieve the same)
I found a way to bypass that problem, i just changed the path to Skim for the 'open' command and i let the system to assign the default app for pdf viewing. So:
dir <- paste("open ",getwd(),"/plots.pdf",sep="")
And it works.

Resources