Narysować wiele wykresów na jednym wykresie w R?

13

Korzystając z następującego kodu, próbowałem narysować cztery wykresy na wykresie w R. Nie jestem zadowolony z tej figury, ponieważ między wykresami jest dużo miejsca, dlatego szerokość wykresów nie jest wystarczająca do analizy wykresów.

  1. Czy ktoś mógłby mi pomóc w stworzeniu ładnego wykresu zawierającego cztery wykresy?

  2. Jak mogę zachować etykiety osi X od 1 do 10 zamiast domyślnych 5 etykiet?

Dane:

a1: 11,013 13,814 13,831 13,714 13,787 13,734 13,778 13,771 13,823 13,659

a2: 5,181 7,747 8,314 861 7,920 8,158 8,540 8,845 7,881 8,301

Użyłem danych a1 dla b1, c1 i d1; dane a2 dla b2, c2 i d2 właśnie tutaj.

Postać:

wprowadź opis zdjęcia tutaj

Kod:

        op=par(mfrow=c(4,1), mar=c(5.5,5.1,4.1,2.1))
        plot(a1, type="b", ylim=c(0,14.5), xlab="Time (secs)", ylab="", cex.axis=1.4, cex.lab=1.3,cex=1.2,lwd=2.5,col="red1",lty=2,pch=1, main="A")
        lines(a2,type="b",pch=3,lty=3,col="darkblue",lwd=2.5,cex=1.2)
        par(xpd=T)
        legend(1,26.5,c("X","Y"),bty="n",horiz=T,cex=1.5,col=c("red1","darkblue"),text.col=c("red1","darkblue"),pch=c(1,3),lty=c(2,3),x.intersp=0.4,adj=0.2)
        plot(b1, type="b", ylim=c(0,14.5), xlab="Time (secs)", ylab="", cex.axis=1.4, cex.lab=1.3,cex=1.2,lwd=2.5,col="red1",lty=2,pch=1, main="B")
        lines(b2,type="b",pch=3,lty=3,col="darkblue",lwd=2.5,cex=1.2)
        plot(c1, type="b", ylim=c(0,14.5), xlab="Time (secs)", ylab="", cex.axis=1.4, cex.lab=1.3,cex=1.2,lwd=2.5,col="red1",lty=2,pch=1, main="C")
        lines(c2,type="b",pch=3,lty=3,col="darkblue",lwd=2.5,cex=1.2)
        plot(d1/1000, type="b", ylim=c(0,14.5), xlab="Time (secs)", ylab="", cex.axis=1.4, cex.lab=1.3,cex=1.2,lwd=2.5,col="red1",lty=2,pch=1, main="D")
        lines(d2,type="b",pch=3,lty=3,col="darkblue",lwd=2.5,cex=1.2)
   > mtext("Price", side=2, at=100,line=3,cex=1.1)
samarasa
źródło
1
czy możesz podać szczegóły swoich danych? ewentualnie dput (data_from_r)
suncoolsu
@ suncoolsu, zaktualizowałem pytanie próbką danych. Dziękuję Ci.
samarasa,
Co jeśli masz 2 kolory i 4 rodzaje linii na tych samych osiach z legendą? Chciałbym zobaczyć kod i wyniki.
Paul,
@ user87: Ponieważ 4 wykresy pochodzą z 4 różnych eksperymentów. Dlatego myślę, że lepiej jest narysować 4 wykresy, aby przeanalizować wyniki eksperymentów.
samarasa,
@ user87, nie jestem pewien, co masz na myśli. Być może, jeśli zaczniesz nowe pytanie, ktoś by na nie odpowiedział (chciałbym :))
Brandon Bertelsen,

Odpowiedzi:

16

Jeśli chcesz pozostać przy metodzie, której używałeś, możesz nauczyć się polecenia układu (). Kilka innych zmian w szczegółach i możesz zbliżyć wykresy do siebie. Możesz także umieścić unikalne rzeczy, które zmieniają się między wykresami na liście (takie jak dane i marginesy), a następnie przejść przez pętlę. Zauważysz również, że utworzyłem dolną oś za pomocą polecenia direct axis (), abyś mógł kontrolować, dokąd idą elementy.

