Search code examples
rimageggplot2gridextracowplot

How can I plot an image directly above a ggplot aligned with the graph below?


I am trying to insert an image at the top of an already existing ggplot object. Below is an example of my end goal, created using an image processor.

enter image description here

...and here is some code that replicates the ggplot side of the arrangement.

library(tidyverse)

proportion<-data.frame(group=c(rep("A",10),
                  rep("B",10),
                  rep("C",10)),
           num=c(rnorm(20,mean=0.45,sd=0.05),
                rnorm(20,mean=0.55,sd=0.05),
                rnorm(20,mean=0.5,sd=0.05)))

proportion %>%
  ggplot(aes(x=num,y=group)) +
  geom_boxplot(width=0.5)+
  coord_cartesian(xlim=c(0,1))+
  labs(x="measurement (as percent of total length)",y="group")+
  geom_vline(xintercept=c(0,1))

The graph is supposed to represent the location of something on a fish's body as a percentage of body length and placing a silhouette immediately above the y-axis gives readers a more intuitive idea of what the graph is measuring. The xmin and xmax of the silhouette need to be aligned with c(0,1) on the x-axis of the graph in order to get the comparison across.

This data is supposed to be for a data report in an RMarkdown file knitted to .html, so it is not possible to simply export the ggplot from R and editing it in an image processor. I am having trouble figuring out the best way to achieve this in R. I have tried using the cowplot and magick packages, but have found it is difficult to place an image on the graph if the y-axis is a discrete variable. I think this might be achievable through the use of gridExtra and calling an additional viewport, but I do not know how to get the image to properly line up with the graph below. Does anyone know how this can be achieved?


