3 votes

Comment créer un tracé geom_line avec un tracé de barres d'axe y inversé (deuxième) dans ggplot?

Je essaie de tracer une figure geom_line, combinée avec un barplot. Le barplot aura un axe des y inversé. Le produit final devrait être similaire à la figure ci-dessous. Je ne sais pas comment combiner le barplot inversé avec le tracé de ligne.

Aussi, ce serait génial si nous pouvions avoir une légende pour A, B et C. Merci pour toute aide.

library(ggplot2)
Mydata = data.frame(ID=1:14, A=1:14, B=20:7, C=100:113)

ggplot(data = Mydata) + 
geom_line(aes(x=ID, y = A)) +
geom_line(aes(x=ID, y = B))

entrer la description de l'image ici

J'ai essayé le code suivant. Le deuxième axe des y est maintenant inversé de 90 à 130, cependant, le barplot n'est toujours pas inversé.

ggplot(data = Mydata) + 
geom_line(aes(x=ID, y = A)) +
geom_line(aes(x=ID, y = B)) + 
geom_bar(stat="identity", aes(x=ID, y = (190-C)/5)) + 
scale_y_continuous(breaks=seq(0,30,5), sec.axis = sec_axis(trans=~190-.*5, breaks=seq(0,130,10)))

entrer la description de l'image ici

1voto

Kat Points 686

Mettre à jour

Si vous souhaitez que l'apparence ressemble au graphique de gauche plutôt qu'au graphique de droite :

entrez ici la description de l'image entrez ici la description de l'image

Alors tout ce dont vous avez besoin est rev() dans geom_col :

geom_col(aes(x = ID, y = rev(-(190-C)/5)))

Laissez-moi savoir si j'ai encore mal compris ce que vous recherchez.


Réponse originale

Si vous voulez que les barres descendent, elles doivent contenir des valeurs négatives.

Probablement que vous le savez déjà.

Lorsque vous ajoutez un deuxième axe Y, c'est juste visuel; aucune de vos traces ne suit réellement cet axe. Le 'tour de passe-passe' est la transformation.

Si vous voulez que les barres soient au-dessus des lignes comme s'il y avait un axe zéro pour les barres en haut et un axe zéro en bas pour les lignes, certaines choses doivent changer.

  1. les barres doivent être négatives pour aller vers le bas; c'est ce qui fait bouger tout le reste

  2. les lignes doivent être inférieures aux valeurs des barres sans perdre le rapport d'aspect (pour faute d'un meilleur terme)

La manière la plus simple de transformer le y dans les lignes pour s'assurer que les barres ne se chevauchent pas est de compenser les deux traces en inversant le y actuel et en ajoutant la plus grande valeur apparaissant dans la trace de barre.

Tout d'abord, trouvez cette valeur de compensation :

offset = max((190 - Mydata$C)/5)  # combien décaler les autres traces

Vérifiez où nous en sommes jusqu'à présent, avec les y inversés et compensés :

offset = max((190 - Mydata$C)/5)
ggplot(data = Mydata) + 
  geom_line(aes(x = ID, y = -A - offset)) +
  geom_line(aes(x = ID, y = -B - offset)) +
  geom_col(aes(x = ID, y = -(190-C)/5))

entrez ici la description de l'image

Ensuite, nous devons corriger les deux axes y. En commençant par l'axe y sur la gauche, nous devons faire en sorte que cela ressemble à si nous n'avions pas inversé tout. Pour cela, nous devons trouver la valeur négative réelle qui reflète le zéro perçu sur l'axe y.

Comme la colonne B a la plus grande valeur (à 20), je l'ai utilisée pour déterminer où se situe le bas. De plus, étant donné que la valeur la plus basse entre A et B est 1, nous allons ajouter -1 pour obtenir cette ligne zéro. Pour trouver le bas où nous voulons la ligne zéro, trouvez le minimum de la colonne B inversée - compensée moins 1.

btm = min(-1 * Mydata$B - offset - 1) # parce que la valeur minimale est 1

Regardez où nous en sommes jusqu'à présent :

btm = min(-1 * Mydata$B - offset - 1) # parce que la valeur minimale de B est 1
offset = max((190 - Mydata$C)/5)
ggplot(data = Mydata) + 
  geom_line(aes(x = ID, y = -A - offset)) +
  geom_line(aes(x = ID, y = -B - offset)) +
  geom_col(aes(x = ID, y = -(190-C)/5)) +
  scale_y_continuous(breaks = seq(btm, by = 10, length.out = 5), 
                     labels = seq(0, 40, 10))

entrez ici la description de l'image

Il est temps d'ajouter le deuxième axe y.

J'ai inversé le signe sur la transformation et j'ai regardé où les nombres se sont positionnés sur le deuxième axe y.

btm = min(-1 * Mydata$B - offset - 1) # parce que la valeur minimale de B est 1
offset = max((190 - Mydata$C)/5)
ggplot(data = Mydata) + 
  geom_line(aes(x = ID, y = -A - offset)) + 
  geom_line(aes(x = ID, y = -B - offset)) +
  geom_col(aes(x = ID, y = -(190-C)/5)) +
  scale_y_continuous(breaks = seq(btm, by = 10, length.out = 5), 
                     labels = seq(0, 40, 10),
                     sec.axis = sec_axis(~190 + . * 5))  # changé le signe !