layout(matrix(1:5, ncol = 1), widths = 1,
        heights = c(1,5,5,5,7), respect = FALSE)
par(mar=c(0, 4, 0, 0))
plot(1, type = 'n', axes = FALSE, bty = 'n', ylab = '')
legend('left', , c("X","Y"), bty="n", horiz=T, cex=1.5, col=c("red1","darkblue"), text.col=c("red1","darkblue"), pch=c(1,3), lty=c(2,3), x.intersp=0.4,adj=0.2)
par(mar=c(0, 4, 2, 1), bty = 'o')
plot(a1, type="b", ylim=c(0,14.5), xlab="Time (secs)", ylab="", xaxt = 'n', cex.axis=1.4, cex.lab=1.3,cex=1.2, lwd=2.5, col="red1", lty=2, pch=1, main="A")
lines(a2,type="b",pch=3,lty=3,col="darkblue",lwd=2.5,cex=1.2)
par(xpd=T)
plot(b1, type="b", ylim=c(0,14.5), xlab="Time (secs)", ylab="", xaxt = 'n', cex.axis=1.4, cex.lab=1.3,cex=1.2,lwd=2.5,col="red1",lty=2,pch=1, main="B")
lines(b2,type="b",pch=3,lty=3,col="darkblue",lwd=2.5,cex=1.2)
plot(c1, type="b", ylim=c(0,14.5), xlab="Time (secs)", ylab="", xaxt = 'n', cex.axis=1.4, cex.lab=1.3,cex=1.2,lwd=2.5,col="red1",lty=2,pch=1, main="C")
lines(c2,type="b",pch=3,lty=3,col="darkblue",lwd=2.5,cex=1.2)
par(mar=c(4, 4, 2, 1))
plot(d1/1000, type="b", ylim=c(0,14.5), xlab="Time (secs)", ylab="", xaxt = 'n', cex.axis=1.4, cex.lab=1.3,cex=1.2,lwd=2.5,col="red1",lty=2,pch=1, main="D")
lines(d2,type="b",pch=3,lty=3,col="darkblue",lwd=2.5,cex=1.2)
mtext("Price", side=2, at=40,line=2.5,cex=1.1)
axis(1, 1:10, cex.axis = 1.4)

fabuła

Powinienem zauważyć, że tak naprawdę nie dołożyłem starań, aby uczynić to tak przyjemnym, jak tylko mogłem i zamiast zrobić ten pierwszy fikcyjny wykres, mogłem po prostu ustawić wystarczająco dużo miejsca w pierwszej klatce. Niestety ustawienie mar () próbuje wypełnić ramkę, a górny margines wpływa na odległość, na którą nie ma etykiety nad wykresem, więc musiałbym iść i zrobić wszystkie moje etykiety za pomocą mtext () lub text () zamiast po prostu użyć główne ustawienie w fabule i nie miałem ochoty tego robić

Jan
źródło
drugi +1 dla grafiki bazowej badass. Na próżno próbowałem napisać coś ładnego za pomocą polecenia layout (). Wrócę tu następnym razem, gdy będę musiał z niego skorzystać.
Chris Beeley,
13

Poleciłbym nauczyć się pakietu graficznego sieci. Mogę zbliżyć się do tego, co chcesz, za pomocą kilku linii. Najpierw spakuj swoje dane w ramkę danych, mniej więcej tak:

dat <- data.frame (x=rep (1:10, 8), y=c(a1, a2, b1, b2, c1, c2, d1, d2),
        var=factor (rep (c("X", "Y"), each=10)),
        graph=factor (rep (c("A", "B", "C", "D"), each=20)))

co daje:

    x           y var graph
