xlim in ggplot2 verstehen

Wie erstelle ich Grafiken, was ist zu beachten?

Moderatoren: EDi, jogo

bigben
Beiträge: 2771
Registriert: Mi Okt 12, 2016 9:09 am

xlim in ggplot2 verstehen

Beitrag von bigben »

Hallo!

Sagen wir, wir hätten bei n Personen einen Score erhoben, der ganzzahlige Werte zwischen 5 und 10 annimmt und wollten die Häufigkeit als Balkengrafik darstellen. Folgender Code enthält einen Fehler, den ich gerade in einem etwas weniger übersichtlichen Fall IRL gemacht habe:

Code: Alles auswählen

library(ggplot2)
fragen <- data.frame(item1 = c(5,5,5,5,5,6,6,7,7,7,7,7,7,7,7,8,9,9,10,10,10,10,10))

ggplot(fragen, aes(x = item1)) + 
  geom_bar() + xlim(c(5,10))
Das führt dann zu folgender Grafik:
Rplot.png
Rplot.png (5.36 KiB) 764 mal betrachtet
Und wie man sieht, fehlen die Balken für die Werte 5 und 10, also für die Grenzen in xlim(c(5,10)). Lässt man das xlim weg, werden wieder alle Balken gezeichnet.

Die zwei offensichtlichen Antworten wären "Du solltest coord_cartesian nehmen statt xlim" und "fortune(155); fortune(85)"

Dennoch geht es mir nicht in den Kopf, warum xlim die angegebenen Grenzen aus- und nicht einschließt. Kann man das nur lernen, oder auch verstehen?
Ich habe gerade für eine Doktoranden gute 40 Grafiken in ggplot2 erstellt und wenn der nicht so gut aufgepasst hätte, also mir wäre es nicht aufgefallen.

LG,
Bernhard
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
Benutzeravatar
student
Beiträge: 674
Registriert: Fr Okt 07, 2016 9:52 am

Re: xlim in ggplot2 verstehen

Beitrag von student »

Oh Wunder! Ich habe spontan an ein offenes (beschränktes) Intervall gedacht, aber keinerlei Hinweis in der Doku gefunden. Und das haben sich die tidyverse-Entwickler doch bestimmt nicht gedacht, oder? :roll: ;)

Was ja funktioniert (und ich weiß, dass Du das weißt) ist das:

Code: Alles auswählen

p <- ggplot(fragen, aes(x = item1)) + geom_bar()
p + coord_cartesian(xlim = c(5, 10))
Was auch funktioniert und damit komme ich wieder zum beschränkten Intervall zurück, ist das:

Code: Alles auswählen

p2 <- ggplot(fragen, aes(x = item1)) + geom_bar() + xlim(4, 11)
p2
Wir haben morgen erst den 1. April und ich nehme nicht an, dass die Tidyversnauten das als Scherz implementiert haben. Die Beobachtungen entspricht nicht meinen Basis-Grafik-Erfahrungen. :)

Also, jetzt sollen doch mal die havy duty ggplot-user eine Erklärung raus hauen...!
Viele Grüße,
Student
-----------------------------------------------------------------------------------------------------------------------
faes.de, Datenanalyse mit R & das Ad-Oculos-Projekt
Das Ad-Oculos-Projekt auf YouTube

Habe Mut, dich deines eigenen Verstandes zu bedienen! (Kant)
Benutzeravatar
EDi
Beiträge: 1599
Registriert: Sa Okt 08, 2016 3:39 pm

Re: xlim in ggplot2 verstehen

Beitrag von EDi »

Hier ein bisschen code zum tüfteln... bzw als unterstüzung zu meiner erklärung.

Code: Alles auswählen

library(ggplot2)
fragen <- data.frame(item1 = c(5,5,5,5,5,6,6,7,7,7,7,7,7,7,7,8,9,9,10,10,10,10,10))

ggplot(fragen, aes(x = item1)) + 
  geom_bar()


