web-dev-qa-db-fra.com

Libellés d'axe x à plusieurs lignes dans le graphique en courbes de ggplot

Edit: Cette question a été marquée comme dupliquée, mais les réponses ici ont été essayées et n'ont pas fonctionné car le cas en question est un graphique à courbes, et non un graphique à barres. L'application de ces méthodes produit un graphique avec 5 lignes, une pour chaque année - inutile. Quelqu'un qui a voté pour marquer comme duplicata a-t-il réellement essayé ces approches sur l'ensemble de données fourni avec cette question? Dans l'affirmative, postez une réponse.

Question originale:

Il existe une fonctionnalité dans les tableaux croisés dynamiques Excel qui permet aux axes catégoriels à plusieurs niveaux. J'essaie de trouver un moyen de faire la même chose avec ggplot (ou tout autre logiciel de traçage en R).

Considérez le jeu de données suivant:

set.seed(1)
df=data.frame(year=rep(2009:2013,each=4),
              quarter=rep(c("Q1","Q2","Q3","Q4"),5),
              sales=40:59+rnorm(20,sd=5))

Si cela est importé dans un tableau croisé dynamique Excel, il est facile de créer le graphique suivant:

Notez que l’axe des x a deux niveaux, un pour le trimestre et un pour la variable de regroupement, année. Des axes multiniveaux sont-ils possibles avec ggplot?

NB: Il y a un bidouillage avec des facettes qui produit quelque chose de similaire, mais ce n'est pas ce que je recherche.

library(ggplot2)
ggplot(df) +
  geom_line(aes(x=quarter,y=sales,group=year))+
  facet_grid(.~year,scales="free")

39
jlhoward

Nous utilisons des arguments dans theme pour supprimer le texte par défaut de l'axe x (axis.title.x/axis.text.x = element_blank()) et des marges supplémentaires sont ajoutées (plot.margin).

Les nouvelles étiquettes sont ajoutées à l'aide de annotate(geom = "text",. En convertissant l'objet de tracé en grob (ggplot_gtable(ggplot_build(), il est possible de désactiver le découpage des étiquettes d'axe x. 

library(ggplot2)
g1 <- ggplot(data = df, aes(x = interaction(year, quarter, Lex.order = TRUE), 
                            y = sales, group = 1)) +
  geom_line(colour = "blue") +
  coord_cartesian(ylim = c(35, 65), expand = FALSE) +
  annotate(geom = "text", x = seq_len(nrow(df)), y = 34, label = df$quarter, size = 4) +
  annotate(geom = "text", x = 2.5 + 4 * (0:4), y = 32, label = unique(df$year), size = 6) +
  theme_bw() +
  theme(plot.margin = unit(c(1, 1, 4, 1), "lines"),
        axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        panel.grid.major.x = element_blank(),
        panel.grid.minor.x = element_blank())


# remove clipping of x axis labels
g2 <- ggplot_gtable(ggplot_build(g1))
g2$layout$clip[g2$layout$name == "panel"] <- "off"
grid::grid.draw(g2)

 enter image description here


Voir aussi la réponse de Nice par @ eipi10 ici: Étiquettes d’axe sur deux lignes avec des variables x imbriquées (année inférieure au mois)

44
Henrik

Le code suggéré par Henrik fonctionne et m'a beaucoup aidé! Je pense que la solution a une grande valeur. Mais s'il vous plaît soyez conscient, il y a un petit méfait dans la première ligne du code, ce qui entraîne un mauvais ordre des données. Au lieu de

... aes(x = interaction(year,quarter), ...

cA devrait etre

... aes(x = interaction(quarter,year), ...

Le graphique obtenu contient les données dans le bon ordre.

enter image description here

P.S. J'ai suggéré une modification (qui a été rejetée jusqu'à présent) et, en raison d'un léger manque de réputation, je ne suis pas autorisé à commenter ce que j'aurais plutôt fait.

26
VDK

L'utilisateur Tung a eu une excellente réponse sur ce fil

library(tidyverse)
library(lubridate)
library(scales)

set.seed(123)
df <- tibble(
  date = as.Date(41000:42000, Origin = "1899-12-30"), 
  value = c(rnorm(500, 5), rnorm(501, 10))
)

# create year column for facet
df <- df %>% 
  mutate(year = as.factor(year(date)))

p <- ggplot(df, aes(date, value)) + 
  geom_line() + 
  geom_vline(xintercept = as.numeric(df$date[yday(df$date) == 1]), color = "grey60") + 
  scale_x_date(date_labels = "%b", 
               breaks = pretty_breaks(),
               expand = c(0, 0)) +
  # switch the facet strip label to the bottom
  facet_grid(.~ year, space = 'free_x', scales = 'free_x', switch = 'x') +
  labs(x = "") +
  theme_classic(base_size = 14, base_family = 'mono') +
  theme(panel.grid.minor.x = element_blank()) + 
  # remove facet spacing on x-direction
  theme(panel.spacing.x = unit(0,"line")) +
  # switch the facet strip label to outside 
  # remove background color
  theme(strip.placement = 'outside',
        strip.background.x = element_blank())
p

 Image

0
stackinator