latest gganimate: How to have a fixed plot in the background? - r

In the latest version of gganimate by https://github.com/thomasp85 I would like to choose which parts of the plot I can keep static throughout the animation and which will be animated. In the previous version of gganimate you could specify the frame in the aes of ggplot. Thus you could create a base plot that would be static and plot the animated plot over this. How can similar be achieved in the latest version?

This has already been addressed in an issue for gganimate on GitHub: https://github.com/thomasp85/gganimate/issues/94
Basically you specify the the layers that are meant to be static with a separate data frame from the one you initially passed to ggplot. The example in the GitHub ticket I referred to is
library(gganimate)
#> Loading required package: ggplot2
ggplot(dat = data.frame(x=1:10,y=1:10), aes(x=x,y=y)) +
geom_point() +
geom_line(data = data.frame(x2 = 1:10, y = 1:10),
aes(x = x2, y = y, group = 1)) +
transition_time(x)
animate(last_plot(), nframes = 50)
Here the line is held static, while the point is moving.

Related

How do I create multiple boxplots whilst also making them proportional using geom_boxplot within ggplot2?

I understand that varwidth = TRUE within ggplot2's geom_boxplot can be used to create proportional boxplots so that each boxplot also summarises the number of points within a plot. However, I am struggling to maintain proportional boxplot sizes whilst also producing multiple plots?
Using the diamonds df in ggplot2 I am trying to reproduce the below image.
What I have tried is this:
ggplot(data = diamonds, mapping = aes(x = carat, y = price)) + geom_boxplot(mapping = aes(group = cut_number(carat, 20), varwidth = TRUE))
I tried to use cut_number to achieve the multiple, and var-width for proportionality. I'd also like to have the boxplots show vertically. I have been stumped on this for hours and have looked online but to no avail. Any tips?
Since ggplot2 v3.3.0, the orientation of layers are autodetected. In some cases, this detection can be incorrect. You can force the orientation by adding it as an argument to a layer:
library(ggplot2)
ggplot(data = diamonds, mapping = aes(x = carat, y = price)) +
geom_boxplot(mapping = aes(group = cut_number(carat, 20)),
orientation = "x")
Created on 2020-05-01 by the reprex package (v0.3.0)

stat_density2d tile geom showing grid when exporting as PDF

I'm having an issue when exporting stat_density2d plots.
ggplot(faithful, aes(eruptions, y = waiting, alpha = ..density..)) +
stat_density2d(geom = 'tile', contour = F)
When exporting as a png it looks like so:
But when I export as a PDF a grid appears:
I'm assuming that this is because the boundaries of the tiles overlap and so have equivalent of a doubled alpha value.
How can I edit just the edges of the tiles to stop this from happening?
Secondary question:
As Tjebo mentioned geom = 'raster' would fix this problem. However, this raises a new issue that only one group gets plot.
df <- faithful
df$new <- as.factor(ifelse(df$eruptions>3.5, 1, 0))
ggplot(df, aes(eruptions, waiting, fill = new, alpha = ..density..)) +
stat_density2d(geom = 'tile', contour = F) +
scale_fill_manual(values = c('1' = 'blue', '0' = 'red'))
ggplot(df, aes(eruptions, waiting, fill = new, alpha = ..density..)) +
stat_density2d(geom = 'raster', contour = F) +
scale_fill_manual(values = c('1' = 'blue', '0' = 'red'))
help on this second issue would also be much appreciated!
Now I decided to transform my comment into an answer instead. Hopefully it solves your problem.
There is an old, related google thread on this topic - It seems related to how the plots are vectorized in each pdf viewer.
A hack is suggested in this thread, but one solution might simply be to use geom = 'raster' instead.
library(ggplot2)
ggplot(faithful, aes(eruptions, y = waiting, alpha = ..density..)) +
stat_density2d(geom = 'raster', contour = F)
Created on 2019-08-02 by the reprex package (v0.3.0)
If you have a look at the geom_raster documentation - geom_raster is recommended if you want to export to pdf!
The most common use for rectangles is to draw a surface. You always want to use geom_raster here because it's so much faster, and produces smaller output when saving to PDF
edit - second part of the question
Your tile plot can't be correct - you are creating cut-offs (your x value), so the fill should not overlap. This points to the core of the problem - the alpha=..density.. probably calculates the density based on the entire sample, and not by group. I think the only way to go is to pre-calculate the density (e.g., using density(). In your example, for demonstration purpose, we have this luckily precalculated, as faithfuld (this is likely not showing the results which you really want, as it is the density on the entire sample!!).
I'd furthermore recommend not to use numbers as your factor values - this is pretty confusing for you and R. Use characters instead. Also, ideally don't use df for a sample data frame, as this is a base R function;)
Hope this helps
mydf <- faithfuld ## that is crucial!!! faithfuld contains a precalculated density column which is needed for the plot!!
mydf$new <- as.factor(ifelse(mydf$eruptions>3.5, 'large', 'small'))
ggplot(mydf, aes(eruptions, waiting)) +
geom_raster(aes(fill = new, alpha = density), interpolate = FALSE)
Created on 2019-08-02 by the reprex package (v0.3.0)

