Analyzing President Trump's Approval Rating and the 2018 Generic Ballot

This question, however simple, carries long-reaching implications for America’s future. Trump’s political and moral standing come 2020 will likely define the path of the presidential election, which seems to contend either continued darkening of American politics or a great reversal of the current political environment.

As they have done for the many presidents before him, and will do for the many after him, pollsters have taken the nation’s political temperature constantly throughout the Trump administration. Luckily for us, the Huffington Post has an API which allows us to query all of these polls in aggregate and interrogate the results for specific questions.

To build the graphics below, I assembled all of the historical results for the question “Do you approve or disapprove of the way Donald Trump is handling his job as President?”


Trump Approval - Adults

Trump Approval - Voters

Trump Approval - Partisan

Quick Takeaways

  • It is fascinating to see America’s partisan divide crystallized in the chart broken apart by political party - Republicans and Democrats hold almost diametricly opposed views of President Trump… really shows the polarization of the electorate
  • I was suprised to see that a majority of likely and registered voters held favorable opinions of Donald Trump at the time of his inauguration given that he did not obtain a majority of the popular vote in the election
  • I was not shocked to see his popularity “bottom out” in the fall of 2017, where Trump dealt with fallout from his comments in Charlottesville, response to the hurricane in Puerto Rico, and shooting in Las Vegas

Midterm Election Generic Ballot

In addition to examining the President’s approval rating, I also took a look at the Generic Congressional Ballot. This poll is designed to measure nation-wide sentiment by party without focusing on specific candidates. I figured this might give a decent preview for how things are shaping up in advance of the 2018 midterm elections for the House of Representatives this fall.

Take a look at how things have been trending below!

House Generic Ballot

Notable Code Snippets

Melt the Poll Data

This converts “wide” data into “long” data so that each of the variables below falls under one column, “variable”. With this in place, we can treat each variable as a factor and use them to colorize our graphs.

# Melt data where variable is approval, disapprove, or undecided
trump.m <- melt(trump, measure.vars = c("Approve", "Disapprove", "Undecided"))

# Melt data where variable is political party
house.m <- melt(house, measure.vars = c("Democrat", "Republican", "Undecided", "Other"))

Create a Common Plot Theme

I applied this plot_theme to each ggplot2 chart that I created to maintain a consistent aesthetic.

# Create theme elements
plot_theme <- theme(
  axis.text.x = element_text(
    angle = 45,
    hjust = 1,
    vjust = 1
  plot.title = element_text(size = 16, face = "bold"),
  plot.subtitle = element_text(size = 12),
  plot.caption = element_text(size = 8, color = "dark grey"),
  # Color the background of the facets
  strip.background = element_rect(fill = "gray92", color = "white"),
  legend.key = element_rect(fill = "white", color = "white"),
  # Set a common color for the plot background
  panel.background = element_rect(fill = "grey97", color = "white")

Save Plots

I used ggsave() to output the charts you see in this post.

  width = 6,
  height = 4,
  unit = "in"

Replace Facet Labels

I noted that the poll data includes the word “independent” with a lower case “i” and wasn’t having it… so I used the following factor list and labeller function to replace the text. Make sure to call the labeller function in your facet_wrap() function.

# Create a factor list to re-map parties
parties <- list(
  'Adults - Democrat' = "Democrats",
  'Adults - independent' = "Independents",
  'Adults - Republican' = "Republicans"

# Create a labeller function for the parties
party_labeller <- function(variable, value) {

Create a Faceted Plot

I wanted to break apart the poll data by the self-reported political leanings of the respondents, but noticed that keeping all the data in one chart was too chaotic. To cleanly delineate between political parties, I used facet_wrap to create an independent facet (with all the same axes and appearance) for respondents from each party.

# Facet Trump Approval by party affiliation
trump_approval_partisan <-
      sample_subpopulation == "Adults - Democrat" |
        sample_subpopulation == "Adults - Republican" |
        sample_subpopulation == "Adults - independent"
    aes(x = end_date, y = value, color = variable)
  ) +
  # Control the transparency of the chart
  geom_jitter(alpha = 0.3) +
    title = "Donald Trump's Approval Rating",
    subtitle = "Favorability varies dramatically depending on party affiliation",
    caption = "Data from HuffPost Pollster API",
    x = "Poll Date",
    y = "Percentage of Respondents"
  ) +
  # Format the date labels as "Mon - YYYY"
  scale_x_date(date_breaks = "2 months", date_labels = "%b-%Y") +
  # Create a line of best fit but hide the colored-in standard error region
  geom_smooth(se = FALSE) +
  theme_minimal() +
  scale_color_brewer(palette = "Dark2") +
  scale_y_continuous(breaks = seq(0, 100, by = 5)) +
  plot_theme +
  # Rename the legend title
  guides(color = guide_legend(title = "Poll Response")) +
  # Create facets and apply the labeller to change the facet names
  facet_wrap( ~ sample_subpopulation, labeller = party_labeller)