0

I have an R script which highlights certain states on the US Map. I want to highlight two features and I have been having trouble with the 2nd feature. I attached what the current map looks like below.

  1. Color the whole state red if their bond rating is below a certain grade (this works)
  2. Give a red downward arrow next to the bond rating as a label on the state if the rating is trending downward over the last few years. These have already been flagged and filtered in the df "dtrend" below.

Any help is much appreciated. Thanks.

#cleanup
statedata <- read.csv(file = "statebondratingsmelted.csv", header = TRUE) 
head(statedata)
summary(statedata)

statedata <- subset(statedata, Year==2017)
statedata$Rank = as.numeric(levels(statedata$Rank))[statedata$Rank]
statedata$region <- tolower(statedata$region)
snames <- data.frame(region=tolower(state.name), long=state.center$x, lat=state.center$y)
snames <- merge(snames, statedata, by="region")
dtrend <- filter(mergestate, downwardtrendflag==1)
aaflag <- filter(mergestate, aa_flag==1)
us <- map_data("state")
mergestate <- merge(statedata, us, by="region")

library(ggplot2)
library(ggmap)

# Map Code
ggplot(color="black") +
    geom_map(data=us, map=us, aes(long, lat, map_id=region), fill="white", color = "#000000")+
    geom_map(data=dtrend, map=us, aes(fill="red", map_id=region), color ="#000000")+
    geom_map(data=aaflag, map=us, aes(fill="red", map_id=region), color ="#000000")+    
    geom_text(data=snames, aes(long, lat, label=Rating), size=3.0, color = "black")+
    coord_map() 

This is the current output:

Current Map

statedata <- structure(list(region = c("alabama", "alaska", "arizona", "arkansas", 
"california", "colorado", "connecticut", "delaware", "florida", 
"georgia", "hawaii", "idaho", "illinois", "indiana", "iowa", 
"kansas", "kentucky", "louisiana", "maine", "maryland", "massachusetts", 
"michigan", "minnesota", "mississippi", "missouri", "montana", 
"nebraska", "nevada", "new hampshire", "new jersey", "new mexico", 
"new york", "north carolina", "north dakota", "ohio", "oklahoma", 
"oregon", "pennsylvania", "rhode island", "south carolina", "south dakota", 
"tennessee", "texas", "utah", "vermont", "virginia", "washington", 
"west virginia", "wisconsin", "wyoming"), Year = c(2017L, 2017L, 
2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 
2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 
2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 
2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 
2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 2017L, 
2017L, 2017L, 2017L), Rating = structure(c(4L, 4L, 4L, 4L, 5L, 
4L, 5L, 7L, 7L, 7L, 6L, 6L, 9L, 7L, 7L, 5L, 3L, 4L, 4L, 7L, 6L, 
5L, 6L, 4L, 7L, 4L, 7L, 4L, 4L, 2L, 6L, 6L, 7L, 6L, 6L, 6L, 6L, 
5L, 4L, 6L, 7L, 7L, 7L, 7L, 6L, 7L, 6L, 5L, 4L, 6L), .Label = c("A", 
"A-", "A+", "AA", "AA-", "AA+", "AAA", "BBB", "BBB-", "N/A"), class = "factor"), 
    Rank = c(3, 3, 3, 3, 4, 3, 4, 1, 1, 1, 2, 2, 10, 1, 1, 4, 
    5, 3, 3, 1, 2, 4, 2, 3, 1, 3, 1, 3, 3, 7, 2, 2, 1, 2, 2, 
    2, 2, 4, 3, 2, 1, 1, 1, 1, 2, 1, 2, 4, 3, 2), downwardtrendflag = structure(c(1L, 
    2L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 2L, 1L, 1L, 2L, 
    1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 1L, 
    1L, 1L, 2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
    1L, 2L, 1L, 2L), .Label = c("0", "1", "FALSE"), class = "factor"), 
    aa_flag = c(0L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 
    1L, 0L, 0L, 1L, 1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 
    0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 
    0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L)), .Names = c("region", "Year", 
"Rating", "Rank", "downwardtrendflag", "aa_flag"), row.names = c(NA, 
50L), class = "data.frame")
Michael Harper
  • 14,721
  • 2
  • 60
  • 84