ggplotly fails with geom_vline() with xintercept Date value

Trying to use ggplotly to graph time series data with a vertical line to indicate dates of interest.
Call fails with Error in Ops.Date(z[[xy]], 86400000) : * not defined for "Date" objects. I have tried unsuccessfully using both the latest CRAN and development versions of ggplot2 (as per plotly recommendation). Other SO questions (e.g., ggplotly and geom_bar when using dates - latest version of plotly (4.7.0)) do not address my concerns.
As illustrated below with plot object p - both ggplot and ggplotly work as expected. However, when a geom_vline() is added to the plot in p2, it only works correctly in ggplot, failing when calling ggplotly(p2).
library(plotly)
library(ggplot2)
library(magrittr)
set.seed(1)
df <- data.frame(date = seq(from = lubridate::ymd("2019-01-01"), by = 1, length.out = 10),
y = rnorm(10))
p <- df %>%
ggplot(aes(x = date, y = y)) +
geom_line()
p ## plots as expected
ggplotly(p) ## plots as expected
p2 <- p + geom_vline(xintercept = lubridate::ymd("2019-01-08"), linetype = "dashed")
p2 ## plots as expected
ggplotly(p2) ##fails
I just solved this using #Axeman's suggestion. In your case, you can just replace the date:
lubridate::ymd("2019-01-01")
becomes
as.numeric(lubridate::ymd("2019-01-01"))
Not pretty, but it works.
For future reference:
The pop-up window for vertical lines created via date (or POSIX*) to numeric conversions is rather blank. This is particularly valid for POSIX* applications where the exact time can often not be read off directly.
In case you need more significant pop-up content, the definition of a text aesthetic could be helpful (just ignore the 'unknown aesthetics' warning as it doesn't seem to apply). Then, simply specify what you want to see during mouse hover via the tooltip argument, ie. rule out xintercept, and you're all set.
p2 = p +
geom_vline(
aes(
xintercept = as.numeric(lubridate::ymd("2019-01-08"))
, text = "date: 2019-01-08"
)
, linetype = "dashed"
)
ggplotly(p2, tooltip = c("x", "y", "text"))

replicate addCCI (quantmod's chartSeries) in ggplot2

In the quantmod package, chartSeries provides the option to "addCCI" which is based on a moving average. The CCI chart uses a very good idea but is based on a moving average whereas I prefer to use a single long term average which is why Im trying to replicate the chart in ggplot2 instead of in quantmod.
the addCCI picture I want to replicate is the bottom chart
I want to use the same concept of using a highlighted area for the range outside of the +100/-100 but Id like to highlight points above and below 1 standard deviation from the long term mean. In the picture below.
ideally I want the area above and below 1 std dev to appear the same as in the addCCI chart
library(quantmod)
library(ggplot2)
y <- rnorm(31,2,1)
x <- seq.Date(as.Date("2015-01-01"),as.Date("2015-01-31"),1)
d<-data.frame(cbind(x,y))
d$pmean <- mean(d$y)
d$m1d <- mean(d$y)-sd(d$y)
d$p1d <- mean(d$y)+sd(d$y)
d2 <- xts(d[,-1],order.by=as.Date(d$x))
chartSeries(d2$y, TA="addCCI(5)")
ggplot(d, aes(as.Date(x))) +
geom_line(aes(y = y, colour = "blue")) +
geom_line(aes(y = pmean, colour = "red")) +
geom_line(aes(y = p1d, colour = "red")) +
geom_line(aes(y = m1d, colour = "red"))
This bit of code is what I used to create the examples above.
Is this even possible in ggplot2 and if so, I would appreciate any help in accomplishing it.
Thank you in advance

Line plot that changes color over "time"

I have a data frame that contains x and y coordinates for a random walk that moves in discrete steps (1 step up, down, left, or right). I'd like to plot the path---the points connected by a line. This is easy, of course. The difficulty is that the path crosses over itself and becomes difficult to interpret. I add jitter to the points to avoid overplotting, but it doesn't help distinguish the ordering of the walk.
I'd like to connect the points using a line that changes color over "time" (steps) according to a thermometer-like color scale.
My random walk is stored in its own class and I'm writing a specific plot method for it, so if you have suggestions for how I can do this using plot, that would be great. Thanks!
This is pretty easy to do in ggplot2:
so <- data.frame(x = 1:10,y = 1:10,col = 1:10)
ggplot(so,aes(x = x, y = y)) +
geom_line(aes(group = 1,colour = col))
If you prefer not to use ggplot, then ?segments will do what you want. -- I'm assuming here that x and y are both functions of time, as implied in your example.
If you use ggplot, you can set the colour aesthetic:
library(ggplot2)
walk <-cumsum(rnorm(n=100, mean=0))
dat <- data.frame(x = seq_len(length(walk)), y = walk)
ggplot(dat, aes(x,y, colour = x)) + geom_line()

Resources