I need to create a map like that on the picture in R, but by County level. I have CSV file with names of Florida Counties and the column with the population by county.
How can I create a map?
Thank you!
The built in maps data is kinda meh and out of date. I have no idea if the county boundaries have changed. I prefer the county maps from here: http://www.baruch.cuny.edu/geoportal/data/esri/esri_usa.htm
And, this http://www.baruch.cuny.edu/geoportal/data/esri/usa/census/counties.zip is the direct link to the US counties shapefile.
If you grab ogr you can extract Florida with:
ogr2ogr -f "ESRI Shapefile" -where "STATE_NAME = 'FLORIDA'" fl.shp counties.shp
Then read it into R and have some fun. I found some population data:
pop <- structure(list(County = c("Alachua", "Baker", "Bay", "Bradford",
"Brevard", "Broward", "Calhoun", "Charlotte", "Citrus", "Clay",
"Collier", "Columbia", "DeSoto", "Dixie", "Duval", "Escambia",
"Flagler", "Franklin", "Gadsden", "Gilchrist", "Glades", "Gulf",
"Hamilton", "Hardee", "Hendry", "Hernando", "Highlands", "Hillsborough",
"Holmes", "Indian River", "Jackson", "Jefferson", "Lafayette",
"Lake", "Lee", "Leon", "Levy", "Liberty", "Madison", "Manatee",
"Marion", "Martin", "Miami-Dade", "Monroe", "Nassau", "Okaloosa",
"Okeechobee", "Orange", "Osceola", "Palm Beach", "Pasco", "Pinellas",
"Polk", "Putnam", "St. Johns", "St. Lucie", "Santa Rosa", "Sarasota",
"Seminole", "Sumter", "Suwannee", "Taylor", "Union", "Volusia",
"Wakulla", "Walton", "Washington"),
pop = c(248002L, 26881L,
169866L, 27217L, 548424L, 1784715L, 14621L, 163679L, 140519L,
192843L, 333663L, 67489L, 34367L, 16263L, 876075L, 301120L, 97843L,
11562L, 47588L, 16880L, 12658L, 16106L, 14507L, 27682L, 37808L,
173808L, 99092L, 1276410L, 20022L, 139586L, 50166L, 14554L, 8618L,
303317L, 643367L, 278377L, 40304L, 8483L, 19395L, 333880L, 335008L,
148077L, 2582375L, 73560L, 74661L, 188349L, 39762L, 1202978L,
288361L, 1345652L, 473566L, 926610L, 613950L, 72605L, 201541L,
281151L, 157317L, 385292L, 431074L, 105104L, 43873L, 23018L,
15483L, 498978L, 30869L, 57779L, 24793L)),
.Names = c("County",
"pop"), class = "data.frame", row.names = c(NA, -67L))
and that is easily integrated into a choropleth:
library(sp)
library(maptools)
library(ggplot2)
library(plyr)
library(ggplot2)
# read in the florida county shapefile
fl <- readShapePoly("fl.shp", repair=TRUE, IDvar="NAME")
# make it work nicely with ggplot
fl.f <- fortify(fl, region="NAME")
# start the plot
gg <- ggplot(pop)
# plot the base mape
gg <- gg + geom_map(data=fl.f, map = fl.f, aes(map_id=id, x = long, y = lat),
fill="white", color="#7f7f7f", size=0.25)
# add the county population data
gg <- gg + geom_map(map = fl.f, aes(map_id = County, fill = pop), size=0.25)
# should prbly not do this - use `cut` for explicit groupings
# i was pressed for time
gg <- gg + scale_fill_gradient(low="#fff7bc", high="#cc4c02", name="Population")
gg <- gg + theme_bw()
gg <- gg + labs(x="", y="")
gg <- gg + theme(plot.background = element_rect(fill = "transparent",colour = NA),
panel.border = element_blank(),
panel.background =element_rect(fill = "transparent",colour = NA),
panel.grid = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
legend.position="right")
gg
NOTE that you'll have to ensure the county names match up with what's in the fl.shp structure:
unique(fl.f$id)
## [1] "Alachua" "Baker" "Bay" "Bradford" "Brevard" "Broward" "Calhoun"
## [8] "Charlotte" "Citrus" "Clay" "Collier" "Columbia" "DeSoto" "Dixie"
## [15] "Duval" "Escambia" "Flagler" "Franklin" "Gadsden" "Gilchrist" "Glades"
## [22] "Gulf" "Hamilton" "Hardee" "Hendry" "Hernando" "Highlands" "Hillsborough"
## [29] "Holmes" "Indian River" "Jackson" "Jefferson" "Lafayette" "Lake" "Lee"
## [36] "Leon" "Levy" "Liberty" "Madison" "Manatee" "Marion" "Martin"
## [43] "Miami-Dade" "Monroe" "Nassau" "Okaloosa" "Okeechobee" "Orange" "Osceola"
## [50] "Palm Beach" "Pasco" "Pinellas" "Polk" "Putnam" "Santa Rosa" "Sarasota"
## [57] "Seminole" "St. Johns" "St. Lucie" "Sumter" "Suwannee" "Taylor" "Union"
## [64] "Volusia" "Wakulla" "Walton" "Washington"
I didn't bother checking for my example (tho it looks like it's OK), but for real data you prbly should.
Here is how you get a map of counties for Florida:
library(maps)
m <- map("county", "Florida")
Adding the information to the map (such as a heat index) is a different question.
If you want to map the population of Florida at the county level check out this https://cran.r-project.org/web/packages/usmap/vignettes/mapping.html. They use usmaps.
Related
I am working on a project where I need to make a map for the top global streaming music. And I have got the map with song's streamings in different location.
Here is my map
Here is my code, Below are the background info and some data cleaning:
library("dplyr")
library("stringr")
library("tidyverse")
library("scales")
library("ggplot2")
library("maps")
library("leaflet")
# load the .csv into R studio, you can do this 1 of 2 ways
#read.csv("the name of the .csv you downloaded from kaggle")
#spotiify_origional <- read.csv("charts.csv")
spotiify_origional <- read.csv("https://raw.githubusercontent.com/info201a-au2022/project-group-1-section-aa/main/data/charts.csv")
# filters down the data
# removes the track id, explicit, and duration columns
spotify_modify <- spotiify_origional %>%
select(name, country, date, position, streams, artists, genres = artist_genres)
#returns all the data just from 2022
#this is the data set you should you on the project
spotify_2022 <- spotify_modify %>%
filter(date >= "2022-01-01") %>%
arrange(date) %>%
group_by(date)
spotify_2022$streams <- as.numeric(spotify_2022$streams)
View(spotify_2022)
spotify_2022_global <- spotify_modify %>%
filter(date >= "2022-01-01") %>%
filter(country == "global") %>%
arrange(date) %>%
group_by(date)
View(spotify_2022_global)
# use write.csv() to turn the new dataset into a .csv file
#write.csv(Your DataFrame,"Path to export the DataFrame\\File Name.csv", row.names = FALSE)
#write.csv(spotify_2022_global, "/Users/oliviasapp/Documents/info201/project-group-1-section-aa/data/spotify_2022.csv" , row.names = FALSE)
# top 5 most popular songs globally
top_5 <- spotify_2022_global[order(spotify_2022_global$streams, decreasing = TRUE), ]
top_5 <- top_5[1:5, ]
top_5$streams <- as.numeric(top_5$streams)
View(top_5)
# Pepas, Blank Space, I'm Tired, Yonaguni, and Heather
# were the most streamed song of the year according to top_5
Here is the map part:
# makes the map template
world_map <- map_data("world")
ggplot(world_map, aes(x = long, y = lat, group = group)) +
geom_polygon(fill="lightgray", colour = "white")
# a new data frame that has all the abrevated country codes and the country names
abrevations <- read.csv("https://pkgstore.datahub.io/core/country-list/data_csv/data/d7c9d7cfb42cb69f4422dec222dbbaa8/data_csv.csv")
#abrevations <- read.csv("wikipedia-iso-country-codes.csv")
# shortens abreviations to only include names and 2 char codes
abrevations <- abrevations %>%
select(region = Name, Code)
abrevations$region <- str_replace(abrevations$region, "United States", "USA")
abrevations$region <- str_replace(abrevations$region, "Libyan Arab Jamahiriya", "Libya")
abrevations$region <- str_replace(abrevations$region, "Côte d'Ivoire", "Ivory Coast")
abrevations$region <- str_replace(abrevations$region, "Tanzania, United Republic of", "Tanzania")
abrevations$region <- str_replace(abrevations$region, "Republic of Democratic Republic of the Congo", "Democratic Republic of the Congo")
abrevations$region <- str_replace(abrevations$region, "Congo", "Republic of Congo")
abrevations$region <- str_replace(abrevations$region, "Republic of Republic of Republic of Congo", "Republic of Congo")
abrevations$region <- str_replace(abrevations$region, "South Sudan", "Sudan")
abrevations$region <- str_replace(abrevations$region, "Syrian Arab Republic", "Syria")
abrevations$region <- str_replace(abrevations$region, "Korea, Democratic People's Republic of", "North Korea")
abrevations$region <- str_replace(abrevations$region, "Korea, Republic of (South Korea)", "South Korea")
abrevations$region <- str_replace(abrevations$region, "Lao People's Democratic Republic", "Laos")
abrevations$region <- str_replace(abrevations$region, "United Kingdom", "UK")
abrevations$region <- str_replace(abrevations$region, "Moldova, Republic of", "Moldova")
abrevations$region <- str_replace(abrevations$region, "Macedonia, the former Yugoslav Republic of", "North Macedonia")
# makes a list off all the countries where the song was popular this year
get_song_streams <- function(song_name) {
song_streams <- spotify_2022 %>%
select(name, date, country, streams) %>%
filter(name == song_name) %>%
filter(country != "global") %>%
group_by(country) %>%
summarize(streams = sum(streams)) %>%
rename(Code = country)
song_streams$Code <- toupper(song_streams$Code) #capatalizes country codes
# data frame that join's abrevations with the modified countries that listened to a song
# if a country listened to Peopas they get a 1, if not they get a 0
abrevs <- left_join(abrevations, song_streams, by = "Code") %>%
replace(is.na(.), 0)
# fixes some of the names of the countries in abrevs so they match the countries in world_map
# dataframe that will go into the map
top_country.map <- left_join(world_map, abrevs, by = "region")
return(top_country.map)
}
# gets rid of grid lines
blank_theme <- theme_bw() +
theme(
axis.line = element_blank(), # remove axis lines
axis.text = element_blank(), # remove axis labels
axis.ticks = element_blank(), # remove axis ticks
axis.title = element_blank(), # remove axis titles
plot.background = element_blank(), # remove gray background
panel.grid.major = element_blank(), # remove major grid lines
panel.grid.minor = element_blank(), # remove minor grid lines
panel.border = element_blank() # remove border around plot
)
plot_song_map <- function(song_name){
# map of the world. Yellow countries listened to Blenk Space, blue countries did not
# grey countries means we have no data
plot<- ggplot(get_song_streams(song_name), aes(map_id = region, fill = streams))+
geom_map(map = get_song_streams(song_name), color = "white")+
expand_limits(x = get_song_streams(song_name)$long,
y = get_song_streams(song_name)$lat)+
ggtitle(paste("How popular was the song", song_name, "in each country?")) +
scale_fill_continuous(type = "viridis", labels = comma) +
labs(fill = "Streams") +
blank_theme
return(plot)
}
leaflet(plot_song_map("Blank Space"))
plot_song_map("Blank Space")
plot_song_map("I’m Tired (with Zendaya) - Bonus Track")
plot_song_map("Yonaguni")
I wonder how can I make this map interactive? So I can upload it to Shiny later on. I tried to use leaflet but it returns a blank.
Thank you so much in advance! Any comments or suggestions will help!
I have this network graph that I made using the "igraph" library:
library(tidyverse)
library(igraph)
set.seed(123)
n=15
data = data.frame(tibble(d = paste(1:n)))
relations = data.frame(tibble(
from = sample(data$d),
to = lead(from, default=from[1]),
))
data$name = c("new york", "chicago", "los angeles", "orlando", "houston", "seattle", "washington", "baltimore", "atlanta", "las vegas", "oakland", "phoenix", "kansas", "miami", "newark" )
graph = graph_from_data_frame(relations, directed=T, vertices = data)
(edge_fac <- forcats::as_factor(get.edgelist(graph)[,1]))
n2 <- as.integer(factor(data$name,levels = levels(edge_fac)))
V(graph)$color <- ifelse(data$d == relations$from[1], "red", "orange")
V(graph)$label <- paste0(data$name,"\n\n\n",n2)
plot(graph, layout=layout.circle, edge.arrow.size = 0.2, main = "my_graph")
Is it somehow possible to convert the above graph into a "visnetwork" graph, so that it looks like this?
I know there is a function ( visIgraph() ) meant for converting "igraph" graps to "visnetwork" graphs: https://www.rdocumentation.org/packages/visNetwork/versions/2.1.0/topics/visNetwork-igraph
But I am not sure if I can transform the first "igraph" graph (with both "numeric" and "text" labels) into an interactive "visnetwork" graph.
I tried to do this with the following code :
visIgraph(graph)
But this creates an interactive graph without the "number" labels.
Is it possible to do this?
Thank you!
You have to do a bit of manipulation to make this work because this uses base R plotting.
Essentially, these are two different igraph objects lying on top of each other. This is the only way I could think of to have two different 'cex' sizes. It may require a bit of finesse, depending on where you go from here.
library(tidyverse)
library(igraph)
library(gridGraphics) # <--- I'm new!
library(grid) # <--- I'm new!
#----------- from question -----------
set.seed(123)
n=15
data = data.frame(tibble(d = paste(1:n)))
relations = data.frame(tibble(
from = sample(data$d),
to = lead(from, default=from[1]),
))
data$name = c("new york", "chicago", "los angeles", "orlando",
"houston", "seattle", "washington", "baltimore",
"atlanta", "las vegas", "oakland", "phoenix",
"kansas", "miami", "newark" )
graph = graph_from_data_frame(relations,
directed=T,
vertices = data)
(edge_fac <- forcats::as_factor(get.edgelist(graph)[,1]))
n2 <- as.integer(factor(data$name,levels = levels(edge_fac)))
V(graph)$color <- ifelse(data$d == relations$from[1],
"red", "orange")
This is where the changes begin.
#---------- prepare the first plot -----------
# make label text larger
V(graph)$label.cex = 1.5
# V(graph)$label <- paste0(data$name,"\n",n2)
V(graph)$label <- paste0(n2) # just the number instead
#---------- prepare to collect grob ----------
# collect base plot grob
grabber <- function(){
grid.echo()
grid.grab()
}
# create a copy for the top layer
graph2 <- graph
#-------------- plot and grab ----------------
# without arrow sizes
plot(graph, layout=layout.circle, main = "my_graph")
# grab the grob
g1 = grabber()
Now for the second graph; the top layer
#----------- create the top layer -------------
# with the copy, make the vertices transparent
V(graph2)$color <- "transparent"
# reset the font size
V(graph2)$label.cex = 1
# shift the labels below (while keeping the plot design the same)
V(graph2)$label <- paste0("\n\n\n\n", data$name)
# show me
plot(graph2, layout=layout.circle,
main = "my_graph",
edge.color = "transparent") # invisible arrows/ only 1 layer of arrows
# grab the grob
g2 = grabber()
Layer them!
#-------------- redraw the plots -------------
# make the plot background transparent on the top layer
g2[["children"]][["graphics-background"]][["gp"]][["fill"]] <- "transparent"
# draw it!
grid.draw(g1)
grid.draw(g2)
You might find it interesting that the graphs going into the grob look different than what comes out of them...grid essentially adjusts them. I thought that was kind of awesome.
What about creating the graph using visNetwork? You could then add both the number and name as a label inside the nodes.
library(tidyverse)
library(visNetwork)
set.seed(123)
n=15
data = data.frame(tibble(id = paste(1:n)))
relations = data.frame(tibble(
from = sample(data$id),
to = lead(from, default=from[1]),
))
data$name = c("new york", "chicago", "los angeles", "orlando", "houston", "seattle", "washington", "baltimore", "atlanta", "las vegas", "oakland", "phoenix", "kansas", "miami", "newark" )
data$shape ='circle'
data$label = paste0(data$id,'\n',data$name)
data$color = ifelse(data$id==1, 'red', 'orange')
visNetwork(data, relations, width = "100%") %>%
visEdges(arrows =list(to = list(enabled = TRUE))) %>%
visIgraphLayout(layout = "layout_in_circle")
I have written the following code:
library(ozmaps)
oz(states = TRUE, coast = TRUE,
ylim = NULL, add = FALSE, ar = 1, eps = 0.25)
That generates:
I wonder how to add the names of the states on the map? If the whole process can be done by "map" package, it is fine as well.
Thanks.
I'm not familiar with package ozmaps. I could not find data for the state names and latitude and longitude values for state centroids within the package.
A quick internet search produced some representative state data from https://www.distancelatlong.com/distancecalculator/country/australia/
You can adjust this data or find a better source, so this should be a start.
library(tibble)
library(ggplot2)
library(ozmaps)
ggplot(ozmap_states)+
geom_sf()+
geom_text(data = oz_states, aes(long, lat, label = state))+
theme_void()
data
oz_states <- tribble(
~state, ~lat, ~long,
"Australian Capital Territory", -35.3546004, 149.2113468,
"New South Wales", -33.42004148, 151.3000048,
"Northern Territory", -13.81617348, 131.816698,
"Queensland", -26.67998777, 153.0500272,
"South Australia", -34.28293455, 140.6000378,
"Tasmania", -40.83292234, 145.1166613,
"Victoria", -37.73119953, 142.0234135,
"Western Australia", -33.58287392, 120.0333345
)
Created on 2021-03-29 by the reprex package (v1.0.0)
I've been browsing a lot of the topics on mapping in R and would appreciate a little help.
I've made it to this code which builds an image of a purchase density then overlays a US State map on top and a Canadian national map as well.
It's an ok solution, but Ideally I'd like to show the provinces in Canada as well.
library(mapdata);
library(maps);
library(maptools);
library(spatstat);
png(filename=file_name, type="cairo-png", bg="transparent", width=10.*960, height=10.*960, pointsize=1);
spatstat.options(npixel=c(1000,1000));
densitymap<-density(points, sigma=0.15, weights=dedupedMergedZips[!is.na(dedupedMergedZips$longitude), zipCount]);
my.palette <- colorRampPalette(c("#3F3F3F","#e2ffcc","#b6ff7f","white"), bias=2, space="rgb")
image(densitymap, col=my.palette(200));
map("state", col="grey", fill=FALSE, bg="transparent", lwd=3.0, xlim=longitudeLimits, ylim=latitudeLimits, add = TRUE);
map("worldHires","Canada", xlim=longitudeLimits, ylim=latitudeLimits, col="grey", fill=FALSE, bg="transparent", lwd=3.0, add=TRUE)
dev.off()
Any tips on how I could add an additional Arguement to the second line to get the provinces to show?
Thanks
Here is a solution, based on leaflet:
library(rgdal)
if (!file.exists("./src/ref/ne_50m_admin_1_states_provinces_lakes/ne_50m_admin_1_states_provinces_lakes.dbf")){
download.file(file.path('http://www.naturalearthdata.com/http/',
'www.naturalearthdata.com/download/50m/cultural',
'ne_50m_admin_1_states_provinces_lakes.zip'),
f <- tempfile())
unzip(f, exdir = "./src/ref/ne_50m_admin_1_states_provinces_lakes")
rm(f)
}
region <- readOGR("./src/ref/ne_50m_admin_1_states_provinces_lakes", 'ne_50m_admin_1_states_provinces_lakes', encoding='UTF-8')
library(leaflet)
leaflet() %>%
addTiles() %>%
setView(-74.09, 45.7, zoom = 3) %>%
addPolygons(data = subset(region, name %in% c("British Columbia", "Alberta", "Saskatchewan", "Manitoba", "Ontario", "Quebec", "New Brunswick", "Prince Edward Island", "Nova Scotia", "Newfoundland and Labrador", "Yukon", "Northwest Territories", "Nunavut")),
fillColor = topo.colors(10, alpha = NULL),
weight = 1)
Here is another proposal leveraging ggplot2:
library(ggplot2)
regions <- subset(region, name %in% c("British Columbia", "Alberta", "Saskatchewan", "Manitoba", "Ontario", "Quebec", "New Brunswick", "Prince Edward Island", "Nova Scotia", "Newfoundland and Labrador", "Yukon", "Northwest Territories", "Nunavut")) # region is defined in the first part of the code (see above)
ggplot(regions) +
aes(long,lat, group = group, fill = group) +
geom_polygon() +
geom_path(color="white") +
coord_equal() +
guides(fill = FALSE)
I think this might have an easy answer - which I can't seem to find anywhere - so I'll forgo the reproducibility for the moment. I have a function designed to draw a ggplot2. I use mapply to pass it a few vectors of strings for the functions input parameters. The parameter of concern here is title. Which is fed a character vector with elements such as "this is a plot title".
Then the following code:
p <- ggplot(df, aes(x=date, y=value))
## plot the line
p <- p + geom_line()
## add plot title
p <- p + ggtitle(title)
actually works just fine and the plot title is "this is a plot title" as expected.
However if the title is long and I want to specify a point to wrap the title using \n it fails to work.
Precisely if I feed ggtitle an element of "this is a \n plot title". I get exactly that contained in the quotes, rather than wrapping the title at the \n. My suspicion is I need eval, or paste or get, but my formations of such a request have failed to achieve the desired results. I appreciate the help.
UPDATE:
I guess it must be the interaction with mapply. This should allow you to reproduce the problem.
create data.frame of strings as sample and assign it to fred.M.SA
structure(list(RegionalCoverage = c("National", "National", "National",
"National", "National", "National"), GeographicLevel = c("MSA",
"MSA", "MSA", "MSA", "MSA", "MSA"), Category = c("Workers", "Workers",
"Workers", "Workers", "Workers", "Workers"), Sector = c("Labor Market",
"Labor Market", "Labor Market", "Labor Market", "Labor Market",
"Labor Market"), Source2 = c("FRED", "FRED", "FRED", "FRED",
"FRED", "FRED"), Title = c("Unemployment Rate in La Crosse, WI-MN (MSA)",
"Trade, Transportation and Utilities Employment in La Crosse, WI-MN (MSA)",
"Professional and Business Services Employment in La Crosse, WI-MN (MSA)",
"Other Services Employment in La Crosse, WI-MN (MSA)", "Manufacturing Employment in La Crosse, WI-MN (MSA)",
"Leisure and Hospitality Employment \\n in La Crosse, WI-MN (MSA)"
), SeriesID = c("LACR155UR", "LACR155TRAD", "LACR155PBSV", "LACR155SRVO",
"LACR155MFG", "LACR155LEIH"), Units = c("%", "Thous. of Persons",
"Thous. of Persons", "Thous. of Persons", "Thous. of Persons",
"Thous. of Persons"), Freq = c("M", "M", "M", "M", "M", "M"),
Seas = c("SA", "SA", "SA", "SA", "SA", "SA"), OriginalSource = c("U.S. Department of Labor: Bureau of Labor Statistics",
"Federal Reserve Bank of St. Louis", "Federal Reserve Bank of St. Louis",
"Federal Reserve Bank of St. Louis", "Federal Reserve Bank of St. Louis",
"Federal Reserve Bank of St. Louis"), Method = c("ImportXML",
"ImportXML", "ImportXML", "ImportXML", "ImportXML", "ImportXML"
), LinktoSource = c("", "", "", "", "", ""), Link.to.Data.Spreadsheet.Name = c("",
"", "", "", "", ""), Link.to.Data.Storage = c("", "", "",
"", "", ""), Link.to.Data.Manipulation.File = c(NA, NA, NA,
NA, NA, NA), Link.to.Data.Manipulation.File.1 = c(NA, NA,
NA, NA, NA, NA)), .Names = c("RegionalCoverage", "GeographicLevel",
"Category", "Sector", "Source2", "Title", "SeriesID", "Units",
"Freq", "Seas", "OriginalSource", "Method", "LinktoSource", "Link.to.Data.Spreadsheet.Name",
"Link.to.Data.Storage", "Link.to.Data.Manipulation.File", "Link.to.Data.Manipulation.File.1"
), row.names = c(27L, 34L, 44L, 46L, 47L, 48L), class = "data.frame")
MakelineFred <- function(series, ylab="",xlab="", title="") {
require(ggplot2) # hadley's plotting framework
require(scales) # to adjust y axis scales
require(ggthemes) # extra themes including tufte
require(xts) # our favorite time series
require(gridExtra) # for adding a caption
require(timeDate) # for our prediction at the end
require(quantmod) #
# Get Data using quantmod
data <- getSymbols(series,src="FRED") #fred ignore from dates
# convert the string df to object df
data.xts <- get(data)
## convert data to data.frame
df <- data.frame(
date=as.Date(index(data.xts)),
value=as.numeric(data.xts))
p <- ggplot(df, aes(x=date, y=value))
## plot the line
p <- p + geom_line()
## add plot title
p <- p + ggtitle(title)
file <- paste("_",series,".png",sep="")
ggsave(file=file, plot=p, width=6, height=4)
finally here is the mapply call.
mapply(MakelineFred, series=fred.M.SA$SeriesID, title=fred.M.SA$Title)