here + ggplot2 particularly ggsave - r

I have been trying to clean up my project workflow, and have been using the here package, but have am perplexed at some of the utility.
I set up an Rstudio project in the folder ~\ProjFolder. Within this folder I added a Plots folder ~\ProjFolder\Plots.
But when I try to use ggsave to save a plot into the Plots folder it instead places it in the ProjFolder.
library(here)
library(ggplot2)
xdat = rnorm(10)
ydat = rnorm(10)
df = data.frame(xdat,ydat)
ggplot(data = df, aes(x = xdat, y = ydat)) + geom_point()
here("Plots", ggsave("ScatterPlot.jpg"))
Any help? Or am I just using the here package ineffectively?

You should do ggsave(here("Plots", "ScatterPlot.jpg")). here::here is just a way to provide the right file path, you put it in as a replacement for the path argument in functions that take one.

The problem is that you are composing here() and ggsave() in the wrong order. You want the first argument to ggsave() to be the full path, so
ggsave(here("Plots", "ScatterPlot.jpg"))
Does what you want.

Related

Specifying the `stratum` and `alluvium` parameters without attaching ggalluvial

I use ggalluvial with ggplot2, though, I'd like to be able to generate the same plot without attaching ggalluvial but only specify its use with ggalluvial::. If it is not attached, I get the following error: Error: Can't find stat called "stratum".
d <- data.frame(
status = rep(c("state1","state2","state3"), rep(90, times=3)),
cellIndex = rep(seq_len(90), times=3),
cellCategory = c(rep(letters[seq_len(3)], each=30),
rep(letters[c(2,3,1)], each=30),
rep(letters[c(3,1,2)], each=30))
)
ggplot2::ggplot(data=d, ggplot2::aes(x=status, stratum=cellCategory, alluvium=cellIndex,
fill=cellCategory, label=cellCategory)) +
ggalluvial::geom_flow(stat="alluvium", lode.guidance="rightleft", color="darkgray") +
ggalluvial::geom_stratum() +
ggplot2::geom_text(stat="stratum", size=3)
This was a tough one---digging into the code for ggplot2, the stat argument pastes the string you give and then looks for that object (in this case "StatStratum") in the environment you're in. Because you don't want to load the package, it won't be able to find it (and there's no way to change the argument itself).
Answer
So you need to save that object from the ggalluvial package like so:
StatStratum <- ggalluvial::StatStratum
Then leave the rest of your code as is.
The following worked for me.
ggplot2::geom_text(stat = ggalluvial::StatStratum)

Save and Load a ggplot plot

I am working on a large shinydashboard and was keeping my code for modeling in a separate file from the main app.R. The problem is that I need to plot my data. This requires that I save my ggplots from one file and load them in my main app.R file. How can I save my ggplots and load them.
As a simple example lets say I have the following
#make plot
> p <- mtcars %>%
ggplot(aes(x = mpg, y = cyl))+geom_point()
#save plot
> save(file=here::here("plots/a_plot.Rdata"),p)
#load plot
> p <- load(file=here::here("plots/trans_arima.Rdata"))
> p
[1] "p"
How can I load my ggplot?
You can save your plot as a png file and then load it back into youyr file
you have several option for saving your plot. you could use ggplot2s' ggsave()
function or you could use the save_plot() from the cowplot package. save_plot() is said to
give you more flexibility when it comes file adjusting hence my pick.
You can explore both.
refer to https://rdrr.io/cran/cowplot/man/save_plot.html to read more about save_plot.
tmp = data.frame(first = c('a','b','c','d','e','f','g','h','i','j','k','l','m','n'),
second = c(2,3,4,5,2,3,4,5,6,3,4,4,6, 7))
plot_tmp = ggplot(tmp, aes(first, second)) + geom_bar(stat = 'identity')
dev.new()
if("png" %in% installed.packages()){
library(png)
}else{
install.packages("png")
library(png)
}
save_plot("~/plot_tmp.png", plot_tmp, base_height = NULL, base_aspect_ratio = 1.618,
base_width = 6)
Use the following steps to load files into your shiny using by using the
#read plot
library(OpenImageR)
img<-OpenImageR::readImage("~/plot_tmp.png")
imageShow(img)
Hopefully this helps. To read more about OpenImageR and how you can use it in shiny please go to https://cran.r-project.org/web/packages/OpenImageR/vignettes/The_OpenImageR_package.html
have fun!!!

