I have started integrating R usage into Notebook to get, from my perspective, the best of both worlds (data management in python while exploiting the comparative analytical/graphical advantages of R). Unfortunately I am hung up on a seemingly easy element, adjusting plot size for ggplot2 graphics. Adjusting plot sizes is pretty straightforward with pandas, and in a purely R environment (like RStudio), I can adjust plots with dev.new() or PNG(), etc. However, attempting to do this is Notebook makes my computer go nuts (I am running Ubuntu 13.04 on an ASUS U46E). Furthermore, this is crucial, I want to keep the graphics inline so that I can pass the script in its entirety to my colleagues.
When trying dev.new(), my computer locked up and I had to switch to a different virtual terminal to reboot. I tried to adjust x11() options, my browser became temporarily unresponsive while the graphics went a bit haywire. Ultimately, I was granted control again, but I have no idea why this happened.
Does anyone know why this may have occurred? Additionally, does anyone know how to adjust the plot size of ggplot2 objects rendered from within IPython Notebook? I am afraid I can't share the data, but I can tell you that I was attempting to plot three numeric variables faceted by fund center (a categorical variable). These plots did execute as written ... until I tried to adjust the size. Here is my example code:
%%R
#x11(width=500,height=300) << didn't work
#dev.new() << tried before setting size parameters, and it locked up my laptop
#Plot total expenses by unit
print('*****Expenses by Unit*****')
print(smu)
print(ggplot(smu,aes(x=fy,y=as.numeric(as.character(totexp)),group=fund,colour=fund))+geom_line(size=2)+
ggtitle('Total Expenses'))
#Plot expense components
print(ggplot(smu,aes(fy))+
geom_line(aes(y=as.numeric(as.character(fixed)),colour='fixed',group=fund,colour=fund))+
geom_line(aes(y=as.numeric(as.character(var)),colour='variable',group=fund,colour=fund))+
geom_bar(aes(y=as.numeric(as.character(incadj)),group=1),stat='identity')+
facet_grid(.~fund)+
ggtitle('Components of Expenditure'))
The rmagic command has optional arguments to specify the size of the plot. The default is a width and height of 480 pixels. Thus, the code below replicates the default settings:
%%R -w 480 -h 480 -u px
library(ggplot2)
dat <- data.frame(x = rnorm(10), y = rnorm(10),
lab = sample(c('A', 'B'), 10, replace = TRUE))
x <- ggplot(dat, aes(x = x, y = y, color = lab)) + geom_point()
print(x)
And this code below creates a plot with a width of 50 cm and a height of 25 cm:
%%R -w 50 -h 25 -u cm
library(ggplot2)
dat <- data.frame(x = rnorm(10), y = rnorm(10),
lab = sample(c('A', 'B'), 10, replace = TRUE))
x <- ggplot(dat, aes(x = x, y = y, color = lab)) + geom_point()
print(x)
You can also specify the size in inches or millimeters.
Related
I have a number of plots using {ggplot2} and {ggiraph} that I have consolidated into a {flexdashboard}
Before attempting to display them with the dashboard, these plots displayed correctly on RStudio's viewer using the sizing option width = 0.7
However, they do not display on the dashboard (just a blank panel), and now produce a blank panel if run directly in RStudio. After some investigation it seems that some setting has changed and that the charts are not output because the size is inconsistent with the window.
If I change the width setting to 10 it displays correctly in the RStudio viewer which seems odd.
I have a small reprex here:
library(ggplot2)
library(ggiraph)
#dummy dataframe
df <- data.frame(
x = seq.Date(Sys.Date() - 30, Sys.Date() - 1, by = "days"),
y = runif(30, 0, 2)
)
p <- ggplot2::ggplot(df, (aes(x,y)))+
geom_point_interactive(aes(tooltip = x, data_id = x))
plot <- girafe(ggobj = p,
width =0.7)
print(plot)
This produces the following output:
However if I adjust width setting to 10
plot <- girafe(ggobj = p,
width =10)
print(plot)
I get the following:
This seems inconsistent with the documentation for {ggiraph}, is there some graphics setting that has been modified by {flexdashboard}? I've tried interactive (js) charts with {plotly} and {echarts4r} on {flexdashboard} output which don't show the same behaviour.
I'm using
RStudio 1.4.1103
R version 4.0.2
System: x86_64-apple-darwin17.0
I've been experimenting and it seems that I can control the output by using width_svg consistently.
I still don't know why there is an issue but I suspect some underlying graphics setting.
I build scatterplots using ggplot2 in R. I then want to save them as svg files with Cairo::CairoSVG. It seems to work fine except for the point size, which is enlarged in the resulting .svg file.
Here comes some example code:
library (ggplot2)
my_plot <- ggplot(mpg, aes(cty, hwy)) +
geom_point(size = 0.5)
x11 (width = 6, height = 6)
my_plot
Cairo::CairoSVG (file = "my_path",
width = 6, height = 6)
print (my_plot)
dev.off()
And this is what I get: on the right hand, the plot printed in R and on the left side the saved .svg-file opened in Inkscape. It looks fine except for the point size, which is a pity. Are there any ideas on how to get the right point-size? I tried different point sizes and also shapes, with similarly unmatched results.
Note that I seek to stick with Cairo::CairoSVG, beacuse in the final plots I wish to use custom fonts which are printed nicely with Cairo::CairoSVG. Any help is appreciated.
EDIT: I am working on a Windows machine.
Preliminary remark: when you pass width = 6, height = 6 in the Cairo::CairoSVG() parameters, you provide potentially different parameters (resolution and display) from the ones used in the RStudio plot panel.
To get the exact same image than the one rendered in the panel as well as using Cairo, you can use this alternative (dev.size('px') returns the dimensions of the current plot panel):
library (ggplot2)
my_plot <- ggplot(mpg, aes(cty, hwy)) +
geom_point(size = 0.5)
my_plot
mirror <- recordPlot()
png(filename = "mypath",
width = dev.size('px')[1]/96,
height = dev.size('px')[2]/96,
res = 96, # base RStudio resolution
units = "in",
type = "cairo") # calls CairoSVG
replayPlot(mirror)
dev.off()
(Note : I prefer the use of png() rather than ggsave() because it will save the entire last plot. I have observed that ggsave() would save only the last facet of a grid, for example)
I have a ggplot object. Let's call it plot. I would like to convert it to png format, but I don't want to save it to a file on my local drive. I'm trying to work with that png object but I want to keep everything in the environment. Everything I've found, including ggsave, appears to force one to save the image as a file on the local drive first. I know image files can be stored as values, but I can't seem to get over the "save as" image and "import" image steps.
Here's some code for repoducibility:
library(tidyverse)
df <- as.data.frame(Titanic)
gg <- ggplot(data = df, aes(x = Survived, y = Freq))
plot <- gg + geom_bar(stat = "identity")
Now, I'd like to convert plot to a png to png without having to save it to a file. Something like:
png <- save.png(plot)
Thanks for the help!
It looks like the goal here would be to convert plot (the ggplot object) directly to a Magick image that you can operate on with functions in the magick package. Something like this:
mplot = image_graph(width=400, height=500)
plot
dev.off()
image_graph opens a graphics device that produces a Magick image and assigns it to mplot so that you'll have the object available in your environment. Then, when you type mplot in the console, you'll see the following:
format width height colorspace matte filesize density
1 PNG 400 500 sRGB TRUE 0 +72x+72
However, when I try to display the mplot image (type mplot in the console), I see the following:
even though the original plot looks like this:
I'm not sure what's going wrong, but hopefully someone with greater familiarity with magick will drop by and provide a solution.
I was faced with a similar issue and followed #eipi12 approach of using magick. The code bellow should work:
library(ggplot2)
library(magrittr)
ggsave_to_variable <- function(p, width = 10, height = 10, dpi = 300){
pixel_width = (width * dpi) / 2.54
pixel_height = (height * dpi) / 2.54
img <- magick::image_graph(pixel_width, pixel_height, res = dpi)
on.exit(utils::capture.output({
grDevices::dev.off()}))
plot(p)
return(img)
}
p <- data.frame(x = 1:100, y = 1:100) %>%
ggplot(aes(x = x, y = y)) +
geom_line()
my_img <- ggsave_to_variable(p)
my_img %>%
magick::image_write("my_img.png")
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.
I'm constructing a plot that uses geom_tile and then outputting it to .pdf (using pdf("filename",...)). However, when I do, the .pdf result has tiny lines (striations, as one person put it) running through it. I've attached an image showing the problem.
Googling let to this thread, but the only real advice in there was to try passing size=0 to geom_tile, which I did with no effect. Any suggestions on how I can fix these? I'd like to use this as a figure in a paper, but it's not going to work like this.
Minimal code:
require(ggplot2)
require(scales)
require(reshape)
volcano3d <- melt(volcano)
names(volcano3d) <- c("x", "y", "z")
v <- ggplot(volcano3d, aes(x, y, z = z))
pdf("mew.pdf")
print(v + geom_tile(aes(fill=z)) + stat_contour(size=2) + scale_fill_gradient("z"))
This happens because the default colour of the tiles in geom_tile seems to be white.
To fix this, you need to map the colour to z in the same way as fill.
print(v +
geom_tile(aes(fill=z, colour=z), size=1) +
stat_contour(size=2) +
scale_fill_gradient("z")
)
Try to use geom_raster:
pdf("mew.pdf")
print(v + geom_raster(aes(fill=z)) + stat_contour(size=2) + scale_fill_gradient("z"))
dev.off()
good quality in my environment.
I cannot reproduce the problem on my computer (Windows 7), but I remember it was a problem discussed on the list for certain configurations. Brian Ripley (if I remember) recommended
CairoPDF("mew.pdf") # Package Cairo
to get around this
In the interests of skinning this cat, and going into waaay too much detail, this code decomposes the R image into a mesh of quads (as used by rgl), and then shows the difference between a raster plot and a "tile" or "rect" plot.
library(raster)
im <- raster::raster(volcano)
## this is the image in rgl corner-vertex form
msh <- quadmesh::quadmesh(im)
## manual labour for colour scaling
dif <- diff(range(values(im)))
mn <- min(values(im))
scl <- function(x) (x - mn)/dif
This the the traditional R 'image', which draws a little tile or 'rect()' for every pixel.
list_image <- list(x = xFromCol(im), y = rev(yFromRow(im)), z = t(as.matrix(im)[nrow(im):1, ]))
image(list_image)
It's slow, and though it calls the source of 'rect()' under the hood, we can't also set the border colour. Use 'useRaster = TRUE' to use 'rasterImage' for more efficient drawing time, control over interpolation, and ultimately - file size.
Now let's plot the image again, but by explicitly calling rect for every pixel. ('quadmesh' probably not the easiest way to demonstrate, it's just fresh in my mind).
## worker function to plot rect from vertex index
rectfun <- function(x, vb, ...) rect(vb[1, x[1]], vb[2,x[1]], vb[1,x[3]], vb[2,x[3]], ...)
## draw just the borders on the original, traditional image
apply(msh$ib, 2, rectfun, msh$vb, border = "white")
Now try again with 'rect'.
## redraw the entire image, with rect calls
##(not efficient, but essentially the same as what image does with useRaster = FALSE)
cols <- heat.colors(12)
## just to clear the plot, and maintain the plot space
image(im, col = "black")
for (i in seq(ncol(msh$ib))) {
rectfun(msh$ib[,i], msh$vb, col = cols[scl(im[i]) * (length(cols)-1) + 1], border = "dodgerblue")
}