entrez ici la description de l'image

Ensuite, nous devons déterminer où se situe notre zéro perçu en haut sur le deuxième axe y. Pour calculer ceci, nous avons besoin du maximum de la colonne C, lorsqu'elle est calculée comme dans le graphique et transformée comme l'axe est transformé, puis modifiée par la plus grande valeur de C, la plus grande valeur de B et la compensation déjà calculée.

top = max(((190 + (-(190 - Mydata$C)/5) * 5) + offset - btm + max(Mydata$B)))

Remarquez que dans cet appel pour créer cette valeur :

Le Y dans les barres est :

-(190 - Mydata$C)/5

Le Y dans les barres transformé par le deuxième axe est :

190 + (-(190 - Mydata$C)/5) * 5

Et voilà ! Vous pouvez ajuster les étiquettes maintenant qu'elles sont prêtes comme bon vous semble. (Je suppose que vous avez quelque chose en tête.)

btm = min(-1 * Mydata$B - offset - 1) # parce que la valeur minimale de B est 1
offset = max((190 - Mydata$C)/5)
top = max(((190 + (-(190 - Mydata$C)/5) * 5) + offset - btm + max(Mydata$B))) 

ggplot(data = Mydata) + 
  geom_line(aes(x = ID, y = -A - offset)) +
  geom_line(aes(x = ID, y = -B - offset)) +
  geom_col(aes(x = ID, y = -(190-C)/5)) +
  scale_y_continuous(breaks = seq(btm, by = 10, length.out = 5), 
                     labels = seq(0, 40, 10),
                     sec.axis = sec_axis(~190 + . * 5,  # changé le signe !
                                         breaks = seq(top - 20 * 4, top, by = 20),
                                         labels = seq(100, 0, by = -25)))

entrez ici la description de l'image

1voto

jay.sf Points 8160

Vous pouvez essayer les graphiques de base, où cela est assez simple.

## base plane with the lines
par(mar=c(5, 4, 4, 3) + .1)
matplot(Mydata[2:3], type='o', pch=c(0, 4), col=1, lty=1,
        ylim=c(min(Mydata[2:3]), max(Mydata[2:3]) + 10),
        yaxt='n', xlim=c(.5, nrow(Mydata) + .5),
        xlab='xlab', ylab='ylab', main='main')
axis(2, axTicks(2), axTicks(2), tck=.02, las=2)  ## make nicer west axis
ymax <- par()$usr[4]  ## store north coord
xseq <- seq_len(nrow(Mydata))  ## store x axis
fac <- 1/15  ## define reduction factor for upper barplot
## upper barplot using `rect`
rect(xseq - .25, ymax, xseq + .25, ymax - Mydata$C*fac, 
     col='#139FFF', border=NA)
axis(3, xseq, tck=.02, labels=FALSE)  ## north x axis
ats <- seq.int(0, max(Mydata$C), by=50)  ## east ats
axis(4, y - ats*fac, ats, tck=.02, las=2)  ## east axis
## legend
legend('bottomright', legend=c('foo', 'bar', 'baz'), lty=1,
       lwd=c(1, 1, 5), pch=c(0, 4, NA), col=c(1, 1, '#139FFF'),
       bty='n', horiz=TRUE)

entrez la description de l'image ici


Données :

Mydata <- structure(list(ID = 1:14, A = 1:14, B = 20:7, C = 100:113), class = "data.frame", row.names = c(NA, 
-14L))

1voto

Hadley Wickham répond ici (https://stackoverflow.com/a/3101876/19594737) que les échelles d'axe y séparées ne sont pas prises en charge par ggplot, car il les considère fondamentalement défectueuses.

Cela dit, en utilisant le package gridExtra, vous pouvez vous en rapprocher. Fondamentalement, vous devez créer les deux graphiques séparément, puis les attacher dans une grille.

Voici la sortie...

entrer la description de l'image ici

...et voici l'entrée :

library(tidyverse)
library(gridExtra)

Mydata = data.frame(ID=1:14, A=1:14, B=20:7, C=100:113)

lines<-Mydata%>%
  select(-C)%>%
  gather(key=Lines,value=vals,-ID)

bars<-Mydata%>%
  select(ID,C)

b<-ggplot()+
  geom_bar(data=bars,  aes(ID,C),stat="identity",fill='blue')+
  scale_y_reverse()+
  theme_minimal()+
  theme(axis.ticks.x = element_blank(),
        axis.text.x = element_blank())+
  labs(x="",y="Étiquette de l\'axe Y")+
  scale_x_continuous(limits = c(0,15))

l<-ggplot()+
    geom_line(data=lines,aes(ID,vals,color=Lines))+
  theme_minimal()+
  theme(legend.position="bottom")+
  scale_x_continuous(limits = c(0,15))+
  labs(y="Deuxième étiquette de l'axe Y")

grid.arrange(b,l,nrow=2)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X