How to store r ggplot graph as html code snippet

I am creating an html document by creating various objects with ggplotly() and htmltools functions like h3() and html(). Then I submit them as a list to htmltools::save_html() to create an html file.
I would like to add ggplot charts directly as images, rather than attaching all the plotly bells and whistles. In the end, I will create a self-contained html file (no dependencies), and the plotly stuff would make that file excessively large.
Is there some function that converts a ggplot object into some html-type object? Or do I have to save the ggplot as a .png file, then read the .png file into some object that I add to the list in the save_html() function?
My R code looks something like this:
library("tidyverse")
library("plotly")
library("htmltools")
HTMLOut <- "c:/Users/MrMagoo/My.html")
df <- data.frame(x=1:25, y=c(1:25*1:25))
g7 <- ggplot(df,aes(x=x, y=y)) + geom_point()
p7 <- ggplotly(g7) # I would like to use something other than ggplotly here. Just capturing the ggplot as an image would be fine.
# create other objects to add to the html file
t7 <- h2(id="graph7", "Title for graph #7")
d7 <- p("description of graph 7")
save_html(list(t7, p7, d7), HTMLOut)
# of course, the real code has many more objects in that list – more graphs, text, tables, etc.
I would like to replace the plotly object (p7) with something that just presents g7 in a way that would not cause an error in the save_html function.
I had hoped to find a function that could directly Base64 encode a ggplot object, but it seems that I first need to output the 'ggplot' object as a .png file (or SVG, per Teng L, below), then base64-encode it. I was hoping there was a more direct way, but I may end up doing that, as in https://stackoverflow.com/a/33410766/3799203 , ending it with
g7img <- "<img src=\"data:image/png;base64,(base64encode string)\""
g7img <- htmltools::html(g7img)
If you want to save the plot as a dynamic plotly graph, you could use htmlwidgets::saveWidget. This will produce a stand-alone html file.
Here is a minimal example:
library(tidyverse);
library(plotly);
library(htmlwidgets);
df <- data.frame(x = 1:25, y = c(1:25 * 1:25))
gg <- ggplot(df,aes(x = x, y = y)) + geom_point()
# Save ggplotly as widget in file test.html
saveWidget(ggplotly(gg), file = "test.html");
I ended up generating a temparory image file, then base64 encoding it, within a function I called encodeGraphic() (borrowing code from LukeA's post):
library(ggplot2)
library(RCurl)
library(htmltools)
encodeGraphic <- function(g) {
png(tf1 <- tempfile(fileext = ".png")) # Get an unused filename in the session's temporary directory, and open that file for .png structured output.
print(g) # Output a graphic to the file
dev.off() # Close the file.
txt <- RCurl::base64Encode(readBin(tf1, "raw", file.info(tf1)[1, "size"]), "txt") # Convert the graphic image to a base 64 encoded string.
myImage <- htmltools::HTML(sprintf('<img src="data:image/png;base64,%s">', txt)) # Save the image as a markdown-friendly html object.
return(myImage)
}
HTMLOut <- "~/TEST.html" # Say where to save the html file.
g <- ggplot(mtcars, aes(x=gear,y=mpg,group=factor(am),color=factor(am))) + geom_line() # Create some ggplot graph object
hg <- encodeGraphic(g) # run the function that base64 encodes the graph
forHTML <- list(h1("My header"), p("Lead-in text about the graph"), hg)
save_html(forHTML, HTMLOut) # output it to the html file.
I think what you want may be close to one of the following:
Seems you are creating an HTML report but hasn't checked out RMarkdown. It comes with Base64 encode. When you create an RMarkdown report, pandoc automatically converts any plots into an HTML element within the document, so the report is self-contained.
SVG plots. This is less likely to be what you might want, but SVG plots are markup-language based and may be easily portable. Specify .svg extension when you use ggsave() and you should be getting an SVG image. Note that SVG is an as-is implementation of the plot, so if can be huge in file size if you have thousands of shapes and lines.
This is an extension to the Maurits Evers post. In this answer I'm showing how to combine multiple plotly plots in the same html file in an organized fashion:
library("plotly")
library("htmltools")
# a small helper function to avoid repetition
my_func <- function(..., title){
## Description:
## A function to add title to put multiple gg plotly objects under a html heading
##
## Arguments:
## ...: a list of gg objects
## title: a character vector to specify the heading text
# get the ... in list format
lst <- list(...)
# create the heading
tmp_title <- htmltools::h1(title)
# convert each ggplot to ggplotly and put them under the same div html tag
tmp_plot <- lapply(lst, ggplotly) |>
htmltools::div()
# return the final object as list
return(list(tmp_title, tmp_plot))
}
# a toy data
df <- data.frame(x = 1:25, y = c(1:25 * 1:25))
# the ggplot object using the toy data
gg <- ggplot(df,aes(x = x, y = y)) + geom_point()
# put everything in order
final_list <- list(my_func(obj = list(gg, gg, gg), title = "The first heading"),
my_func(obj = list(gg, gg), title = "The second heading"))
# write to disk as a unified HTML file
htmltools::save_html(html = final_list,
file = "index.html"))
Disclaimer: I specifically did this to avoid using widgetframe R package and to be completely on par with the documentation of plotly-r. You can read the link if you are comfortable with adding extra dependency and extra abstraction layer. I prefer to use packages if and only if necessary. :)

