Scatterplot of 1st Gen Pokemon Attributes

From Lab 3

Published

April 22, 2026

Between first-generation bug, fighting, and psychic Pokemon, which type typically has the highest special attack and defense? Is there a linear relationship between special attack and defense?

Code
# Create a scatterplot
pkmn_plot <- pkmn_3 |> 
  ggplot(aes(
    x = special_attack,
    y = special_defense,
    
    # Properly map shape, color, and fill to `type_1`
    shape = type_1,
    color = type_1,
    fill = type_1
  )) +
  
  # Increase the point size and outline shapes in black
  geom_point(
    color = "black",
    size = 3
  ) +
  
  # Add lines of best fit and group by `type_1`
  geom_smooth(
    aes(group = type_1),
    se = F,
    method = "lm",
    show.legend = F
  ) +
  
  # Pick "fillable" shapes and change to a better color palette
  scale_shape_manual(
    values = c(21,22,24)
  ) +
  scale_fill_manual(
    values = wes_palette("Darjeeling1")
  ) +
  scale_color_manual(
    values = wes_palette("Darjeeling1")
  ) +
  
  # Set a theme that has a white background
  theme_minimal() +
  
  # Update titles and labels
  labs(
    title = "Special Attack and Defense Attributes of 1st Generation\nBug, Fighting, and Psychic Pokemon",
    x = "Special Attack",
    y = "Special Defense",
    fill = "Type",
    shape = "Type"
  )

pkmn_plot

In part, my motivation for looking at these three types and these particular attributes stems from my recollection that psychic types have unusually good special stats, while fighting types are weak against psychic types and therefore especially susceptible to special attacks. I’m including bug types as a sort of baseline comparison, since they’re generally one of the weaker types. Hopefully, this plot will tell us something about the balance of these types and let us know if picking fighting types is ever worth it when facing a psychic type opponent.

Data

The above scatterplot was created using the Pokemon data set hosted through TidyTuesday, which provides descriptive information about 949 uniquely identifiable Pokemon. For the purposes of the present figure, these data have been filtered to include only 1st generation Pokemon (i.e., the original 151).

Audience

The concept behind this plot is rather informal and playful, and it is intended for a general audience interested in Pokemon cards, video games, etc. It is not expected that the viewership has any special familiarity with reading graphs, but there is a clear expectation that the audience is familiar with Pokemon.

Graph Type

The above figure shows a categorical scatterplot. Two continuous axes allow for the plotting of points on a Cartesian plane, which allows us to see relationships between the two variables represented by the x- and y-axes. In this case, points on the plane are grouped according to some common attribute (e.g., Pokemon type), and can be differentiated from other groups using different colors and/or shapes (in this case, we see that both aesthetics are varied).

Representation Description

Bug, fighting, and psychic type Pokemon are represented by circles, squares, and triangles, and by pinkish red, blue-green, and yellow colors, respectively. The x-axis shows base special attack statistic; the y-axis is an index of special defense. Linear lines of best fit are drawn through each of the three type groups.

Bug and fighting Pokemon tend to have lower special attack stats, but are both capable of having considerable special defense. Of these two, there does seem to be a positive linear relationship between special attack and defense for bug types, but not fighting types, surprisingly. Finally, we can see that psychic Pokemon tend to have both high special attack and defense, though there’s not much of a linear relationship between these attributes. Going back to look at the raw data, we see that Drowzee was the psychic type with the lowest special attack.

Based on this figure, it doesn’t seem like we’d want to use a fighting type Pokemon to go up against a psychic type! Not only are fighting types weak against psychic types to begin with, but fighting types seem to have lower special defense while psychic types have higher special attack.

Tips for Interpretation

Look for clustering (or lack thereof) between the different categories of points. Does one group fall visibly below or above the other groups along one or both of the axes? Now, look for linear trends (i.e., can you draw a straight line through any of the groups and get close to most of the points?). If so, what is the slope of the line like? Does it increase as you move left-to-right? Does it decrease? Maybe it stays flat?

Presentation Considerations

Both color and shape aesthetics were mapped to Pokemon type, to maximize discernibility of the groups. Specifically, circles, squares, and triangles were chosen, since they are easy to distinguish from one another. For color, wesanderson::wes_palette() was used with Darjeeling1, since the first three colors in this palette were very distinct, assuming normal color vision. Also for the purposes of color, a white background was used to increase contrast.

To see how our plot holds up for colorblind viewers, we can use cvd_grid():

Code
# Preview different colorblind appearances
cvd_grid(pkmn_plot)

It doesn’t look too bad, especially for tritanomaly. \(\checkmark\)

Method

To make this figure, load the pokemon data frame, filter out all Pokemon except those of the original 151. Then, filter by primary type (type_1) and select bug, fighting, and psychic types. Luckily, this data set is very clean as-is when you load it, so there is very little wrangling needed in preparation for plotting.

Code
# Filter down to only gen 1 Pokemon
pokemon_df <- pokemon_df |> 
  filter(generation_id == 1)

# Reduce to just the three types of interest
pkmn_3 <- pokemon_df |> 
  filter(
    type_1 %in% c("bug","fighting","psychic")
  )

After completing the necessary filtering steps, you can use geom_point() and geom_smooth() to create the scatterplot and fit lines. Remember, you’ll need to map the fill and color aesthetics to type_1.

Code
# Create a scatterplot
pkmn_plot <- pkmn_3 |> 
  ggplot(aes(
    x = special_attack,
    y = special_defense,
    
    # Properly map shape, color, and fill to `type_1`
    shape = type_1,
    color = type_1,
    fill = type_1
  )) +
  
  # Increase the point size and outline shapes in black
  geom_point(
    color = "black",
    size = 3
  ) +
  
  # Add lines of best fit and group by `type_1`
  geom_smooth(
    aes(group = type_1),
    se = F,
    method = "lm",
    show.legend = F
  ) +
  
  # Pick "fillable" shapes and change to a better color palette
  scale_shape_manual(
    values = c(21,22,24)
  ) +
  scale_fill_manual(
    values = wes_palette("Darjeeling1")
  ) +
  scale_color_manual(
    values = wes_palette("Darjeeling1")
  ) +
  
  # Set a theme that has a white background
  theme_minimal()