ggplot2: color individual words in title to match colors of groups

前端 未结 3 1818
一向
一向 2020-12-07 23:38

I recently saw a line chart in the Economist where the title had colored words to match the colors of the groups used in the line chart. I was wondering how to do this with

相关标签:
3条回答
  • 2020-12-07 23:44

    Here's a simple and more general way using the ggtext package

    produced with:

    library(ggtext) 
    
    ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) +
      geom_point(size = 3) +
      scale_color_manual(
        name = NULL,
        values = c(setosa = "#0072B2", virginica = "#009E73", versicolor = "#D55E00"),
        labels = c(
          setosa = "<i style='color:#0072B2'>I. setosa</i>",
          virginica = "<i style='color:#009E73'>I. virginica</i>",
          versicolor = "<i style='color:#D55E00'>I. versicolor</i>")
      ) +
      labs(
        title = "**Fisher's *Iris* dataset**  
        <span style='font-size:11pt'>Sepal width vs. sepal length for 
        <span style='color:#0072B2;'>setosa</span>, 
        <span style='color:#D55E00;'>versicolor</span>, and
        <span style='color:#009E73;'>virginica</span>
        </span>",
        x = "Sepal length (cm)", y = "Sepal width (cm)"
      ) +
      theme_minimal() +
      theme(
        plot.title = element_markdown(lineheight = 1.1),
        legend.text = element_markdown(size = 11)
      )
    
    0 讨论(0)
  • 2020-12-07 23:49

    This solution is based on Displaying text below the plot generated by ggplot2 and Colorize parts of the title in a plot (credits to the contributors there!).

    By using phantom placeholders for text, we avoid (most of the) hardcoding of positions.

    # create text grobs, one for each color
    library(grid)
    t1 <- textGrob(expression("Concentration of " * phantom(bold("affluence")) * "and" * phantom(bold("poverty")) * " nationwide"),
                   x = 0.5, y = 1.1, gp = gpar(col = "black"))
    
    t2 <- textGrob(expression(phantom("Concentration of ") * bold("affluence") * phantom(" and poverty nationwide")),
                   x = 0.5, y = 1.1, gp = gpar(col = "#EEB422"))
    
    t3 <- textGrob(expression(phantom("Concentration of affluence and ") * bold("poverty") * phantom(" nationwide")),
                   x = 0.5, y = 1.1, gp = gpar(col = "#238E68"))
    
    # plot and add grobs with annotation_custom
    ggplot(data, aes(year, concentration, color = group)) +
      geom_line(size = 1.5) +
      geom_point(size = 4) +
      annotation_custom(grobTree(t1, t2, t3)) +
      scale_y_continuous(limits = c(0, 0.15)) +
      scale_color_manual(values = c("#EEB422", "#238E68")) +
      coord_cartesian(clip = "off") +
      labs(x = NULL, y = NULL) +
      theme_minimal() +
      theme(legend.position = 'none',
            # add some extra margin on top
            plot.margin = unit(c(4, 1, 1, 1), "lines"))
    


    With a larger number of colored words, the creation of the different expressions should be done more programmatically. See e.g. the nice multiTitle function in a similar question for base plot: title: words in different colors?, which should be useful in ggplot as well.

    0 讨论(0)
  • 2020-12-08 00:01

    A somewhat cumbersome solution with annotation_custom:

    ggplot(dat, aes(year, concentration, color = group)) +
      geom_line(size = 1.5) +
      geom_point(size = 4) +
      scale_y_continuous(limits = c(0, 0.16)) +
      labs(x = NULL, y = NULL, title = ' ') +
      theme_minimal() +
      theme(legend.position = 'none') +
      scale_color_manual(values = c('#EEB422', '#238E68')) +
      annotation_custom(textGrob('Concentration of', gp = gpar(col = 'black')), 
                        xmin = 1972, xmax = 1972, ymin = 0.165, ymax = 0.165) +
      annotation_custom(textGrob('affluence', gp = gpar(col = '#EEB422', fontface = 'bold')), 
                        xmin = 1975.7, xmax = 1975.7, ymin = 0.165, ymax = 0.165) +
      annotation_custom(textGrob(' and ', gp = gpar(col = 'black')), 
                        xmin = 1977.65, xmax = 1977.65, ymin = 0.165, ymax = 0.165) +
      annotation_custom(textGrob('poverty', gp = gpar(col = '#238E68', fontface = 'bold')), 
                        xmin = 1979.35, xmax = 1979.35, ymin = 0.165, ymax = 0.165) +
      annotation_custom(textGrob('nationwide', gp = gpar(col = 'black')), 
                        xmin = 1982, xmax = 1982, ymin = 0.165, ymax = 0.165)
    

    which gives:

    Main drawback of this approach is that it requires a lot fiddling with the parameters to get the words of the title on the right spots.

    0 讨论(0)
提交回复
热议问题