R open plotly in standalone window

I would like to display a plotly plot object in a standalone window that behaves similarly to the window that pops up using the base R plot() function.
Using a basic example from the plotly website:
library(ggplot2)
library(plotly)
d <- diamonds[sample(nrow(diamonds), 1000), ]
p <- ggplot(data = d, aes(x = carat, y = price)) +
geom_point(aes(text = paste("Clarity:", clarity))) +
geom_smooth(aes(colour = cut, fill = cut)) + facet_wrap(~ cut)
p2 <- ggplotly(p)
The p2 object is an htmlwidget object and I get some control over its display using the sizingPolicy element as described here. However, I can't find anything that allows me to set the viewer/browser to something other than my current browser (as a new tab) or within RStudio.
Ideally, I'd like to avoid applications outside of R packages to launch a separate window from within R. However, I would also be happy with figuring out how to granularly control browser output to display p2 as a new window in kiosk or app mode (see the answers to this question for some examples of kiosk/app mode).
Edit: Although I mentioned RStudio when discussing some of the options that I was able to find, I am talking about using R from a simple console. That said, granular display options should hopefully be independent of the user interface.
I have a working solution, but I'll be happy to change the accepted answer if someone has anything better.
I defined a print function that can be used to launch a custom browser command for an htmlwidget object. In this case, I used chromium-browser -app=..., but the overall approach should be general.
print_app <- function(widget) {
# Generate random file name
temp <- paste(tempfile('plotly'), 'html', sep = '.')
# Save. Note, leaving selfcontained=TRUE created files that froze my browser
htmlwidgets::saveWidget(widget, temp, selfcontained = FALSE)
# Launch with desired application
system(sprintf("chromium-browser -app=file://%s", temp))
# Return file name if it's needed for any other purpose
temp
}
Combining with the previous example:
library(ggplot2)
library(plotly)
d <- diamonds[sample(nrow(diamonds), 1000), ]
p <- ggplot(data = d, aes(x = carat, y = price)) +
geom_point(aes(text = paste("Clarity:", clarity))) +
geom_smooth(aes(colour = cut, fill = cut)) + facet_wrap(~ cut)
p2 <- ggplotly(p)
print_app(p2)
It seems like htmlwidgets normally uses the html_print function from htmltools, which in turn selects the browser to use via getOption("viewer", utils::browseURL), which bakes in a lot of the browser selection options -- making it challenging to change.
The idea for saving the html file locally came from this plotly issue: saving plotly plots locally?.
If you are using MacOS, change this line in #ssokolen's answer
# Launch with desired application
system(sprintf("chromium-browser -app=file://%s", temp))
to
system(sprintf("open -a 'google chrome' /%s", temp))
Works in zsh in MacOs Catalina with the Intellij R plugin.