ggplot(fragen, aes(x = item1)) + 
  geom_bar() + 
  xlim(c(5,10))

# same as
ggplot(fragen, aes(x = item1)) + 
  geom_bar() + 
  scale_x_continuous(limits =  c(5, 10))

# same as, but without warnings
ggplot(fragen[fragen$item1 > 5 & fragen$item1 < 10, , drop = FALSE], aes(x = item1)) + 
  geom_bar() + 
  scale_x_continuous(limits =  c(5, 10))


# use factor instead (x-axis is implicitly categoric with bars!)
ff <- fragen
ff$item1 <- factor(ff$item1)

# Error: Discrete value supplied to continuous scale
ggplot(ff, aes(x = item1)) + 
  geom_bar() + 
  xlim(limits =  c(5, 10))

# Error: Discrete value supplied to continuous scale
ggplot(ff, aes(x = item1)) + 
  geom_bar() + 
  scale_x_continuous(limits =  c(5, 10))


# hehe
ggplot(ff, aes(x = item1)) + 
  geom_bar() + 
  scale_x_discrete(limits =  c(5, 10))

ggplot(ff, aes(x = item1)) + 
  geom_bar() + 
  scale_x_discrete(limits =  c(6, 7, 8, 9))
# now you should understand
ggplot(ff, aes(x = item1)) + 
  geom_bar()


# this works, because the bar with is 0.9 (s0 0.45 in each direction), so the full geom fits into the range
ggplot(fragen, aes(x = item1)) + 
  geom_bar() + 
  scale_x_continuous(limits =  c(4.5, 10.5))

# this doesn't workm because the geom does not fit into the limtis range (geom spancs from 5-0.45 = 4.55)
ggplot(fragen, aes(x = item1)) + 
  geom_bar() + 
  scale_x_continuous(limits =  c(4.6, 10.4))

# if we reduce the with, the geom fits again
ggplot(fragen, aes(x = item1)) + 
  geom_bar(width = 0.1) + 
  scale_x_continuous(limits =  c(4.6, 10.4))

  

xlim(c(5, 10) ist gleich zusetzen it scale_x_continuous(limits = c(5, 10)). D.h. es bezieht sich auf eine Kontinuierliche x-achse.
Dies macht ja aber bei einem barplot aus meiner Sicht wenig Sinn, da die x-Achse implizit diskret ist.

Balken haben immer eine breite (width argument). Standardmäßig ist die bei 0.9, also 0.45 in beide Richtungen.
Der ersten balken reicht also von 5-0.45 = 4.55 bis 5+0.45 = 5.45.
Jetzt sagt du aber mit xlim: schneide mir alles kleiner 5 weg. Damit ist auch dein Balken weg, da er ja von 4.55 anfängt.
Machst du die Balken schmäler passt es wieder.

Zusammenfassend:
Ich nutze nie die Abkürzungen xlim, ylim. Stattdseen empfehle ich die scale_*_* funktionenzu verwenden. Das ist expliziter. In dem Fall würde ich aber einfach vorher die 5er und 10 wegfiltern.... Wenn unbedingt im Plot sein muss (ich bin kein Fan von Logik in Plot-befehle zu packen), dann scale_x_discrete.

Hoffe es hilft dir ein wenig weiter...

Edi
Bitte immer ein reproduzierbares Minimalbeispiel angeben. Meinungen gehören mir und geben nicht die meines Brötchengebers wieder.

Dieser Beitrag ist lizensiert unter einer CC BY 4.0 Lizenz
Bild.
Benutzeravatar
student
Beiträge: 674
Registriert: Fr Okt 07, 2016 9:52 am

Re: xlim in ggplot2 verstehen

Beitrag von student »

Hallo Edi,

da hast Du Dich ja richtig reingekniet (Corona-Auszeit?), oder - jetzt mal ehrlich - hast Du das alles parat gehabt? ;)

Danke dafür!

