r cairo_pdf dotted line distorted - r

I am trying to save a ggplot2 plot using the cairo_pdf() function, but the markers of the dotted geom_line() keep getting stretched. Please see sample code and output below.
library(ggplot2)
df <- data.frame(x = 0:10, y = 0:10)
p <- ggplot(data = df) +
geom_line(aes(x, y), linetype = 3, size = 2, lineend = "round")
ggsave("ggsave.pdf", width = 7, height = 5)
pdf("pdf.pdf", width = 7, height = 5)
print(p)
dev.off()
cairo_pdf("cairo_pdf.pdf", width = 7, height = 5)
print(p)
dev.off()
Output using ggsave() with markers nice and round:
Output using pdf() same as ggsave().
Output using cairo_pdf() with markers stretched and spacing between markers wrong:
Is there any way to make the cairo_pdf() output, specifically the geom_line(), look like the the other PDFs? I would like to use cairo_pdf() since it has some other benefits that really help with my work. Any help would be appreciated.
EDIT: I have the same problem using R base graphics. For instance:
pdf("r_base_pdf.pdf")
plot(x = c(0, 1), y = c(0, 1), type = "l", lty = "11", lwd = 5)
dev.off()
cairo_pdf("r_base_cairo.pdf")
plot(x = c(0, 1), y = c(0, 1), type = "l", lty = "11", lwd = 5)
dev.off()

Related

How to edit a previous plot in an R graphics device split by mfrow

I have an existing plotting function (perhaps written by someone else) that uses mfrow to plot multiple figures on the same graphics device. I want to edit figures that have already been plotted (e.g. perhaps add a reference line to figure 1)
par(mfrow = c(1, 2))
plot(1:10)
hist(1:10)
# Oh no! I want to add abline(a = 0, b = 1) to the first plot!
Assume this code is nested in another plotting function
PlotABunchOfStuff(1:10) that I can't modify.
I don't want to modify PlotABunchOfStuff because someone else owns it, or I'm just debugging and won't need the extra details once the bug is found.
Use par(mfg).
For example:
par(mfrow = c(2, 3))
for (i in 1:6) {
plot(i, xlim = c(0,7), ylim = c(0, 7))
}
par(mfg = c(2, 2))
points(3,3,col= "red")
par(mfg = c(1, 1))
points(3,3,col= "blue")
If you are ready to use ggplot I think you can find what you want in the code below :
df <- data.frame(x = 1:10, y = 1:10)
g1 <- ggplot(df, aes(x = x, y = y)) +
geom_point()
g2 <- ggplot(df, aes(x = x, y = y)) +
geom_line()
grid.arrange(g1, g2)
g1 <- g1 + geom_smooth(method='lm',formula=y~x) # it could be anything else !
grid.arrange(g1, g2)
Edit 1
Create a graphical object in windows which will be destroye after dev.off() if filename = "" :
win.metafile(filename = "")
By default inhibit doesn't allow the plot to be recorded so we use enable :
dev.control('enable')
plot(1:10)
p <- recordPlot()
dev.off()
replayPlot(p)
p
abline(a = 1, b = 1, col = "red")
p <- recordPlot()
dev.off()
replayPlot(p)
My inspirations on Stackoverflow :
R plot without showing the graphic window
Save a plot in an object
My inspirations on R :
https://www.rdocumentation.org/packages/grDevices/versions/3.6.0/topics/dev
https://www.rdocumentation.org/packages/grDevices/versions/3.6.0/topics/recordPlot
I hope it helps you ! Good luck.
Be careful with scaling!
For the example in the original question, this will not have the result I think is desired.
par(mfrow = c(1, 2))
plot(1:10)
hist(1:10)
par(mfg = c(1, 1))
abline(a = 0, b = 1)
But this will have the result I think is desired.
par(mfrow = c(1, 2))
plot(1:10)
hist(1:10)
par(mfg = c(1, 1))
plot.window(xlim = c(1, 10), ylim = c(1, 10))
abline(a = 0, b = 1)
The mfg graphics parameter will allow you to jump to any panel, but the window scaling may need to be adjusted to be appropriate for the scale used when the original plot was created in that panel.

Align gridlines with ticks in base R plot

