问题
Goal:
Import, transform / prep, and animate a coronavirus dataset from .xlsx using only R.
Text from Reproducible Error:
Error in seq.default(range[1], range[2], length.out = nframes) : 'from' must be a finite number
R Script:
# tidyverse contains ggplot2, dplyr, readr, and tibble libraries
# ggplot2 contains scales library
# install.packages("tidyverse")
library("tidyverse")
# install.packages("RColorBrewer")
library("RColorBrewer")
# install.packages("ggthemes")
library("ggthemes")
# install.packages("gganimate")
library("gganimate")
# install.packages("readxl")
library("readxl")
# create <chr> object to store list of names of 10 most populous TX counties
top10 <- c("Harris", "Dallas", "Tarrant", "Bexar", "Travis", "Collin", "Hidalgo", "El Paso", "Denton", "Fort Bend")
# —1—IMPORT—
# store unmodified .xlsx file from TX Dept. of State Health Services in 'wide' object
# define object 'wide' to store relevant portions of table from Excel file
wide <- read_xlsx("Texas COVID-19 Case Count Data by County.xlsx",
sheet = NULL, # defaults to first sheet
skip = 2, # skip first 2 rows
col_names = TRUE, # 3rd row contains column header names
n_max = 255) # exclude all irrelevant rows after first 255 records
# —2—TRANSFORM—PREP—
# improve dataset usability by transposing table from wide to long format
# define 'long' object to modify and store long format table
long <- wide %>%
gather(Date, Cases, -c("County Name", "Population"))
# creates 'Date' and 'Cases' columns to transpose and store values
# transform / prep the table with a few tweaks
# changes first column header name from 'County Name' to 'County'
colnames(long)[colnames(long) == "County Name"] = "County"
# removes unneeded text from all values in 'Date' column
long$Date <- gsub("Cases\r\n\r\n", "", long$Date)
# changes all values in 'Date' column from <chr> to <date> format
long$Date <- as.Date(long$Date, "%m-%d")
# changes all values in 'Population' & 'Cases' column from <dbl> to <int> format
long$Population <- as.integer(long$Population)
long$Cases <- as.integer(long$Cases)
# add ability to compare % of population infected between counties
# adds 'Rate' column
long <- mutate(long, Rate = Cases/Population)
# note: you can ignore the 'Rate' column because it is not relevant to my question and not relevant to the animation
# —3—ANIMATE—
# animates dataset over time
covid_animation <- long %>% filter(County != "Total" & County %in% top10) %>%
# sets aesthetic to map 'Date' on x-axis and 'Cases' on y-axis...
ggplot(aes(Date, Cases,
# ...the size of each county's dot proportional to its population...
size = Population,
# ...and a unique color and label for each county's dot
color = County, label = County)) +
# further species that each county's dot should be 70% opaque and that the legend should not be shown because labels are readable
geom_point(alpha = 0.7, show.legend = FALSE) +
# scale_colour_manual() +
# scale_colour_brewer(palette="Set1") +
# further specifies that each county's dot should range in size on a 1 to 20 scale
scale_size(range = c(1, 20)) +
# adds a vertical blue line intersecting the x-axis at a value (date) of May 1st, 2020
geom_vline(xintercept=as.numeric(as.Date("2020-05-01")), color="blue") +
# specifies text rules for each county's dot
geom_text(check_overlap = FALSE, hjust = 0, nudge_x= 6, color="black", size=3) +
# adds label for vertical blue line
annotate("text", x = as.Date("2020-05-01"), y = 9000, label = "Texas Re-opens » ", color = "blue", hjust = 1) +
# specifies ggplot theme
theme_minimal() +
# specifies text for chart attributes
labs(title="Total Coronavirus Cases in Texas on: {frame_time}",
subtitle="for 10 most populous counties",
caption="Dataset Source: Texas Department of State Health Services, May 22, 2020",
x="",
y="") +
# potentially where the issue is...animates the plot with gganimate function and produces a frame for each date
transition_time(Date) +
# another gganimate function to smooth the transition between frames
ease_aes('sine-in')
# saves animation as .gif in your present working directory
anim_save("covid_animation.gif", covid_animation)
#
#
#
Additional
Information
To Consider:
#
#
#
• as_tibble(wide)
and as_tibble(long)
returns the following, which indicates steps steps #1 (Import) and #2 (Transform/Prep) ran successfully. Based on my research and answers to other StackOverflow questions, I would guess the issue possibly lies with transition_time(Date)
when defining covid_animation
.
#
#
#
• Animation runs perfectly when I transform / prep the dataset outside of R using OpenRefine and Excel, and when I use a modified version of the R script from above (see below). as_tibble(long)
from the script above appears to return the same structure and format as as_tibble(current_date)
from the script below — which seems like it rules out any issues with the file itself (Note: You can ignore the difference in the row count — the source file for this happens to be from an earlier date, so there are fewer rows, but the structure is the same.)
# tidyverse contains ggplot2, dplyr, readr, and tibble libraries
# ggplot2 contains scales library
# install.packages("tidyverse")
library("tidyverse")
# install.packages("RColorBrewer")
library("RColorBrewer")
# install.packages("ggthemes")
library("ggthemes")
# install.packages("gganimate")
library("gganimate")
# creates <chr> object to store list of names of 10 most populous TX counties
top10 <- c("Harris", "Dallas", "Tarrant", "Bexar", "Travis", "Collin", "Hidalgo", "El Paso", "Denton", "Fort Bend")
# stores modified file from TX Dept. of State Health Services in 'current_date' object
current_date <- read.table("COVID.csv", sep=",", header=TRUE)
# file has been modified outside of R using OpenRefine and Excel
# file modifications include:
# changed filename from 'Texas COVID-19 Case Count Data by County.xlsx' to 'COVID.csv'
# deleted irrelevant headers, footers, rows, and cells
# changed name of first column header from 'County Name' to 'County'
# deleted unnecessary text preceding date text from all values in 'Date' column
# changed format of all values in 'Date' column from <chr> to default <date> format in Excel
# note: my goal is to do all of the preceding modifications in R rather than using OpenRefine and Excel
# changes 'Date' column contents from <chr> to <date> just to be sure
current_date <- mutate(current_date, Date = as.Date(Date, "%m/%d"))
# add ability to compare % of population infected between counties
# adds 'Rate' column
current_date <- mutate(current_date, Rate = Cases/Population)
# animates dataset over time
covid_animation <- current_date %>% filter(County != "Total" & County %in% top10) %>%
# sets aesthetic to map 'Date' on x-axis and 'Cases' on y-axis...
ggplot(aes(Date, Cases,
# ...the size of each county's dot proportional to its population...
size = Population,
# ...and a unique color and label for each county's dot
color = County, label = County)) +
# further species that each county's dot should be 70% opaque and that the legend should not be shown because labels are readable
geom_point(alpha = 0.7, show.legend = FALSE) +
# scale_colour_manual() +
# scale_colour_brewer(palette="Set1") +
# further specifies that each county's dot should range in size on a 1 to 20 scale
scale_size(range = c(1, 20)) +
# adds a vertical blue line intersecting the x-axis at a value (date) of May 1st, 2020
geom_vline(xintercept=as.numeric(as.Date("2020-05-01")), color="blue") +
# specifies text rules for each county's dot
geom_text(check_overlap = FALSE, hjust = 0, nudge_x= 6, color="black", size=3) +
# adds label for vertical blue line
annotate("text", x = as.Date("2020-05-01"), y = 9000, label = "Texas Re-opens » ", color = "blue", hjust = 1) +
# specifies ggplot theme
theme_minimal() +
# specifies text for chart attributes
labs(title="Total Coronavirus Cases in Texas on: {frame_time}",
subtitle="for 10 most populous counties",
caption="Dataset Source: Texas Department of State Health Services, May 22, 2020",
x="",
y="") +
# potentially where the issue is...animates the plot with gganimate function and produces a frame for each date
transition_time(Date) +
# another gganimate function to smooth the transition between frames
ease_aes('sine-in')
# saves animation as .gif in your present working directory
anim_save("covid_animation.gif", covid_animation)
回答1:
The problem is with your transformation of the column names into Dates. That seems to introduce NAs into the Dates, and makes the range indeterminate, which gganimate uses for the start and end of the animation.
What worked for me was:
names(wide) = janitor::make_clean_names(names(wide))
and
long <- wide %>%
gather(Date, Cases, -county_name, -population) %>%
rename(County = county_name, Population = population) %>%
mutate(Date = as.Date(str_remove(Date, "cases_"), format = "%m_%d")) %>%
mutate(Rate = Cases/Population)
long %>% filter(is.na(Date))
Alternatively, you could use str_remove(Date, "\\D+")
instead of cleaning up the column names beforehand.
来源:https://stackoverflow.com/questions/62030888/gganimate-ggplot2-error-when-using-transition-time-after-transforming-dataset