Als Anwender würde mich das
Dies macht ja aber bei einem barplot aus meiner Sicht wenig Sinn, da die x-Achse implizit diskret ist.
nicht glücklich machen und als anwenderfreundlicher Entwickler würde ich das abfangen und egal ob kontinuierlich oder diskret immer die richtige Achse-Limits wählen. Der Standard-R-User - wenn es ihn denn gibt - denkt doch nicht an so etwas....
Viele Grüße,
Student
-----------------------------------------------------------------------------------------------------------------------
faes.de, Datenanalyse mit R & das Ad-Oculos-Projekt
Das Ad-Oculos-Projekt auf YouTube

Habe Mut, dich deines eigenen Verstandes zu bedienen! (Kant)
bigben
Beiträge: 2771
Registriert: Mi Okt 12, 2016 9:09 am

Re: xlim in ggplot2 verstehen

Beitrag von bigben »

Danke EDi,

jede Auseinandersetzung mit dem Thema hilft, und wenn es nur dabei hilft, sich die Inkonsistenzen besser einzuprägen.

Ich könnte verstehen, dass Balken wegfallen, weil man den Balken eine Breite zuspricht und die Ränder der Balken außerhalb meiner x-limits lägen. Inkonsistent ist dann aber, dass Punkte in geom_point keine Breite haben:

Code: Alles auswählen

library(ggplot2)
eckpunkte <- data.frame(x=c(0,0,1,1), y=c(0,1,0,1))
ggplot(eckpunkte, aes(x=x, y=y)) +geom_point(size=25) + xlim(c(0,1))
Da werden die Punkte auch mit xlim gezeichnet, selbst wenn sie über den Bildrand hinaus ragen. Merke: Balken haben eine Breite aber Punkte nicht. :? :shock:
xlim(c(5, 10) ist gleichzusetzen mit scale_x_continuous(limits = c(5, 10)). D.h. es bezieht sich auf eine kontinuierliche x-Achse.
Dies macht ja aber bei einem barplot aus meiner Sicht wenig Sinn, da die x-Achse implizit diskret ist.
Irgendwie stecken xlim und ylim noch aus base so tief drin. Es passiert mir halt immer noch. Meine x-Achse ist nicht kontinuierlich, aber doch metrisch. Sowas kennt ggplot aber nicht. Diskret heißt in ggplot ja nicht diskret, sondern ordered. Eine Achse für diskrete ganze Zahlen mit scale_x_discrete nachzuahmen ist eher aufwändig, was ich weiter unten zeige.

In dem Fall würde ich aber einfach vorher die 5er und 10 wegfiltern....
Da hast Du mich falsch verstanden, ich wollte nichts wegfiltern! Wenn ein Summenscore von 5 bis 10 reicht, dann will ich oft auch, dass auf der Achse der gesamte Bereich von 5 bis 10 dargestellt wird. Selbst dann, wenn die Werte unbesetzt sind. Ich mache mal ein anderes Beispiel. Nehmen wir an, wir legen jedem Probanden einen Fragebogen mit mehreren Fragen vor und bilden Summenscores und da können jetzt Werte zwischen 0 und 48 herauskommen (Beispiel). Die Extreme 0 und 48 sind aber selten. Ich habe mal versucht, das mit meinen bisherigen Kenntnissen und, Deinem Rat folgend, als factor um zusetzen. Das sieht dann so aus:

Code: Alles auswählen

library(ggplot2)
# beispieldaten
fragen <- data.frame(item1 = rbinom(100, 48, .7))

# Umwandlung und Achsenpflege:
fragen$item1.f <- factor(fragen$item, levels = 0:48)
ggplot(fragen, aes(x=item1.f)) +
  geom_bar() +
  scale_x_discrete(limits=as.character(0:48),
                   breaks = as.character(seq(0, 48, 4)))
Ich muss also erst den Summenscore in einen factor umwandeln, dann die limits in character umwandeln und mich dann um die x-Achsenbeschriftung selbst kümmern. Dafür funktioniert es dann auch, wenn mal eine 0 oder eine 48 vorkommen sollte.

Ist das so kompliziert, oder geht das auch etwas kürzer, mehr so in der Art von

Code: Alles auswählen

plot(table(fragen$item1), xlim=c(0,48), type="h")
oder wie die jungen Leute heute schreiben würden:

Code: Alles auswählen

fragen %>% `[`("item1") %>% table() %>% plot(type = "h", xlim = c(0,48))
:lol:

LG,
Bernhard
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
Benutzeravatar
EDi
Beiträge: 1599
Registriert: Sa Okt 08, 2016 3:39 pm

Re: xlim in ggplot2 verstehen

Beitrag von EDi »

Da werden die Punkte auch mit xlim gezeichnet, selbst wenn sie über den Bildrand hinaus ragen. Merke: Balken haben eine Breite aber Punkte nicht. :?
Jaein... :?

1) Punkte nur durch eine Koordinate.
Balken werden durch die koordinaten von 2 Ecken definiert. Deshalb haben Balken immer eine breite (unterschied in x-Richtung der 2 Ecken) und Punkte keine (weil ja keine different in x Richtung da ist mit nur einem Balken. Also ja, das stimmt. Ist aber nichts überraschendes.

2) Die Punkte werden gezeichnet weil xlim die Grenzen inkludiert. Genauso ist das aber auch bei Balken der Fall. Wenn ich z.b. xlim auf

