I would like to animate a ggplot with gganimate using geom_area with different values for the years between 2000 and 2050. However, for some reason if I include view_zoom to keep the y-axis fixed and to zoom out along the x-axis for around the first 50 frames it zooms in between the values 1999.95 and 2000.05 and for the last 50 frames it shows the whole range of the x-axis (from year 2000 to 2050). How can I fix this, so that it gradually zooms out until it shows the whole range of the x-axis at the end?
library(gganimate)
library(tidyverse)
gif_data <-
tibble(year = as.numeric(2000:2050),
value = as.numeric(seq(0.5, 0.3, length.out = 51)))
gif <-
ggplot(gif_data,
aes(x = year,
y = value)) +
geom_area() +
transition_reveal(year) +
ggtitle('Frame {frame} of {nframes}') +
view_zoom(fixed_y = TRUE)
animate(gif,
fps = 10,
duration = 10,
height = 337.5,
width = 600,
units = "px",
res = 50,
renderer = gifski_renderer())
anim_save("~/Desktop/gif.gif",
animation = last_animation())
Use view_follow instead of view_zoom like this:
gif <-
ggplot(gif_data,
aes(x = year,
y = value)) +
geom_area() +
transition_reveal(year) +
ggtitle('Frame {frame} of {nframes}') +
view_follow(fixed_y = TRUE)
When I plot using ggplot I get grey vertical lines on my plot before data chart. Any ideas on how to remove it would be highly appreciated.
ggplot(fitbit_data, aes(x = Date, y = Steps)) +
geom_bar(stat = "identity", fill = "green") +
labs(title = "My Steps", subtitle = " June - Dec 2019",
x = " Date", y = "Steps") +
scale_x_date(
date_labels = "%b\n%Y",
date_breaks = "1 month",
limits = c(as.Date("2019-06-01"), as.Date("2019-12-31"))
)
Likely the data is converted to factor, thus ggplot shows a categorical y-axis, that then appears with overlapping labels that look like those grey columns.
When reading the data make sure to use
df= read.table(...,
# assign appropriate data types by using
colClasses = c(...),
... ,
# it can also be adviseable to use
stringsAsFactors = FALSE)
ggplot lets me control the position of my x-axis labels and breaks in x-axis but when I pass the ggplot object to ggplotly function, the resulting plotly object loses the formatting.
library(plotly)
df <- data.frame(
Date = seq(as.Date("2017-01-01"), as.Date("2020-01-01"), by = 30),
Value = rnorm(37)
)
p1 = ggplot(df) + geom_point(aes(x=Date, y = Value)) +
scale_x_date(position = "top", date_breaks = "1 year", date_minor_breaks =
"3 months")
ggplotly(p1)
With the code mention above the x-axis values are still plotted at the bottom in ggplotly plot and also the break lines every 3 months are not shown.
You could try this:
f <- list(
side = "top"
)
ggplotly(p1) %>% layout(xaxis = f)
running into issues while plotting stock data in ggplot2 and with an x-axis that contains gaps from weekends and holidays. this post has been very helpful, but i run into a variety of issues when trying to use ordered factors.
library(xts)
library(grid)
library(dplyr)
library(scales)
library(bdscale)
library(ggplot2)
library(quantmod)
getSymbols("SPY", from = Sys.Date() - 1460, to = Sys.Date(), adjust = TRUE, auto.assign = TRUE)
input <- data.frame(SPY["2015/"])
names(input) <- c("Open", "High", "Low", "Close", "Volume", "Adjusted")
# i've tried changing rownames() to index(), and the plot looks good, but the x-axis is inaccurate
# i've also tried as.factor()
xaxis <- as.Date(rownames(input))
input$xaxis <- xaxis
p <- ggplot(input)
p <- p + geom_segment(aes(x = xaxis, xend = xaxis, y = Low, yend = High), size = 0.50) # body
p <- p + geom_segment(aes(x = xaxis - 0.4, xend = xaxis, y = Open, yend = Open), size = 0.90) # open
p <- p + geom_segment(aes(x = xaxis, xend = xaxis + 0.4, y = Close, yend = Close), size = 0.90) # close
p <- p + scale_y_continuous(scale_y_log10())
p + ggtitle("SPY: 2015")
The plot above (sans red boxes) is generated with the above code segment. And the following charts are some of the issues when attempting some solutions. First, if I try using the data frame's index, I will generate I nice looking graph, but the x-axis is inaccurate; the data currently ends in October, but in the plot below it ends in July:
xaxis <- as.Date(index(input))
Second, if I try coercing the rownames to an ordered factor, I lose my horizontal tick data (representing the open and the close).
xaxis <- factor(rownames(input), ordered = TRUE)
The same issue of removing the horizontal ticks happens if I use the package bdscale, but the gridlines are cleaner:
p <- p + scale_x_bd(business.dates = xaxis)
The method below uses faceting to remove spaces between missing dates, then removes white space between facets to recover the look of an unfaceted plot.
First, we create a grouping variable that increments each time there's a break in the dates (code adapted from this SO answer). We'll use this later for faceting.
input$group = c(0, cumsum(diff(input$xaxis) > 1))
Now we add the following code to your plot. facet_grid creates a new facet at each location where there was a break in the date sequence due to a weekend or holiday. scale_x_date adds major tick marks once per week and minor grid lines for each day, but you can adjust this. The theme function gets rid of the facet strip labels and the vertical spaces between facets:
p + facet_grid(. ~ group, space="free_x", scales="free_x") +
scale_x_date(breaks=seq(as.Date("2015-01-01"),max(input$xaxis), "1 week"),
minor_breaks="1 day",
labels=date_format("%b %d, %Y")) +
theme(axis.text.x=element_text(angle=-90, hjust=0.5, vjust=0.5, size=11),
panel.margin = unit(-0.05, "lines"),
strip.text=element_text(size=0),
strip.background=element_rect(fill=NA)) +
ggtitle("SPY: 2015")
Here's the resulting plot. The spaces for weekends and holidays are gone. The major breaks mark each week. I set the weeks in thescale_x_date breaks argument to start on a Thursday since none of the holidays fell on a Thursday and therefore each facet has a major tick mark for the date. (In contrast, the default breaks would fall on a Monday. Since holidays often fall on a Monday, weeks with Monday holidays would not have a major tick mark with the default breaks.) Note, however, that the spacing between the major breaks inherently varies based on how many days the market was open that week.
If you'd like to use bdscale for this, just tell it to use more gridlines:
ggplot(input) +
geom_segment(aes(x = xaxis, xend = xaxis, y = Low, yend = High), size = 0.50) + # body
geom_segment(aes(x = xaxis - 0.4, xend = xaxis, y = Open, yend = Open), size = 0.90) + # open
geom_segment(aes(x = xaxis, xend = xaxis + 0.4, y = Close, yend = Close), size = 0.90) + # close
ggtitle("SPY: 2015") +
xlab('') + ylab('') +
scale_x_bd(business.dates=xaxis, max.major.breaks=10, labels=date_format("%b '%y")) # <==== !!!!
It should put October on the axis there, but it's not that smart. Womp womp. Pull requests welcome!
You'll probably need to treat the dates as discrete values rather than continuous. This approach with a slightly simplified version of your code might look like:
getSymbols("SPY", from = Sys.Date() - 1460, to = Sys.Date(), adjust = TRUE, auto.assign = TRUE)
SPY <- SPY["2015/"]
colnames(SPY) <- sub("SPY.","", colnames(SPY))
month_brks <- c(1,endpoints(SPY, "months")[-1])
p <- ggplot(data.frame(xaxis=seq(nrow(SPY)), SPY))
p <- p + geom_linerange(aes(x=xaxis, ymin=Low, ymax=High), size=.5)
p <- p + geom_text(aes(x = xaxis, y = Open), size = 4., label="-", hjust=.7, vjust=0) # Open
p <- p + geom_text(aes(x = xaxis, y = Close), size = 4., label="-", hjust=-.1, vjust=0) # close
p <- p + scale_x_continuous(breaks=month_brks, labels=format(index(SPY)[month_brks], "%d %b %Y"))
p <- p + labs(title="SPY: 2015", x="Date", y="Price")
UPDATE
Updated treatment of axis labels.
Well, you can tweak it manually, but it's kind of hacky. First, you should use index, so that your observations are numbered 1 to 188.
input$xaxis <-index(as.Date(rownames(input)))
Then your own plot code:
p <- ggplot(input)
p <- p + geom_segment(aes(x = xaxis, xend = xaxis, y = Low, yend = High), size = 0.50) # body
p <- p + geom_segment(aes(x = xaxis - 0.4, xend = xaxis, y = Open, yend = Open), size = 0.90) # open
p <- p + geom_segment(aes(x = xaxis, xend = xaxis + 0.4, y = Close, yend = Close), size = 0.90) # close
p <- p + scale_y_continuous(scale_y_log10()) + ggtitle("SPY: 2015")
And finally, I looked in input where the breaks should be made, and supplied the labels manually:
p + scale_x_continuous(breaks=input$xaxis[c(1,62,125,188)], labels=c("jan","apr","jul","oct"))
NOTE HERE that I was lazy and just took the closest date for 1-jan, 1-apr 1-jul and 1-oct, because 1 jan is a holiday, the label "jan" stands below 2-jan. And I put the label "oct" below below 30-sep, the last entry in input. You can off course adjust this as you wish.
Off course, you could automate the label add a label field with date and extract the month.
Haven't been able to get the OHLC to work - think you'd need a custom geom.
I know it isn't exactly what you asked for, but may I tempt you with a delicious candle chart instead?
library(dplyr)
library(bdscale)
library(ggplot2)
library(quantmod)
library(magrittr)
library(scales)
getSymbols("SPY", from = Sys.Date() - 1460, to = Sys.Date(), adjust = TRUE, auto.assign = TRUE)
input <- data.frame(SPY["2015/"]) %>%
set_names(c("open", "high", "low", "close", "volume", "adjusted")) %>%
mutate(date=as.Date(rownames(.)))
input %>% ggplot(aes(x=date, ymin=low, ymax=high, lower=pmin(open,close), upper=pmax(open,close),
fill=open<close, group=date, middle=pmin(open,close))) +
geom_boxplot(stat='identity') +
ggtitle("SPY: 2015") +
xlab('') + ylab('') + theme(legend.position='none') +
scale_x_bd(business.dates=input$date, max.major.breaks=10, labels=date_format("%b '%y"))
I want to add some labels to a plot on which the x-axis is a Date. I want the label to be centered around the middle. How do I find the midpoint on the x-axis?
Example:
example <- data.frame(time = c("02/26/11", "05/26/10", "05/27/10", "05/28/10",
"05/29/10", "06/27/10", "06/30/10", "10/27/10",
"10/27/10", "12/26/12"),
value = c(5, 1, 7, 8, 11, 20, 14, 1, 20, 12))
example$time <- as.Date(example$time, format = "%m/%d/%Y")
ggplot(example, aes(x = time, y = value)) + geom_point() +
scale_x_date(labels = date_format("%b%Y"),
breaks = "3 month",
minor_breaks = "1 month")
Now, I want to use geom_text to add a text lable that has x coordinate positioned int he middle of the x-axis, and y at the middle of the y-axis.
It sounds like you just want something like
xx<-data.frame(
time=mean(range(example$time)),
value=mean(range(example$value))
)
ggplot(example, aes(x = time, y = value)) + geom_point() +
geom_text(data=xx, label="midtext") +
scale_x_date(labels = date_format("%b%Y"),
breaks = "3 month",
minor_breaks = "1 month")
We find the center of the plot by finding the center of the ranges of each of the axes. Then we use theses values in the call to geom_text.
That will produce this picture.
PS. I also changed your date formatting line to
example$time <- as.Date(example$time, format = "%m/%d/%y")
since you only have two-digit years and not 4 digit years.