I saw this picture on the Internet, and just wondered how to plot it in R. This is my code:
article <- data.frame(x = as.Date(round(runif(1000), 2) * 100, origin = '2017-01-01'), y = sample(letters[1:10], 1000, T))
plot(article$x, article$y, pch = 19, col = article$y, xlab = 'date', ylab = 'account', yaxt = 'n') + grid(nx = 10, ny = 10, lty = 1, col = 'grey')
axis(2, at = 1:10, label = levels(article$y))
And I got a picture like this. There is still a problem: the gridline on the y axis does not correspond to the axis label. So how to solve this problem, or is there a more direct method for rendering the plot?
I don't know how to fix the arguments of grid() so that it gives what you want but you could use plot() to draw a blank plot, use abline() to draw the grid, then plot the data on it using points().
So using your data
plot(article$x, article$y, type="n", xlab = 'date', ylab = 'account', yaxt = 'n', xaxt = 'n')
abline(h=1:10, v=pretty(article$x), col="grey")
points(article$x, article$y, pch = 19, col = article$y)
axis(2, at = 1:10, label = levels(article$y))
axis(1, at = pretty(article$x), label = format(pretty(article$x), "%b"))
Or just plot the data as you're doing and draw the grid afterwards using abline(), but in doing so the grid will be drawn on top of your data points.
ggplot produces a graph very similar to the first picture you included in your post:
library(ggplot2)
library(dplyr)
article %>%
ggplot(aes(x, y, colour=y)) + geom_point() + theme_light() + labs(x='date', y='account')

Converting a ggplot/manipulate plot to a plotly or a js-scripted plot

I'm trying to convert my ggplot to a plotly plot using ggplotly(). However, it doesn't seem to work on this code, after manipulate is acted on the plot. Is there any other way to do it?
library(ggplot2)
library(manipulate)
grades <- data.frame(Final = 20 * runif(70))
myFinalsPlot <- function(sliderInput, initialIndex, finalIndex) {
ggplot(data.frame(grades$Final[initialIndex:finalIndex]),
aes(x = grades$Final[initialIndex:finalIndex])) +
geom_histogram(aes(y = ..density..),
binwidth = sliderInput, colour = "green", fill = "yellow") +
geom_density(alpha = 0.2, fill = "#FF6666") +
labs(x = "Marks", y = "Grades")
}
myFinalsPlot <- manipulate(myFinalsPlot(slidersInput, 1, 70),
slidersInput = slider(1, 12, step = 1, initial = 5))
First, to make your code work with the ggplot2 plot, there is an issue in your code that you need to fix. You shouldn't give the same name to your function and plot object. Replace this:
myFinalsPlot <- manipulate(myFinalsPlot(slidersInput, 1, 70),
slidersInput = slider(1, 12, step = 1, initial = 5))
By, e.g.:
myPlot <- manipulate(myFinalsPlot(slidersInput, 1, 70),
slidersInput = slider(1, 12, step = 1, initial = 5))
Now, regarding plotly plots, I don't think it is supposed to work with manipulate. I quote RStudio's website https://support.rstudio.com/hc/en-us/articles/200551906-Interactive-Plotting-with-Manipulate:
RStudio works with the manipulate package to add interactive capabilities to standard R plots.

How to change the size of R plots in Jupyter?

I am wondering how to configure Jupyter to plot a smaller figure within R kernel.
I have tried using options(repr.plot.width = 1, repr.plot.height = 0.75, repr.plot.res = 300), but the result is kinda messy. It is changing the size of the plot R produced. Are there any ways I can directly configure the output graph size in Jupyter.
In other words, how can I change the size in the first figure to the size in the second figure, while not messing up the plot.
You need to manually set the tick size, marker size and text size. The text size and tick size can be set through the theme() function, while marker size through geom_point() function.
df_1 = data.frame(x=c(5, 6, 7, 8, 9), y = c(200, 225, 250, 270, 310))
options(repr.plot.width = 1, repr.plot.height = 0.75)
ggplot(df_1, aes(x = x, y = y)) + geom_point(size = 0.3) +
theme(text = element_text(size = 3), element_line(size = 0.1))
You should simply change the resolution of your plot. For instance, try repr.plot.res = 100 in:
options(repr.plot.width = 1, repr.plot.height = 0.75, repr.plot.res = 100)

How do I plot a legend next to my title (outside plot) using R?

I'm using base R plot(), and I want a legend (a color block and key) to show up above (outside) the top right of my plot next to my title (generated using title()).
What's the best way to do this?
Maybe something like this is what you're looking for:
x <- c(1,2,3,4)
y <- c(4,1,3,2)
z <- c(1,2,3,4)
dat <- data.frame(x,y,z)
windows(width = 5, height = 9) #quartz() on Mac
layout(matrix(c(1,2), 2, 1, byrow = TRUE), heights=c(0.5,1))
par(oma = c(4,3,0,0) + 0.1, mar = c(0,0,1,1) + 0.1)
plot(dat$x, y=rep(1,4), type = "n", axes = F, ylab = "", xlab = "")
legend(x = "bottomright", legend = c("y", "z"), fill = c("blue", "red"))
plot(dat$x, dat$y, type = "n", main = "PLOT")
lines(z, col = "red")
lines(y, col = "blue")
Basically this makes two plots, one is just invisible and shortened so all that's displayed is the legend.
You may be able to addtionally tweak the margins around the legend and other graphical parameters (?par) to get the layout better.

Resources