2

I need to manually specify the limits of both the x and y axes for each facet (3 rows and 3 columns) in a facet_grid.

I have 2 categorical factors and a continuous y value (so I'm plotting the catch_ema_thousands on the y axis, with data faceted by redlistCategory (3 levels) and TaxonGroup (3 levels), then coloring the points according to VARIABLE (also 3 levels).

The facet_grid has very uneven numbers of data points and range of y values (0 - 1,700, with most points clustered around 0, and some facets with 20 points and others with 0 or 1).

I have scale_y_sqrt to transform the y axis, which helps, but it's still too hard to see the dots in the busy facets.

I've used the scales = "free" and space="free" arguments in facet_grid(), which adjusts the facet sizes to fit to the data points, but doesn't account for fitting the geom_text_repel() labels.

Do I have to adjust the facet sizes within ggrepel?

library(scales)
library(ggrepel)
library(forcats)
library(RColorBrewer)
library(tidyverse)

ylimits <- c(2,NA) #keep the labels above the cluster of points at the bottom of the facets

List of ~25 species I want to label:

special.points <- special.points <- rownames(subset(plotdat, 
                         SpeciesOrTaxon %in% c("Gadus morhua","Melanogrammus aeglefinus","Thunnus obesus",
                                            "Trachurus trachurus","Sardinella maderensis","Thunnus thynnus",
                                            "Thunnus maccoyii","Hippoglossus hippoglossus","Squalus acanthias",
                                            "Merluccius senegalensis","Epinephelus striatus","Apostichopus japonicus",
                                            "Mobula mobular","Isurus oxyrinchus","Mustelus schmitti",
                                            "Pseudotolithus senegalensis","Sebastolobus alascanus",
                                            "Leucoraja circularis","Argyrosomus hololepidotus","Raja undulata",
                                            "Isurus paucus","Sphyrna lewini","Squatina argentina","Dipturus batis",
                                            "Squatina squatina","Carcharhinus falciformis","Squalus acanthias",
                                            "Makaira nigricans","Thunnus orientalis","Carcharhinus longimanus",
                                            "Lamna nasus","Sphyrna zygaena","Alopias vulpinus","Cetorhinus maximus",
                                            "Alopias superciliosus","Carcharodon carcharias","Palinurus elephas"))) 

My really annoying plot:

p <- ggplot(data = plotdat, aes(x= -totRank, y = catch_ema_thousands, label = Name_abbrev)) + 
  geom_point(data=plotdat,aes(color = VARIABLE), size = 1.2, shape = 1, stroke = 0.8) +
  scale_color_manual(values=c("black","orange","darkgrey"), labels = c("CITES","Intl trade","No intl trade")) +
  facet_grid(redlistCategory~TaxonGroup, scales = "free", space = "free") + 
  scale_y_sqrt() +
  geom_text_repel(data = plotdat, 
                  aes(x=-totRank, y = catch_ema_thousands, label = Name_abbrev), 
# used the abbreviated species name to try and fit them better
                  segment.color = "black", segment.size = 0.2, segment.alpha = 0.5, 
                  direction = "both",
                  min.segment.length = 0.5,
                  force = 10, size = 2, color = "black",
                  ylim = ylimits) + 
  ylab("Average catch (thousand tonnes)") +
  theme(axis.text.x = element_blank(),
        axis.ticks.x=element_blank(),
        axis.title.x=element_blank(),
        axis.title.y = element_blank(),
        legend.position = "top", 
        legend.title = element_blank(),
        panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        panel.background = element_blank(), axis.line = element_line(colour = "black")) 
#dev.off() 

I tried a new package, , but got an error:

devtools::install_github("zeehio/facetscales")
library(facetscales)
scales_y <- list(
  CR = scale_y_sqrt(limits = c(0,50), breaks = c(0,50,10)),
  EN = scale_y_continuous(limits = c(0,50), breaks = c(0,50,10)),
  VU = scale_y_continuous(labels = scientific_format())
)

scales_x <- list(
  'Invertebrates' = scale_x_discrete(limits = c(-50,-40)), # plotting in reverse rank (-59 to 0)
  'Cartilaginous fish' =  scale_x_discrete(limits = c(-59,0)),
  'Bony fish' =  scale_x_discrete(limits = c(-59,0))
)

Then,

facet_grid(redlistCategory~TaxonGroup, scales = list(y=scales_y, x = scales_x))

Something isn't right with overriding the "free" scales in facet_grid(), I get this error:

Error in match.arg(scales, c("fixed", "free_x", "free_y",
 "free")) :    'arg' must be NULL or a character vector

Sample plot data:

plotdat <- dput(structure(list(SpeciesOrTaxon = c("Squatina argentina", "Dipturus batis", 
"Squatina squatina", "Thunnus maccoyii", "Epinephelus striatus", 
"Sphyrna lewini", "Mobula mobular", "Isurus oxyrinchus", "Mustelus schmitti", 
"Pseudotolithus senegalensis", "Sebastolobus alascanus", "Leucoraja circularis", 
"Argyrosomus hololepidotus", "Raja undulata", "Isurus paucus", 
"Thunnus thynnus", "Hippoglossus hippoglossus", "Merluccius senegalensis", 
"Apostichopus japonicus", "Carcharhinus falciformis", "Carcharhinus longimanus", 
"Lamna nasus", "Sphyrna zygaena", "Alopias vulpinus", "Cetorhinus maximus", 
"Alopias superciliosus", "Carcharodon carcharias", "Sardinella maderensis", 
"Galeorhinus galeus", "Pomatomus saltatrix", "Pentanemus quinquarius", 
"Pseudupeneus prayensis", "Nemipterus virgatus", "Pseudotolithus senegallus", 
"Dalatias licha", "Lutjanus campechanus", "Megalops atlanticus", 
"Mola mola", "Mustelus mustelus", "Centrophorus squamosus", "Balistes capriscus", 
"Centrophorus lusitanicus", "Leucoraja fullonica", "Rhomboplites aurorubens", 
"Dentex dentex", "Epinephelus marginatus", "Palinurus elephas", 
"Alosa immaculata", "Carcharhinus plumbeus", "Oxynotus centrina", 
"Gymnura altavela", "Carcharias taurus", "Gadus morhua", "Melanogrammus aeglefinus", 
"Thunnus obesus", "Trachurus trachurus", "Squalus acanthias", 
"Makaira nigricans", "Thunnus orientalis"), Name_abbrev = c("S. argentina", 
"D. batis", "S. squatina", "T. maccoyii", "E. striatus", "S. lewini", 
"M. mobular", "I. oxyrinchus", "M. schmitti", "P. senegalensis", 
"S. alascanus", "L. circularis", "A. hololepidotus", "R. undulata", 
"I. paucus", "T. thynnus", "H. hippoglossus", "M. senegalensis", 
"A. japonicus", "C. falciformis", "C. longimanus", "L. nasus", 
"S. zygaena", "A. vulpinus", "C. maximus", "A. superciliosus", 
"C.carcharias", "S. maderensis", "G. galeus", "P. saltatrix", 
"P. quinquarius", "P. prayensis", "N. virgatus", "P. senegallus", 
"D. licha", "L. campechanus", "M. atlanticus", "M. mola", "M. mustelus", 
"C. squamosus", "B. capriscus", "C. lusitanicus", "L. fullonica", 
"R. aurorubens", "D. dentex", "E. marginatus", "P. elephas", 
"A. immaculata", "C. plumbeus", "O. centrina", "G. altavela", 
"C. taurus", "G. morhua", "M. aeglefinus", "T. obesus", "T. trachurus", 
"S. acanthias", "M. nigricans", "T. orientalis"), redlistCategory = structure(c(1L, 
1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("CR", "EN", 
"VU"), class = "factor"), TaxonGroup = structure(c(2L, 2L, 2L, 
3L, 3L, 2L, 2L, 2L, 2L, 3L, 3L, 2L, 3L, 2L, 2L, 3L, 3L, 3L, 1L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 2L, 3L, 3L, 3L, 3L, 3L, 2L, 
3L, 3L, 3L, 2L, 2L, 3L, 2L, 2L, 3L, 3L, 3L, 1L, 3L, 2L, 2L, 2L, 
2L, 3L, 3L, 3L, 3L, 2L, 3L, 3L), .Label = c("Invertebrates", 
"Cartilaginous fish", "Bony fish"), class = "factor"), totRank = c(12, 
39, 55, 7, 38, 56, 57, 8, 11, 17, 33, 36, 37, 50, 58, 6, 9, 16, 
51, 15, 27, 30, 43, 45, 49, 52, 53, 5, 13, 14, 19, 20, 22, 23, 
24, 25, 26, 28, 29, 31, 32, 34, 35, 40, 41, 42, 44, 46, 47, 48, 
54, 59, 1, 2, 3, 4, 10, 18, 21), VARIABLE = structure(c(3L, 3L, 
3L, 2L, 2L, 1L, 1L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 2L, 2L, 2L, 
2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
3L, 3L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("CITES", "YES", 
"NO"), class = "factor"), catch_ema_thousands = c(3.886654422, 
0.1724791016, 0.00911430205, 10.54412869, 0.174470439, 0.00807692997, 
0.001640665002, 9.424452066, 6.583041893, 2.659608617, 0.2663195953, 
0.2329239555, 0.2219422872, 0.01671489332, 0.0014159872, 13.44830652, 
7.585155675, 2.774650025, 0.01599999, 3.024126379, 0.4539170316, 
0.3113769576, 0.1163730191, 0.1011488649, 0.01681304105, 0.01561369792, 
0.01416268544, 108.778465, 3.822553738, 3.251341729, 2.440669803, 
1.688880545, 1.358903072, 1.100693581, 1.06694699, 0.8025907339, 
0.5465603847, 0.4392502858, 0.3591757093, 0.2919081194, 0.2671983104, 
0.2478545144, 0.2435067011, 0.15794176, 0.1539382418, 0.1226202735, 
0.1079683714, 0.06792588753, 0.03801280875, 0.02357907878, 0.009323075655, 
0.000514006594, 1652.737638, 484.1897672, 397.4311939, 153.0306153, 
7.422144444, 2.459107988, 1.545317165)), row.names = c(NA, -59L
), class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame")))
M--
  • 25,431
  • 8
  • 61
  • 93
leslie roberson
  • 167
  • 1
  • 15
  • 1
    https://stackoverflow.com/questions/18046051/setting-individual-axis-limits-with-facet-wrap-and-scales-free-in-ggplot2 – M-- Jun 02 '19 at 03:12
  • True, sorry about that. The link you posted is not the same question, and doesn't solve my problem, as it's adjusting just 1 y-axis, so coord_cartesian() works. Doesn't work in my case, where I need different y limits and different x limits for the facet rows and columns. – leslie roberson Jun 02 '19 at 11:07
  • Ohh @M-M I see what you meant, there were multiple answers in that link. I made it work with creating a dummy data set with the x and y limits I wanted for each panel, and adding it to the plot with geom_point() + geom_blank(data=dummydata, ...) + facet_grid(..., scales = "free", space="free"). Tedious with so many facets, but it worked! – leslie roberson Jun 02 '19 at 12:08
  • It would be great if you could post your solution for users coming across a similar problem. Thanks. – M-- Jun 02 '19 at 20:15

2 Answers2

0

Edit: adding alternative using scale_y_sqrt(expand = expand_scale) to make more border room within each facet.

If the sqrt transformation makes more sense here, you might consider making more room for labels automatically by using expand_scale. The default in ggplot is to add 5% beyond the range of your data, but increasing this will create more space for labels on all facets.

It might also be worth tweaking or removing the the ylim = ylimits part, since that created some overlapping bunched labels when I first opened the example.

scale_y_sqrt(expand = expand_scale(0.2)) +
geom_text_repel(data = plotdat, 
                aes(x=-totRank, y = catch_ema_thousands, label = Name_abbrev), 
                # used the abbreviated species name to try and fit them better
                segment.color = "black", segment.size = 0.2, segment.alpha = 0.5, 
                direction = "both", nudge_y = 0,
                min.segment.length = 0.5, max.iter = 5000,
                force = 10, size = 2, color = "black") + # w/o ylim part

enter image description here


First answer:

I think log10 might be an appropriate scaling option here, given the wide range of magnitudes:

p <- ggplot(data = plotdat, aes(x= -totRank, y = catch_ema_thousands, label = Name_abbrev)) + 
  geom_point(data=plotdat,aes(color = VARIABLE), size = 1.2, shape = 1, stroke = 0.8) +
  scale_color_manual(values=c("black","orange","darkgrey"), labels = c("CITES","Intl trade","No intl trade")) +
  facet_grid(redlistCategory~TaxonGroup, scales = "free", space = "free") + 
    scale_y_log10(
      breaks = 10^(-10:10),
      labels = scales::trans_format("log10", scales::math_format(10^.x))
    ) +
    # annotation_logticks(side = "l") +

  geom_text_repel(data = plotdat, 
                  aes(x=-totRank, y = catch_ema_thousands, label = Name_abbrev), 
                  # used the abbreviated species name to try and fit them better
                  segment.color = "black", segment.size = 0.2, segment.alpha = 0.5, 
                  direction = "both", nudge_y = 0,
                  min.segment.length = 0.5, max.iter = 5000,
                  force = 10, size = 2, color = "black") + #, ylim = ylimits) + 
  ylab("Average catch (thousand tonnes)") +
  theme(axis.text.x = element_blank(),
        axis.ticks.x=element_blank(),
        axis.title.x=element_blank(),
        axis.title.y = element_blank(),
        legend.position = "top", 
        legend.title = element_blank(),
        panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        panel.background = element_blank(), axis.line = element_line(colour = "black")) 

  p

enter image description here

Jon Spring
  • 55,165
  • 4
  • 35
  • 53
  • Thanks for the solution, it doesn't really answer my question though. I agree the log scale looks better but in this case it's quite important that the y value be comprehensible as a value, which is why I went with the sqrt transformed axis (and instead of transforming the numbers themselves). And I'd still like to figure out how to set the scales for each facet individually when labeling with ggrepel because it seems like it should be possible. – leslie roberson Jun 02 '19 at 09:12
0
blank_data <- read_csv("blankdata.csv")  
# must have all the columns that you call in ggplot. 
# Make a row for the minimum and maximum x and y values you want for each facet
p <- ggplot(data = plotdat, aes(x= xvar, y = yvar, label = labelvar)) + 
  geom_jitter(data=plotdat,
              aes(color = colorvar), size = 1.2, shape = 1, stroke = 0.8, width = 
                0.25, height = 0.25) +
  geom_blank(data=blankdata, aes(x =xvar, y = yvar, label = labelvar)) +
  facet_grid(ycategory ~ xcategory, scales = "free", space = "free") + 
  geom_text_repel(data = labelvar, # can subset and only label certain points
                  aes(x=xvar, y = yvar, label = labelvar),
                  segment.color = "black", segment.size = 0.2, segment.alpha = 
                    0.5, 
                  direction = "both", 
                  min.segment.length = 0.5,
                  force = 10, size = 2, color = "black") +
  scale_y_sqrt(expand = expand_scale(mult=c(0.1,0))) + 
  # added extra space (10%) at the bottom of each axis because all the labels were clustered there 
  scale_x_continuous(expand = expand_scale(mult=c(0.1,0.1))) +
  theme_bw()
leslie roberson
  • 167
  • 1
  • 15
  • I created a dummy data set with the x and y limits I wanted for each panel, and added it to the plot with geom_point() + geom_blank(data=dummydata, ...) + facet_grid(..., scales = "free", space="free"). The dummy data can be tedious if you have many facets, I made it manually and imported as a csv, but you could of course do that part in R. – leslie roberson Jun 05 '19 at 01:58
  • helpful geom_blank example, with fewer facets so more straightforward blankdata: https://chrischizinski.github.io/rstats/using_geom_blank/ – leslie roberson Jun 05 '19 at 01:59