2

I was recently attempting to plot some filled points with an additional white border around the standard black border. I was unable to find a posted solution that did not rely on custom point shapes but still plotted all components of each point together.

After far too much time, I came up with the following solution. This solution works by duplicating each point and plotting a slightly larger white point behind it. This is similar to the solutions listed here (R ggplot2: How to draw geom_points that have a solid color and a transparent stroke and are colored depending on color?). However, my solution allows both borders to overlap adjacent points rather than plotting one set of borders behind the other.

Reproducible Example:

## Create test dataframe from built in mpg data frame and add scatter

test_mpg = mpg
test_mpg$displ = test_mpg$displ + runif(length(test_mpg$displ), min = 0, max = 0.5) # Add random values between 0 and 0.5 to test_mpg$displ
test_mpg$cty = test_mpg$cty + runif(length(test_mpg$displ), min = 0, max = 5) # Add random values between 0 and 5 to test_mpg$cty

### Add second border color

## Step 1: Create new dataset with duplicate rows.

rowind = seq(1,nrow(test_mpg)) # Create array of row indices
rowind2 = rep(rowind, each = 2, times = 1) # Create new array with doubled row indices (i.e. 1,2,3 becomes 1,1,2,2,3,3)

newdata = test_mpg[rowind2,] # Create new dataset with doubled rows
newdata$odd_row = seq_len(nrow(newdata)) %% 2 # Create column indicating even and odd rows. Odd rows = 1 and even rows = 0

## Step 2: Create columns with alternating aesthetics

# Create point size aesthetic column with alternating values

newdata$pointsize = NA # Create new column
newdata[newdata$odd_row == 1,]$pointsize = 2.0 # Set odd numbered rows to the desired outer point size. This is plotted behind the main point and determines the amount of secondary border visible.
newdata[newdata$odd_row == 0,]$pointsize = 1.5 # Set even numbered rows to the desired main point size

# Create point color aesthetic column with alternating values

newdata$pointcolor = NA # Create new column
newdata[newdata$odd_row == 1,]$pointcolor = "white" # Set odd numbered rows to the desired outer border color.
newdata[newdata$odd_row == 0,]$pointcolor = "black" # Set even numbered rows to the desired main point border color

## Step 3: Plot your data

# Plot your data with point size set to newdata$pointsize and point color set to newdata$pointcolor. These should be set outside of the aes()

test = ggplot(newdata, aes(displ, cty,  fill = drv, shape = drv)) +
  scale_fill_manual(values=c("green","blue","yellow")) +
  scale_shape_manual(values= c(23, 24, 25)) +
  geom_point(alpha = 1, size = newdata$pointsize, stroke = 0.75, color = newdata$pointcolor) +
  theme_bw()

test

Plot from above code

ikeebrown
  • 56
  • 2

1 Answers1

0

I am not at all sure that his is what you want, but the borders do not overlap.
The code below calls geom_point twice, what the question you link to tries to avoid.

suppressPackageStartupMessages({
  library(ggplot2)
  library(dplyr)
})

set.seed(2022)

mpg %>%
  mutate(displ = displ + runif(length(displ), min = 0, max = 0.5),
         cty = cty + runif(length(displ), min = 0, max = 5)) %>%
  ggplot(aes(displ, cty,  fill = drv, shape = drv)) +
  geom_point(size = 2, color = "white", fill = "white") +
  geom_point(size = 1.5, color = "black", stroke = 0.75) +
  scale_fill_manual(values = c("green", "blue", "yellow")) +
  scale_shape_manual(values = c(23, 24, 25)) +
  theme_bw()

Created on 2022-06-19 by the reprex package (v2.0.1)

Rui Barradas
  • 70,273
  • 8
  • 34
  • 66
  • Hello Rui, thank you very much for your answer. I am afraid I did not explain myself very clearly. I was attempting to plot the outer white border with the regular border rather than plotting the white and black border points as separate layers. If you plot them as separate layers, the outer white border ends up being covered by the second layer when points overlap. The solution I posted works to avoid this problem, although it is a bit overly complicated. Thanks again! – ikeebrown Jun 19 '22 at 19:51