1   1 0.556372979   X     A
2   2 0.754257646   X     A
3   3 0.815432905   X     A
4   4 0.559513013   X     A
5   5 0.763368168   X     A
6   6 0.426415259   X     A
7   7 0.597962532   X     A
8   8 0.723780143   X     A
9   9 0.228920116   X     A
10 10 0.607378894   X     A
11  1 0.865114425   Y     A
12  2 0.919804947   Y     A
13  3 0.437003794   Y     A
14  4 0.203349303   Y     A
15  5 0.620425977   Y     A
16  6 0.703170299   Y     A
17  7 0.174297656   Y     A
18  8 0.698144659   Y     A
19  9 0.732527016   Y     A
20 10 0.778057398   Y     A
21  1 0.355583032   X     B
22  2 0.015765144   X     B
23  3 0.315004753   X     B
24  4 0.257723585   X     B
25  5 0.506324279   X     B
26  6 0.028634427   X     B
27  7 0.475360443   X     B
28  8 0.577119754   X     B
29  9 0.709063777   X     B
30 10 0.308695235   X     B
31  1 0.852567748   Y     B
32  2 0.938889121   Y     B
33  3 0.080869739   Y     B
34  4 0.732318482   Y     B
35  5 0.325673156   Y     B
36  6 0.378161864   Y     B
37  7 0.830962248   Y     B
38  8 0.990504039   Y     B
39  9 0.331377188   Y     B
40 10 0.448251682   Y     B
41  1 0.967255983   X     C
42  2 0.722894624   X     C
43  3 0.039523960   X     C
44  4 0.003774719   X     C
45  5 0.218605160   X     C
46  6 0.722304874   X     C
47  7 0.576140686   X     C
48  8 0.108219812   X     C
49  9 0.258440127   X     C
50 10 0.739656846   X     C
51  1 0.528278201   Y     C
52  2 0.104415716   Y     C
53  3 0.966076056   Y     C
54  4 0.504415150   Y     C
55  5 0.655384900   Y     C
56  6 0.247340395   Y     C
57  7 0.193857228   Y     C
58  8 0.019133583   Y     C
59  9 0.799404908   Y     C
60 10 0.159209090   Y     C
61  1 0.422574508   X     D
62  2 0.823192614   X     D
63  3 0.808715876   X     D
64  4 0.770499188   X     D
65  5 0.049138399   X     D
66  6 0.747017767   X     D
67  7 0.239916970   X     D
68  8 0.152777362   X     D
69  9 0.052862276   X     D
70 10 0.937605577   X     D
71  1 0.850112019   Y     D
72  2 0.675407232   Y     D
73  3 0.273276166   Y     D
74  4 0.455995477   Y     D
75  5 0.695497498   Y     D
76  6 0.688414035   Y     D
77  7 0.454013633   Y     D
78  8 0.874853452   Y     D
79  9 0.568746031   Y     D

Następnie użyj sieci xyplot:

library (lattice)
xyplot (y ~ x | graph, groups=var, data=dat, type="o",
        layout=c(1, 4), as.table=T, xlab="Time (secs)", ylab="Price")

co daje ładny wykres, taki jak:

wprowadź opis zdjęcia tutaj

EDYTOWAĆ:

Jeśli chcesz mieć różne symbole i linie i wyświetlać je w swojej legendzie, staje się to skomplikowane, ponieważ dosłownie budujesz legendę sam i musisz wiedzieć, jak uzyskać domyślne kolory sieci, jeśli sam ich nie zastąpisz :

my.text <- levels (dat$var)
my.lty <- c(2, 3)
my.pch <- c(1, 2)
my.col <- trellis.par.get ("superpose.symbol")$col[1:2]
xyplot (y ~ x | graph, groups=var, data=dat, type="o", pch=my.pch, lty=my.lty,
        main="Main Title", layout=c(1, 4), as.table=T, xlab="Time (secs)", ylab="Price",
        key=list (columns=2, text=list (my.text), points=list (pch=my.pch, col=my.col)))

wprowadź opis zdjęcia tutaj

EDYCJA 2:

Możesz uprościć kod i wykres, jeśli dwie kategorie są tak proste jak „X” i „Y”:

xyplot (y ~ x | graph, groups=var, data=dat, type="o", pch=c("X", "Y"), cex=1.25, lty=c(2, 3),
        layout=c(1, 4), as.table=T, xlab="Time (secs)", ylab="Price")