Ggplot does not show plots in sourced function

I've been trying to draw two plots using R's ggplot library in RStudio. Problem is, when I draw two within one function, only the last one displays (in RStudio's "plots" view) and the first one disappears. Even worse, when I run ggsave() after each plot - which saves them to a file - neither of them appear (but the files save as expected). However, I want to view what I've saved in the plots as I was able to before.
Is there a way I can both display what I'll be plotting in RStudio's plots view and also save them? Moreover, when the plots are not being saved, why does the display problem happen when there's more than one plot? (i.e. why does it show the last one but not the ones before?)
The code with the plotting parts are below. I've removed some parts because they seem unnecessary (but can add them if they are indeed relevant).
HHIplot = ggplot(pergame)
# some ggplot geoms and misc. here
ggsave(paste("HHI Index of all games,",year,"Finals.png"),
path = plotpath, width = 6, height = 4)
HHIAvePlot = ggplot(AveHHI, aes(x = AveHHI$n_brokers))
# some ggplot geoms and misc. here
ggsave(paste("Average HHI Index of all games,",year,"Finals.png"),
path = plotpath, width = 6, height = 4)
I've already taken a look here and here but neither have helped. Adding a print(HHIplot) or print(HHIAvePlot) after the ggsave() lines has not displayed the plot.
Many thanks in advance.
Update 1: The solution suggested below didn't work, although it works for the answer's sample code. I passed the ggplot objects to .Globalenv and print() gives me an empty gray box on the plot area (which I imagine is an empty ggplot object with no layers). I think the issue might lie in some of the layers or manipulators I have used, so I've brought the full code for one ggplot object below. Any thoughts? (Note: I've tried putting the assign() line in all possible locations in relation to ggsave() and ggplot().)
HHIplot = ggplot(pergame)
HHIplot +
geom_point(aes(x = pergame$n_brokers, y = pergame$HHI)) +
scale_y_continuous(limits = c(0,10000)) +
scale_x_discrete(breaks = gameSizes) +
labs(title = paste("HHI Index of all games,",year,"Finals"),
x = "Game Size", y = "Herfindahl-Hirschman Index") +
theme(text = element_text(size=15),axis.text.x = element_text(angle = 0, hjust = 1))
assign("HHIplot",HHIplot, envir = .GlobalEnv)
ggsave(paste("HHI Index of all games,",year,"Finals.png"),
path = plotpath, width = 6, height = 4)
I'll preface this by saying that the following is bad practice. It's considered bad practice to break a programming language's scoping rules for something as trivial as this, but here's how it's done anyway.
So within the body of your function you'll create both plots and put them into variables. Then you'll use ggsave() to write them out. Finally, you'll use assign() to push the variables to the global scope.
library(ggplot2)
myFun <- function() {
#some sample data that you should be passing into the function via arguments
df <- data.frame(x=1:10, y1=1:10, y2=10:1)
p1 <- ggplot(df, aes(x=x, y=y1))+geom_point()
p2 <- ggplot(df, aes(x=x, y=y2))+geom_point()
ggsave('p1.jpg', p1)
ggsave('p2.jpg', p2)
assign('p1', p1, envir=.GlobalEnv)
assign('p2', p2, envir=.GlobalEnv)
return()
}
Now, when you run myFun() it will write out your two plots to .jpg files, and also drop the plots into your global environment so that you can just run p1 or p2 on the console and they'll appear in RStudio's Plot pane.
ONCE AGAIN, THIS IS BAD PRACTICE
Good practice would be to not worry about the fact that they're not popping up in RStudio. They wrote out to files, and you know they did, so go look at them there.

Resources