Code: Alles auswählen

library(ggplot2)
library(dplyr)
fragen <- data.frame(item1 = c(5,5,5,5,5,6,6,7,7,7,7,7,7,7,7,8,9,9,10,10,10,10,10))
ggplot(fragen, aes(x = item1)) + 
  geom_bar() + 
  scale_x_continuous(limits =  c(4.55, 10.45))
  
setze, dann sehe ich die Balken (weil der erste Balken bei x = 5- 0.9/2 =4.55 anfängt und das in xlim liegt) .

Code: Alles auswählen

plot(table(fragen$item1), xlim=c(0,12), type="h")
würde in ggplot so umsetzen (Logik immer außerhalb vom plot).

Code: Alles auswählen

computed <- fragen %>% 
  count(item1)
 
ggplot(data = computed) +
  geom_segment(aes(x = item1, y = n, xend = item1, yend = 0)) +
  scale_x_continuous(limits = c(0, 12))

Lösung deines Problems, wäre coord_cartesian zu nehmen oder xlim so anzupassen, dass die balkenbreite mit in Betracht gezogen wird.

Code: Alles auswählen

ggplot(data = computed) +
  geom_bar(stat = "identity", aes(x = item1, y = n)) +
  coord_cartesian(c(5, 10))
BTW graphic::barplot ist auch nicht wirklich intuitiver:

Code: Alles auswählen

  barplot(n ~ item1, data = computed, xlim = c(5,10))
:?: Letztendlich genau das gleiche wie in ggplot, nur dass die x-skala bei 0 anfängt...
Bitte immer ein reproduzierbares Minimalbeispiel angeben. Meinungen gehören mir und geben nicht die meines Brötchengebers wieder.

Dieser Beitrag ist lizensiert unter einer CC BY 4.0 Lizenz
Bild.
Benutzeravatar
EDi
Beiträge: 1599
Registriert: Sa Okt 08, 2016 3:39 pm

Re: xlim in ggplot2 verstehen

Beitrag von EDi »

student hat geschrieben: Mi Apr 01, 2020 9:43 am Hallo Edi,

da hast Du Dich ja richtig reingekniet (Corona-Auszeit?), oder - jetzt mal ehrlich - hast Du das alles parat gehabt? ;)

Danke dafür!