który użyje „X” i „Y” jako symboli punktowych. W ogóle nie potrzebujesz legendy, a możesz poświęcić jeszcze więcej miejsca samym wykresom. (Z drugiej strony możesz nie polubić wyglądu lub może być trudniej ustalić dokładny środek punktu, choć nie jest to tak duży problem, jak to możliwe, ponieważ linia przechodzi przez każdy punkt.)

EDYCJA 3:

W rzeczywistości należy dodać strip=F, strip.left=T,do wykresu, aby umieścić etykiety A, B, C, D po lewej stronie wykresów, co daje więcej miejsca na długim wykresie:

xyplot (y ~ x | graph, groups=var, data=dat, type="o", pch=my.pch, lty=my.lty,
        main="Main Title", layout=c(1, 4), as.table=T, xlab="Time (secs)", ylab="Price",
        strip.left=T, strip=F,
        key=list (columns=2, text=list (my.text), points=list (pch=my.pch, col=my.col),
        lines=list (lty=my.lty, col=my.col)))

wprowadź opis zdjęcia tutaj

Wayne
źródło
@Wayne: Próbuję zachować legendę na wykresie za pomocą argumentów auto.key ze spacjami = "góra", pch = c (1,2), lty = c (2,4), ale wartości pch i Lty wartości nie działają. Ponadto chciałbym zachować X i Y w pozycji poziomej w legendzie. Czy możesz mi w tym pomóc.
samarasa,
Tak. Muszę użyć różnych wartości pch, aby rozróżnić X i Y na papierze. Jestem w stanie użyć różnych wartości pch na wykresie, dodając argument pch (1,4) do xyplot, ale nie odzwierciedla to legendy. Daj mi znać, jak mogę używać różnych wartości pch dla X i Y w legendzie.
samarasa,
OK, wymyśliłem to po powrocie do domu i przeczytałem książkę. Sprawdź edytowaną wersję.
Wayne,
Nie ma problemu. Myślę, że mój EDIT 3 daje najlepszy wykres podobny do (ale lepiej wyglądającego i z większą przestrzenią graficzną niż) oryginału. Nie przesunąłem legendy, co moim zdaniem jest dość proste. Jeśli chcesz, aby linia przechodziła przez punkt w legendzie, myślę, że musiałbyś przenieść ją na następny poziom złożoności i zrobić remis.key rzeczy, które tworzą niestandardowe groby ( gridrzecz: kratownica i ggplot2 budują na siatce) .
Wayne,
Tak, teraz wykres jest lepszy. Byłoby jednak naprawdę dobrze, gdybyśmy przekroczyli linię legendy, tak jak w przypadku normalnej funkcji kreślenia.
samarasa,
9

Oto wersja rozwiązania @ Brandon, ggplot2która zawiera pożądane zachowanie legendy:

dat <- data.frame (x=rep (1:10, 8), y=runif(80),
        var=factor (rep (c("X", "Y"), each=10)),
        graph=factor (rep (c("A", "B", "C", "D"), each=20)))

ggplot(data = dat,aes(x = x, y = y)) + 
    facet_wrap(~graph,nrow = 4) + 
    geom_point(aes(shape = var)) + 
    geom_line(aes(colour = var, group = var)) + 
    labs(x = NULL, y = NULL, shape = "", colour = "") + 
    theme_bw() + 
    opts(legend.position = "top", legend.direction = "horizontal")

wprowadź opis zdjęcia tutaj

Uważam, że legendy są znacznie łatwiejsze ggplot2, ale YMMV.

EDYTOWAĆ

Odpowiadając na kilka pytań w komentarzach. Aby określić konkretne typy punktów lub linii, należy użyć scale_aesthetic_manualgdzie aestheticjest albo shape, linetypeitd Na przykład:

ggplot(data = dat,aes(x = x, y = y)) + 
    facet_wrap(~graph,nrow = 4) + 
    geom_point(aes(shape = var)) + 
    geom_line(aes(colour = var, linetype = var, group = var)) + 
    labs(x = NULL, y = NULL, shape = "", colour = "", linetype = "") + 
    scale_shape_manual(values = 4:5) +
    theme_bw() + 
    opts(legend.position = "top", legend.direction = "horizontal")

Zmiana rozmiaru różnych etykiet osi odbywa się poprzez zmianę ustawień w motywie, zwykle za pomocą opts(). Na przykład:

ggplot(data = dat,aes(x = x, y = y)) + 
    facet_wrap(~graph,nrow = 4) + 
    geom_point(aes(shape = var)) + 
    geom_line(aes(colour = var, linetype = var, group = var)) + 
    labs(x = "X Label", y = "Y Label", shape = "", colour = "", linetype = "") + 
    theme_bw() + 
    opts(legend.position = "top", legend.direction = "horizontal",
         axis.text.x = theme_text(size = 15),axis.title.y = theme_text(size = 25, angle = 90))

Powinieneś naprawdę zagłębić się w stronę internetową i jego książkę, aby uzyskać więcej informacji.

joran
źródło
2
Często wolę ggplot2. W rzeczywistości próbowałem szybko z ggplot2, gdy sieć była zbyt skomplikowana, i odkryłem, że nie mogę do końca przekonać legendy, aby odpowiednio odzwierciedlała style punktów / linii, jeśli chciałbym jawnie wybierać kształty i style linii. Prawdopodobnie zrobiłem to w niewłaściwy sposób i udało mi się pracować na wykresie, ale oszukałem tworzenie legendy ggplot. Czy widzisz, czy to działa dla Ciebie i opublikujesz kod?
Wayne,
@Joran: Próbowałem wymyślić rodzaje linii, typy punktów i kolory, ale bez powodzenia. Czy możesz nam powiedzieć, w jaki sposób możemy zmienić rodzaje linii itp. A także daj nam znać, w jaki sposób możemy zwiększyć rozmiar laboratoriów xiy.
samarasa,
W tej chwili jestem przy telefonie; jeśli @Brandon nie edytuje swojej odpowiedzi, zanim wrócę do domu z tym, czego szukasz, przejdę do niej później wieczorem.
joran
8

Podobnie do odpowiedzi Wayne'a, również użyłbym innego pakietu, a mianowicie ggplot2

library(ggplot2) 

df <- data.frame(
parameter=runif(300),
Time=1:300,
split=sample(c(1:4),300,replace=T),
split2=sample(c(1:2),300,replace=T)
)

ggplot(df, aes(Time, parameter, colour=as.factor(split2))) + 
geom_line() + 
facet_wrap(~split,nrow=4)

Co daje nam wykres taki jak:

wprowadź opis zdjęcia tutaj

Brandon Bertelsen
źródło
1
Lubię siatki w ggplot, ale czy istnieje sposób na wyłączenie jasnoszarego tła?
bluepole,
1
+ opts(panel.background=theme_blank())
Brandon Bertelsen,
1
Jeśli chcesz wprowadzić inne zmiany, możesz wpisać, theme_get()aby zobaczyć, co możesz zmienić. Następnie postępuj zgodnie z tym samym schematem, co mój ostatni komentarz, ustawiając je=theme_blank()
Brandon Bertelsen
2
Zamierzałem sam zrobić ggplot2, ale pomyślałem, że być może kratownica będzie łatwiejszym krokiem. Każdy z nich zapewnia uporządkowany sposób układania takich wykresów. Poprawianie wielu szczegółów może być trudne, ale szybkie uzyskanie atrakcyjnych i czytelnych rzeczy jest łatwe. (Chociaż musisz owinąć głowę, tworząc odpowiednią ramkę danych, z której chcesz wykreślić dane, zamiast po prostu wrzucać rzeczy do wykresu.
Wayne
Odkryłem, że Hadley dostarczył narzędzia do manipulacji danymi w swoich innych pakietach do masowania danych we właściwym kształcie. W razie wątpliwości odpowiedź brzmi zazwyczaj:melt()
Brandon Bertelsen