WindSur
WindSur

Reputation: 140

R. Fixing labels in pie chart

I am using this script:

# my data:
df <- data.frame(Somatic = c("PIK3CA", "TP53", "GATA3", "KMT2C", "PTEN", "NCOR1", "ARID1A", "RUNX1", "NF1", "TBX3", "FOXA1", "ERBB2", "AKT1", "PREX2", "CBFB", "INPPL1", "NSD3", "ESR1", "AXIN2", "RAD51C"),
                 Freq_mut = c(32.6, 32.6, 11.9, 9.3, 5.4, 4.7, 3.8, 3.8, 3.6, 3.1, 2.9, 2.8, 2.5, 2.4, 2.3, 1, 1, 0.8, 0.6, 0.6))

library(randomcoloR)

# set of 20 random colors
colors <- distinctColorPalette(20)

ggplot(df, aes(x = "", y = Freq_mut, fill = Somatic)) +
  geom_bar(width = 1, stat = "identity", color = "black") +
  coord_polar("y", start = 0) +
  scale_fill_manual(values = colors) +
  ggtitle("A") +
  labs(fill = "Somatic Gene") +
  theme(panel.background = element_blank(), plot.background = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank()) +
geom_label_repel(data = df,
                   aes(y = Freq_mut, label = paste0(Somatic)),
                   size = 4.5, nudge_x = 1, show.legend = FALSE)

enter image description here

But as you can see in the image, the labels are not in the correct position and are missing the rest of the genes. How Could I fix it and remove the "x" to the left of the plot? Thanks!

Upvotes: 0

Views: 1115

Answers (3)

I_O
I_O

Reputation: 6911

In addition to @Allan Camerons perfect solution to implement the specified chart layout, I'd encourage to reconsider whether that layout indeed makes it easy for the viewer to grasp the information you want to convey.

An alternative display might help the viewer to associate gene(?) with mutation frequency and keep mental note of the top/bottom five "mutators" at one glance (if that's the intended message). By having the x-axis stretch from 0-100 % you can maintain if not improve the pie charts 'fraction-of-whole' aesthetic (angles being harder to compare than lengths).

Example (using your data df):

library(forcats) ## for convenient factor operations

df |>
    mutate(Somatic = fct_reorder(Somatic, Freq_mut, mean)) |>
    ggplot(aes(x = Freq_mut, y = Somatic)) +
    geom_bar(aes(x = 100), stat = "identity", fill = '#e0e0e0') +
    geom_bar(stat = "identity") +
    geom_text(aes(x = Freq_mut,
                  label = sprintf("%2.1f  ", round(Freq_mut, 1))
                  ), adj = 0, nudge_x = 1, size = 3) +
    facet_wrap(~ Freq_mut < median(Freq_mut), 
               scales = 'free_y', ncol = 2
               ) +
    scale_x_continuous(breaks = c(0, 100)) +
    labs(x = 'mutation frequency (%)', y = '') +
    theme(
        panel.background = element_blank(),
        strip.text.x = element_blank(),
        axis.text.y = element_text(hjust = 1, size = rel(1)),
        panel.grid = element_blank()
    )

result: pie converted to barchart

Upvotes: 2

Allan Cameron
Allan Cameron

Reputation: 173793

I think you may be best with direct labelling here. Remember if you have a stacked bar graph, the y values are stacked, so your text labels also need to be stacked using position_stack

library(randomcoloR)
library(geomtextpath)

# set of 20 random colors
colors <- distinctColorPalette(20)

ggplot(df, aes(x = 1, y = Freq_mut, fill = Somatic)) +
  geom_bar(width = 1, stat = "identity", color = "black") +
  coord_polar("y", start = 0) +
  scale_fill_manual(values = colors, guide = "none") +
  ggtitle("A") +
  labs(fill = "Somatic Gene", x = NULL) +
  theme(panel.background = element_blank(), plot.background = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank()) +
  geom_textpath(data = df, position = position_stack(vjust = 0.5),
                   aes(x = 1.7, y = Freq_mut, label = paste0(Somatic)),
                   size = 4.5, show.legend = FALSE)

enter image description here

or

ggplot(df, aes(x = 1, y = Freq_mut, fill = Somatic)) +
  geom_bar(width = 1, stat = "identity", color = "black") +
  coord_polar("y", start = 0) +
  scale_fill_manual(values = colors, guide = "none") +
  ggtitle("A") +
  labs(fill = "Somatic Gene", x = NULL) +
  theme(panel.background = element_blank(), plot.background = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank()) +
  geom_labelpath(data = df, position = position_stack(vjust = 0.5),
                   aes(x = 1.7, y = Freq_mut, label = paste0(Somatic)),
                   size = 4.5, show.legend = FALSE) 

enter image description here

To add percentages, you can try:

ggplot(df, aes(x = 1, y = Freq_mut, fill = Somatic)) +
  geom_bar(width = 1, stat = "identity", color = "black") +
  coord_polar("y", start = 0, clip = "off") +
  scale_fill_manual(values = colors, guide = "none") +
  xlim(0.5, 2) +
  ggtitle("A") +
  labs(fill = "Somatic Gene", x = NULL) +
  theme(panel.background = element_blank(), plot.background = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank()) +
  geom_textpath(data = df %>% 
                  mutate(perc = scales::percent(Freq_mut/ sum(Freq_mut))), 
                position = position_stack(vjust = 0.5), hjust = 1,
                aes(x = 1.55, y = Freq_mut, 
                    label = paste0(Somatic, " (", perc, ")")),
                size = 4.5, show.legend = FALSE)

enter image description here

Upvotes: 5

Quinten
Quinten

Reputation: 41225

You should precalculate the positions of the labels so you can position the labels around the pie chart. Here is an option using geom_label_repel:

library(ggplot2)
library(dplyr)
library(ggrepel)
library(randomcoloR)

# set of 20 random colors
colors <- distinctColorPalette(20)
df %>%
  arrange(desc(Somatic)) %>%
  mutate(pos_freq_mut = cumsum(Freq_mut) - Freq_mut/2) %>%
  ggplot(aes(x = "", y = Freq_mut, fill = Somatic)) +
  geom_col(color = "black") +
  coord_polar("y") +
  geom_label_repel(aes(y = pos_freq_mut, label = paste0(Somatic)),
                   size = 4.5, nudge_x = 1, nudge_y = 1, show.legend = FALSE) +
  scale_fill_manual(values = colors) +
  ggtitle("A") +
  labs(fill = "Somatic Gene", x = "") +
  theme(panel.background = element_blank(), plot.background = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank()) 

Created on 2022-12-27 with reprex v2.0.2

Upvotes: 3

Related Questions