SharpSharpLes
  • 302
  • 4
  • 20
  • Please include all the code, including the all the datasets used. If the data has come from an external file you can easily turn it into an R object using `dput()`. https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example. – Michael Harper Nov 01 '17 at 00:58
  • I added the full code to the question. – SharpSharpLes Nov 01 '17 at 15:57
  • It would help having the `statedata` as well. See my suggestion about using `dput ()` to include this. – Michael Harper Nov 01 '17 at 15:59
  • Yup! just added to the question. Let me know if anything else would be useful. – SharpSharpLes Nov 01 '17 at 16:26
  • Hope my answer helps. Your ggplot code had quite a few formatting errors in, in particular, your use of the `aes()` commands. I would recommend you read more about it: http://ggplot2.tidyverse.org/index.html – Michael Harper Nov 01 '17 at 18:33
  • Thanks so much! Yeah, this was my first real dive into a ggplot graph... So, not surprising it was not formatted that well. I started to find some of them after I posted this. Where did you find the '\u2193' for the arrow? – SharpSharpLes Nov 01 '17 at 20:57
  • This is an example source for the arrows: https://www.w3schools.com/charsets/ref_utf_arrows.asp . Appreciate it if you can mark my answer as correct and upvote it if you found it useful: https://stackoverflow.com/help/someone-answers – Michael Harper Nov 01 '17 at 21:38

1 Answers1

1

The key part of the question is asking how to plot ticks. Symbols behave just like text within ggplot if you use the unicode for the symbol, and is answered previously here: Adding arrow symbols in ggplot text in R

Your problem was a bit more complex, as you wanted to plot the arrow in a different colour. This script, therefore, adds another layer to the plot for the arrows.

Your data had a column downwardtrendflag of either 1 or 0. I have used this to make a label for the data using the unicode "\u2193". I changed the way you subset the data as it was a bit confusing.

# Assign arrow to flagged states
library(plyr)
library(ggplot2)
library(ggmap)

us <- map_data("state")

# Format the data
statedata <- subset(statedata, Year==2017)
statedata$Rank = as.numeric(levels(statedata$Rank))[statedata$Rank]
statedata$region <- tolower(statedata$region)

snames <- data.frame(region=tolower(state.name), long=state.center$x, lat=state.center$y)
snames <- merge(snames, statedata, by="region")

# Find states which have either a downward trend or aa flag
highlight <- filter(mergestate, downwardtrendflag==1 | aa_flag==1)

# Create label for snames
snames$downwardtrendflag <- mapvalues(snames$downwardtrendflag, from = c(0,1), to = c("", '\u2193'))

To plot the arrow, I have had to make another geom layer as you want the colour to be red. I have used the argument nudge_x to offset the arrow.

# Map Code
ggplot(color="black") +
  geom_map(data=us, map=us, aes(long, lat, map_id=region), fill="white", color = "#000000") +
  geom_map(data=highlight, map=us, aes(map_id=region), fill="#F8766D", color ="#000000") +
  geom_text(data=snames, aes(long, lat, label=Rating), size=3.0, color = "black") +
  geom_text(data=snames, aes(long, lat, label=downwardtrendflag), size=3.0, color = "red", nudge_x = 2)+
  coord_map() +
  theme_nothing()

enter image description here

Visually, this map is not fantastic, as the two sets of labels conflict. You would be better off plotting the rating as a choropleth map and then overlaying the arrow on problematic states, like this:

# First we must order the levels in the factor
snames$Rating <- factor(snames$Rating, levels = rev(c("BBB-", "A-","A+","AA-","AA","AA+" ,"AAA")))

# Map Code
ggplot(color="black") +
  geom_map(data=snames, map=us, aes(map_id=region, fill = Rating), color = "#000000") +
  geom_map(data=highlight, map=us, aes(map_id=region), fill="#F8766D", color ="#000000") +
  geom_text(data=snames, aes(long, lat, label=downwardtrendlabel), size=3.0, color = "red")+
  scale_fill_brewer(palette = "Reds") +
  coord_map(ylim = c(25, 50)) + 
  labs(title = " US States Debt Rating", subtitle = " Arrows highlights states which have a dowward trend", caption = "Source: Add source of data") +
  theme_nothing(legend = TRUE)

enter image description here

Michael Harper
  • 14,721
  • 2
  • 60
  • 84