Als Anwender würde mich das
Dies macht ja aber bei einem barplot aus meiner Sicht wenig Sinn, da die x-Achse implizit diskret ist.
nicht glücklich machen und als anwenderfreundlicher Entwickler würde ich das abfangen und egal ob kontinuierlich oder diskret immer die richtige Achse-Limits wählen. Der Standard-R-User - wenn es ihn denn gibt - denkt doch nicht an so etwas....

Nein keine Corona Auszeit - Homeoffice... Aber um 22Uhr versuche ich nicht mehr zu arbeiten ;)

Da beist sich jetzt flexibilität vs Komplexität.
Es gibt Situationen in dene man etwas auf eine kontinierlichen skala platzieren will (z.B. text zwischen Balken).
Und ggplot macht das auch perfekt möglich.
xlim bezieht sich nunmal auf die kontinierliche skala.
Bitte immer ein reproduzierbares Minimalbeispiel angeben. Meinungen gehören mir und geben nicht die meines Brötchengebers wieder.

Dieser Beitrag ist lizensiert unter einer CC BY 4.0 Lizenz
Bild.
Benutzeravatar
EDi
Beiträge: 1599
Registriert: Sa Okt 08, 2016 3:39 pm

Re: xlim in ggplot2 verstehen

Beitrag von EDi »

Wenn ein Summenscore von 5 bis 10 reicht, dann will ich oft auch, dass auf der Achse der gesamte Bereich von 5 bis 10 dargestellt wird. Selbst dann, wenn die Werte unbesetzt sind.
Ahh, jetzt verstehe ich was du meinst...

Ich würde dann das a Faktor machen und die levels explizit mit angeben. drop = FALSE zeigt dann auch nicht besetzte levels auf der x-Achse

Code: Alles auswählen

library(ggplot2)
fragen <- data.frame(item1 = factor(c(5,5,5,5,5,6,6,7,7,7,7,7,7,7,7,8,9,9,10,10,10,10,10), levels = 4:10))

ggplot(data = fragen) +
  geom_bar(aes(x = item1)) +
  scale_x_discrete(drop = FALSE)
Bitte immer ein reproduzierbares Minimalbeispiel angeben. Meinungen gehören mir und geben nicht die meines Brötchengebers wieder.

Dieser Beitrag ist lizensiert unter einer CC BY 4.0 Lizenz
Bild.
Benutzeravatar
EDi
Beiträge: 1599
Registriert: Sa Okt 08, 2016 3:39 pm

Re: xlim in ggplot2 verstehen

Beitrag von EDi »

Oder mit kontinuierlicher x-Achse, die fehlende levels mit 0 auffüllen (dann brauchst du keine Faktoren):

Code: Alles auswählen

library(ggplot2)
library(dplyr)
library(tidyr)
fragen <- data.frame(item1 = c(5,5,5,5,5,6,6,7,7,7,7,7,7,7,7,8,9,9,10,10,10,10,10))


computed <- fragen %>% 
  count(item1) %>%
  complete(item1 = c(4:10), fill = list(n = 0))

ggplot(data = computed) +
  geom_bar(stat = "identity", aes(x = item1, y = n)) 
Bitte immer ein reproduzierbares Minimalbeispiel angeben. Meinungen gehören mir und geben nicht die meines Brötchengebers wieder.

Dieser Beitrag ist lizensiert unter einer CC BY 4.0 Lizenz
Bild.
Benutzeravatar
EDi
Beiträge: 1599
Registriert: Sa Okt 08, 2016 3:39 pm

Re: xlim in ggplot2 verstehen

Beitrag von EDi »

Für ordered hast du jetzt also die Qual der Wahl: discrete oder kontinuierliche x-Achse.
Beides geht.
Beides passt irgendwie.

Ich würde vermutlich einen ordered factor nehmen (und somit die diskrete x-Achse),aber der unterschied ich hauchdünn...
Bitte immer ein reproduzierbares Minimalbeispiel angeben. Meinungen gehören mir und geben nicht die meines Brötchengebers wieder.

Dieser Beitrag ist lizensiert unter einer CC BY 4.0 Lizenz
Bild.
Antworten