Solution

  • A sure fire way to do this is load your fish shape into a raster, convert to polygons, then normalise the co-ordinates so that they reach exactly between 0 and 1 on the x axis. You can then plot the fish as a polygon in ggplot and stitch the two plots together with patchwork - this will automatically align the fish and proportions. A patchwork plot will work nicely with R Markdown too.

    library(ggplot2)
    library(patchwork)
    
    p1 <- ggplot(fish, aes(X, Y)) +
      geom_polygon(fill = "steelblue", alpha = 0.5) +
      geom_vline(xintercept = c(0, 1)) +
      scale_x_continuous(expand = c(0, 0)) +
      theme_void()
    
    p2 <- proportion %>%
      ggplot(aes(x = num,y = group)) +
      geom_boxplot(width = 0.5, fill = "lightblue", alpha = 0.5) +
      coord_cartesian(xlim = c(0, 1)) +
      scale_x_continuous(expand = c(0, 0)) +
      labs(x = "measurement (as percent of total length)", y = "group") +
      geom_vline(xintercept = c(0, 1)) +
      theme_classic(base_size = 16) +
      theme(axis.line.y = element_blank())
    
    p1 / p2 + plot_layout(heights = 1:2) & theme(plot.margin = margin(0, 20, 0, 0))
    

    enter image description here


    Fish shape as xy co-ordinates

    fish <- structure(list(X = c(286, 289, 289, 290, 290, 291, 291, 290, 
    290, 291, 291, 295, 295, 297, 297, 298, 298, 299, 299, 300, 300, 
    301, 301, 302, 302, 303, 303, 304, 304, 305, 305, 306, 306, 307, 
    307, 308, 308, 309, 309, 310, 310, 311, 311, 312, 312, 313, 313, 
    312, 312, 313, 313, 316, 316, 318, 318, 319, 319, 320, 320, 321, 
    321, 322, 322, 323, 323, 324, 324, 325, 325, 327, 327, 328, 328, 
    329, 329, 330, 330, 331, 331, 332, 332, 333, 333, 334, 334, 335, 
    335, 336, 336, 335, 335, 333, 333, 330, 330, 326, 326, 323, 323, 
    320, 320, 316, 316, 322, 322, 328, 328, 335, 335, 340, 340, 347, 
    347, 353, 353, 359, 359, 366, 366, 372, 372, 379, 379, 387, 387, 
    393, 393, 402, 402, 409, 409, 417, 417, 421, 421, 427, 427, 432, 
    432, 436, 436, 440, 440, 444, 444, 450, 450, 452, 452, 456, 456, 
    458, 458, 459, 459, 460, 460, 461, 461, 462, 462, 461, 461, 460, 
    460, 459, 459, 457, 457, 454, 454, 451, 451, 453, 453, 481, 481, 
    488, 488, 492, 492, 494, 494, 497, 497, 498, 498, 500, 500, 501, 
    501, 503, 503, 505, 505, 506, 506, 508, 508, 509, 509, 510, 510, 
    512, 512, 514, 514, 516, 516, 518, 518, 520, 520, 521, 521, 523, 
    523, 525, 525, 528, 528, 530, 530, 532, 532, 534, 534, 536, 536, 
    539, 539, 541, 541, 544, 544, 546, 546, 549, 549, 552, 552, 555, 
    555, 558, 558, 574, 574, 575, 575, 574, 574, 575, 575, 576, 576, 
    575, 575, 576, 576, 575, 575, 574, 574, 575, 575, 574, 574, 573, 
    573, 572, 572, 571, 571, 570, 570, 569, 569, 568, 568, 567, 567, 
    568, 568, 569, 569, 570, 570, 571, 571, 572, 572, 573, 573, 574, 
    574, 575, 575, 576, 576, 577, 577, 578, 578, 579, 579, 580, 580, 
    581, 581, 576, 576, 571, 571, 566, 566, 555, 555, 550, 550, 545, 
    545, 541, 541, 537, 537, 534, 534, 530, 530, 527, 527, 524, 524, 
    521, 521, 519, 519, 516, 516, 513, 513, 510, 510, 508, 508, 505, 
    505, 502, 502, 498, 498, 495, 495, 491, 491, 486, 486, 481, 481, 
    465, 465, 457, 457, 451, 451, 446, 446, 442, 442, 443, 443, 446, 
    446, 454, 454, 456, 456, 457, 457, 456, 456, 455, 455, 454, 454, 
    453, 453, 452, 452, 451, 451, 450, 450, 449, 449, 448, 448, 447, 
    447, 446, 446, 443, 443, 439, 439, 437, 437, 434, 434, 432, 432, 
    430, 430, 428, 428, 425, 425, 423, 423, 421, 421, 419, 419, 417, 
    417, 415, 415, 413, 413, 411, 411, 409, 409, 407, 407, 405, 405, 
    403, 403, 401, 401, 400, 400, 398, 398, 396, 396, 394, 394, 392, 
    392, 391, 391, 389, 389, 387, 387, 386, 386, 384, 384, 382, 382, 
    381, 381, 379, 379, 377, 377, 373, 373, 348, 348, 340, 340, 329, 
    329, 322, 322, 315, 315, 309, 309, 304, 304, 302, 302, 303, 303, 
    304, 304, 305, 305, 306, 306, 307, 307, 308, 308, 309, 309, 308, 
    308, 300, 300, 299, 299, 297, 297, 296, 296, 294, 294, 293, 293, 
    292, 292, 290, 290, 289, 289, 288, 288, 287, 287, 286, 286, 285, 
    285, 284, 284, 283, 283, 281, 281, 279, 279, 278, 278, 277, 277, 
    276, 276, 275, 275, 273, 273, 272, 272, 271, 271, 270, 270, 266, 
    266, 265, 265, 263, 263, 262, 262, 261, 261, 260, 260, 259, 259, 
    258, 258, 257, 257, 256, 256, 255, 255, 253, 253, 251, 251, 240, 
    240, 233, 233, 207, 207, 199, 199, 190, 190, 181, 181, 174, 174, 
    166, 166, 160, 160, 154, 154, 153, 153, 152, 152, 151, 151, 147, 
    147, 144, 144, 142, 142, 141, 141, 140, 140, 139, 139, 138, 138, 
    137, 137, 136, 136, 135, 135, 134, 134, 133, 133, 132, 132, 131, 
    131, 130, 130, 129, 129, 128, 128, 127, 127, 126, 126, 125, 125, 
    124, 124, 123, 123, 122, 122, 121, 121, 120, 120, 119, 119, 115, 
    115, 111, 111, 108, 108, 104, 104, 100, 100, 96, 96, 92, 92, 
    88, 88, 84, 84, 80, 80, 76, 76, 72, 72, 68, 68, 65, 65, 60, 60, 
    56, 56, 52, 52, 48, 48, 44, 44, 39, 39, 35, 35, 31, 31, 28, 28, 
    24, 24, 21, 21, 18, 18, 16, 16, 13, 13, 11, 11, 9, 9, 8, 8, 6, 
    6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0, 1, 1, 13, 13, 11, 11, 
    9, 9, 6, 6, 4, 4, 3, 3, 2, 2, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 
    6, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 14, 14, 15, 15, 17, 17, 
    18, 18, 20, 20, 22, 22, 25, 25, 27, 27, 30, 30, 33, 33, 35, 35, 
    38, 38, 41, 41, 44, 44, 47, 47, 50, 50, 53, 53, 56, 56, 59, 59, 
    65, 65, 67, 67, 70, 70, 74, 74, 77, 77, 81, 81, 84, 84, 87, 87, 
    91, 91, 94, 94, 98, 98, 103, 103, 107, 107, 113, 113, 118, 118, 
    124, 124, 130, 130, 136, 136, 144, 144, 152, 152, 160, 160, 171, 
    171, 199, 199, 201, 201, 202, 202, 221, 221, 226, 226, 228, 228, 
    229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 
    235, 236, 236, 237, 237, 238, 238, 239, 239, 240, 240, 241, 241, 
    242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 
    248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 
    255, 255, 257, 257, 258, 258, 259, 259, 260, 260, 261, 261, 263, 
    263, 264, 264, 265, 265, 267, 267, 268, 268, 269, 269, 271, 271, 
    272, 272, 274, 274, 275, 275, 277, 277, 278, 278, 280, 280, 281, 
    281, 283, 283, 284, 284, 286, 286), Y = c(210, 210, 209, 209, 
    208, 208, 203, 203, 202, 202, 201, 201, 200, 200, 199, 199, 198, 
    198, 197, 197, 195, 195, 194, 194, 193, 193, 192, 192, 190, 190, 
    189, 189, 188, 188, 187, 187, 185, 185, 184, 184, 182, 182, 181, 
    181, 179, 179, 177, 177, 175, 175, 176, 176, 175, 175, 174, 174, 
    173, 173, 172, 172, 171, 171, 170, 170, 169, 169, 168, 168, 167, 
    167, 166, 166, 165, 165, 164, 164, 163, 163, 162, 162, 161, 161, 
    159, 159, 158, 158, 156, 156, 154, 154, 153, 153, 152, 152, 151, 
    151, 150, 150, 149, 149, 148, 148, 146, 146, 145, 145, 144, 144, 
    143, 143, 142, 142, 141, 141, 140, 140, 139, 139, 138, 138, 137, 
    137, 136, 136, 135, 135, 134, 134, 133, 133, 132, 132, 131, 131, 
    132, 132, 133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 138, 
    138, 137, 137, 136, 136, 135, 135, 134, 134, 133, 133, 132, 132, 
    130, 130, 129, 129, 128, 128, 127, 127, 126, 126, 125, 125, 124, 
    124, 123, 123, 124, 124, 125, 125, 126, 126, 127, 127, 128, 128, 
    129, 129, 130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 135, 
    135, 136, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141, 
    142, 142, 143, 143, 144, 144, 145, 145, 146, 146, 147, 147, 148, 
    148, 149, 149, 150, 150, 151, 151, 152, 152, 153, 153, 154, 154, 
    155, 155, 156, 156, 157, 157, 158, 158, 157, 157, 155, 155, 154, 
    154, 144, 144, 143, 143, 138, 138, 137, 137, 130, 130, 126, 126, 
    122, 122, 118, 118, 115, 115, 113, 113, 111, 111, 109, 109, 104, 
    104, 101, 101, 97, 97, 94, 94, 91, 91, 87, 87, 81, 81, 79, 79, 
    78, 78, 77, 77, 75, 75, 72, 72, 69, 69, 62, 62, 58, 58, 55, 55, 
    50, 50, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55, 
    56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63, 
    64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 
    72, 72, 73, 73, 72, 72, 71, 71, 70, 70, 69, 69, 67, 67, 66, 66, 
    65, 65, 64, 64, 63, 63, 56, 56, 44, 44, 35, 35, 30, 30, 26, 26, 
    24, 24, 21, 21, 19, 19, 18, 18, 16, 16, 15, 15, 14, 14, 13, 13, 
    14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 
    22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 
    30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 
    38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 
    46, 46, 47, 47, 46, 46, 45, 45, 44, 44, 43, 43, 42, 42, 41, 41, 
    40, 40, 39, 39, 36, 36, 32, 32, 25, 25, 24, 24, 20, 20, 14, 14, 
    1, 1, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 
    9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 18, 18, 17, 17, 18, 
    18, 19, 19, 20, 20, 21, 21, 22, 22, 20, 20, 19, 19, 18, 18, 17, 
    17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 24, 24, 26, 26, 29, 
    29, 30, 30, 32, 32, 33, 33, 34, 34, 35, 35, 34, 34, 35, 35, 36, 
    36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 41, 42, 42, 21, 21, 19, 
    19, 18, 18, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 
    23, 24, 24, 25, 25, 26, 26, 28, 28, 29, 29, 31, 31, 32, 32, 34, 
    34, 35, 35, 36, 36, 38, 38, 39, 39, 41, 41, 42, 42, 43, 43, 45, 
    45, 46, 46, 47, 47, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 
    54, 55, 55, 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 
    62, 63, 63, 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 
    70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 
    78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 
    86, 87, 87, 91, 91, 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 
    97, 98, 98, 99, 99, 105, 105, 106, 106, 107, 107, 108, 108, 109, 
    109, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116, 
    117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 
    123, 124, 124, 125, 125, 126, 126, 127, 127, 128, 128, 129, 129, 
    130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 135, 135, 136, 
    136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141, 142, 142, 
    143, 143, 144, 144, 145, 145, 146, 146, 147, 147, 148, 148, 149, 
    149, 150, 150, 151, 151, 152, 152, 153, 153, 154, 154, 155, 155, 
    156, 156, 157, 157, 158, 158, 157, 157, 158, 158, 159, 159, 160, 
    160, 161, 161, 162, 162, 163, 163, 164, 164, 165, 165, 166, 166, 
    167, 167, 168, 168, 169, 169, 170, 170, 171, 171, 172, 172, 173, 
    173, 174, 174, 175, 175, 176, 176, 177, 177, 178, 178, 179, 179, 
    180, 180, 181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 
    186, 187, 187, 188, 188, 189, 189, 190, 190, 191, 191, 192, 192, 
    193, 193, 194, 194, 195, 195, 196, 196, 197, 197, 198, 198, 199, 
    199, 200, 200, 201, 201, 202, 202, 203, 203, 204, 204, 205, 205, 
    206, 206, 207, 207, 208, 208, 209, 209, 210)), 
    row.names = 6:968, class = "data.frame")/581