Muszę wykreślić wykres słupkowy pokazujący liczby i wykres liniowy pokazujący szybkość wszystko na jednym wykresie, mogę zrobić oba z nich osobno, ale kiedy je złożę, skaluję pierwszą warstwę (tj. geom_bar
) Nakłada się na drugą warstwa (tj. geom_line
).
Czy mogę przesunąć oś geom_line
w prawo?
ggplot2
implementację wewnątrzscale_y_*
, obecnie wywoływanąsec.axis
.Odpowiedzi:
Czasami klient chce dwóch skal y. Przekazanie im „wadliwej” mowy jest często bezcelowe. Ale podoba mi się naleganie ggplot2 na robienie rzeczy we właściwy sposób. Jestem pewien, że ggplot w rzeczywistości kształci przeciętnego użytkownika w zakresie prawidłowych technik wizualizacji.
Może możesz użyć facetingu i skalować za darmo, aby porównać dwie serie danych? - np. spójrz tutaj: https://github.com/hadley/ggplot2/wiki/Align-two-plots-on-a-page
źródło
W ggplot2 nie jest to możliwe, ponieważ uważam, że wykresy z oddzielnymi skalami y (nie skalami y, które są wzajemnymi transformacjami) są zasadniczo wadliwe. Trochę problemów:
Nie są odwracalne: biorąc pod uwagę punkt w przestrzeni wydruku, nie można jednoznacznie odwzorować go z powrotem na punkt w przestrzeni danych.
Są stosunkowo trudne do odczytania poprawnie w porównaniu do innych opcji. Szczegółowe informacje można znaleźć w badaniu na temat wykresów danych w dwóch skalach autorstwa Petry Isenberg, Anastasii Bezerianos, Pierre Dragicevic i Jean-Daniel Fekete
Łatwo nimi manipulować w celu wprowadzenia w błąd: nie ma unikalnego sposobu określenia względnych skal osi, pozostawiając je otwartym na manipulację. Dwa przykłady z bloga Junkcharts: jeden , dwa
Są arbitralne: dlaczego mają tylko 2 skale, a nie 3, 4 lub dziesięć?
Warto również przeczytać obszerną dyskusję Stephena Few na temat podwójnie skalowanych osi na wykresach. Czy są one kiedykolwiek najlepszym rozwiązaniem? .
źródło
Począwszy od ggplot2 2.2.0, możesz dodać oś pomocniczą w ten sposób (zaczerpniętą z ogłoszenia ggplot2 2.2.0 ):
źródło
Biorąc powyższe odpowiedzi i dopracowując (i cokolwiek warto), oto sposób na osiągnięcie dwóch skal poprzez
sec_axis
:Załóżmy prosty (i czysto fikcyjny) zestaw danych
dt
: przez pięć dni śledzi liczbę przerw w porównaniu do wydajności:(zakresy obu kolumn różnią się około 5-krotnie).
Poniższy kod narysuje obie serie, które wykorzystują na całej osi Y:
Oto wynik (powyżej kodu + poprawianie kolorów):
Chodzi o to (oprócz używania
sec_axis
przy określaniu y_scale jest pomnożenie każdej wartości drugiej serii danych przy określaniu serii. Aby uzyskać etykiety bezpośrednio w definicji sec_axis, trzeba ją podzielić przez 5 (i formatowanie). Więc kluczową częścią powyższego kodu jest tak naprawdę*5
geom_line i~./5
sec_axis (formuła dzieląca bieżącą wartość.
przez 5).Dla porównania (nie chcę tutaj oceniać podejść), tak wyglądają dwie wykresy jedna na drugiej:
Możesz sam ocenić, który z nich lepiej przekazuje wiadomość („Nie przeszkadzaj ludziom w pracy!”). To chyba sprawiedliwy sposób na decyzję.
Pełny kod obu obrazów (tak naprawdę nie jest więcej niż powyższy, po prostu kompletny i gotowy do uruchomienia) znajduje się tutaj: https://gist.github.com/sebastianrothbucher/de847063f32fdff02c83b75f59c36a7d Bardziej szczegółowe wyjaśnienie tutaj: https: // sebastianrothbucher. github.io/datascience/r/visualization/ggplot/2018/03/24/two-scales-ggplot-r.html
źródło
Istnieją wspólne przypadki użycia pojedynczych osi, np. Klimatograf pokazujący miesięczną temperaturę i opady. Oto proste rozwiązanie, uogólnione na podstawie rozwiązania Megatron, pozwalające ustawić dolną granicę zmiennych na wartość inną niż zero:
Przykładowe dane:
Ustaw następujące dwie wartości na wartości bliskie limitom danych (możesz się nimi bawić, aby wyregulować pozycje wykresów; osie nadal będą poprawne):
Poniższe dokonuje niezbędnych obliczeń w oparciu o te granice i czyni sam wykres:
Jeśli chcesz się upewnić, że czerwona linia odpowiada prawej osi Y, możesz dodać
theme
zdanie do kodu:który koloruje prawą oś:
źródło
ylim.prim
iylim.sec
.Możesz utworzyć współczynnik skalowania, który zostanie zastosowany do drugiej geom i prawej osi y. Wywodzi się to z rozwiązania Sebastiana.
Uwaga: za pomocą
ggplot2
v3.0.0źródło
Techniczny szkielet rozwiązania tego wyzwania został dostarczony przez Kohske około 3 lata temu [ KOHSKE ]. Temat i szczegóły techniczne jego rozwiązania zostały omówione w kilku przypadkach tutaj na Stackoverflow [ID: 18989001, 29235405, 21026598]. Dlatego przedstawię tylko konkretną odmianę i kilka objaśnień, używając powyższych rozwiązań.
Załóżmy, że mamy pewne dane y1 w grupie G1, z którymi niektóre dane y2 w grupie G2 są w jakiś sposób powiązane, np. Przekształcone zakres / skala lub z dodanym szumem. Tak więc chcemy wykreślić dane razem na jednym wykresie ze skalą y1 po lewej i y2 po prawej.
Jeśli teraz wykreślimy nasze dane razem z czymś takim
nie wyrównuje się ładnie, ponieważ mniejsza skala y1 oczywiście zapada się w wyniku większej skali y2 .
Sztuczka w celu sprostania wyzwaniu polega na technicznym wykreśleniu obu zestawów danych w stosunku do pierwszej skali y1, ale zgłoszenie drugiego w stosunku do osi pomocniczej z etykietami pokazującymi oryginalną skalę y2 .
Dlatego budujemy pierwszą funkcję pomocniczą CalcFudgeAxis, która oblicza i zbiera cechy nowej osi, która ma zostać pokazana. Funkcja może zostać zmieniona na lubianą (ta mapuje po prostu y2 na zakres y1 ).
co daje niektóre:
Teraz zapakowałem rozwiązanie Kohske w drugiej funkcji pomocniczej PlotWithFudgeAxis (do której wrzucamy obiekt ggplot i obiekt pomocniczy nowej osi):
Teraz wszystko można złożyć razem: Poniższy kod pokazuje, w jaki sposób proponowane rozwiązanie można wykorzystać w codziennym środowisku . Wywołanie wydruku nie wykreśla już oryginalnych danych y2, ale sklonowaną wersję yf (przechowywaną wewnątrz wstępnie obliczonego obiektu pomocniczego FudgeAxis ), która działa w skali y1 . Oryginalny obggot objet jest następnie manipulowany za pomocą funkcji pomocniczej Kohske PlotWithFudgeAxis, aby dodać drugą oś zachowującą skale y2 . Przedstawia również wykres zmanipulowany.
Teraz rysuje się zgodnie z potrzebami z dwiema osiami, y1 po lewej i y2 po prawej
Powyższym rozwiązaniem jest, mówiąc krótko, ograniczony chwiejny hack. Kiedy gra z jądrem ggplot, wyświetli ostrzeżenia, że wymieniamy skale post-the-fact itp. Należy się z tym obchodzić ostrożnie i może powodować niepożądane zachowanie w innym otoczeniu. Równie dobrze może być konieczne manipulowanie funkcjami pomocnika, aby uzyskać układ zgodnie z potrzebami. Umieszczenie legendy jest takim problemem (byłoby umieszczone między panelem a nową osią; dlatego ją upuściłem). Skalowanie / wyrównanie 2 osi jest również nieco trudne: powyższy kod działa dobrze, gdy obie skale zawierają „0”, w przeciwnym razie jedna oś zostanie przesunięta. Zdecydowanie z pewnymi możliwościami poprawy ...
Jeśli chcesz zapisać zdjęcie, musisz zawinąć połączenie w urządzenie otwierające / zamykające:
źródło
Poniższy artykuł pomógł mi połączyć dwa wykresy wygenerowane przez ggplot2 w jednym wierszu:
Wiele wykresów na jednej stronie (ggplot2) według Cookbook for R
A oto, jak może wyglądać kod w tym przypadku:
źródło
multiplot
stackoverflow.com/a/51220506Dla mnie trudną częścią było ustalenie funkcji transformacji między dwiema osiami. Kiedyś myCurveFit za to.
Znalezienie funkcji transformacji
funkcja transformacji:
f(y1) = 0.025*x + 2.75
funkcja transformacji:
f(y1) = 40*x - 110
Konspiratorstwo
Zwróć uwagę, w jaki sposób funkcje transformacji są używane w
ggplot
wywołaniu do przekształcania danych „w locie”Pierwsze
stat_summary
wywołanie to takie, które ustawia podstawę dla pierwszej osi y. Drugiestat_summary
połączenie jest wywoływane w celu przekształcenia danych. Pamiętaj, że wszystkie dane przyjmą za podstawę pierwszą oś Y. Tak więc dane muszą zostać znormalizowane dla pierwszej osi Y. Aby to zrobić, używam funkcji transformacji danych:y=packetOkSinr*40 - 110
Teraz przekształcić drugą oś korzystać z funkcji w przeciwną
scale_y_continuous
połączenia:sec.axis=sec_axis(~.*0.025+2.75, name="y_second")
.źródło
coef(lm(c(-70, -110) ~ c(1,0)))
icoef(lm(c(1,0) ~ c(-70, -110)))
. Możesz zdefiniować funkcję pomocnika, taką jakequationise <- function(range = c(-70, -110), target = c(1,0)){ c = coef(lm(target ~ range)) as.formula(substitute(~ a*. + b, list(a=c[[2]], b=c[[1]]))) }
Zdecydowanie mógłby zbudować fabułę z podwójnymi Y osiach zastosowaniem zasady R funtion
plot
.źródło
Możesz użyć
facet_wrap(~ variable, ncol= )
zmiennej, aby utworzyć nowe porównanie. Nie jest na tej samej osi, ale jest podobny.źródło
Potwierdzam i zgadzam się z Hadleyem (i innymi), że osobne skale y są „zasadniczo wadliwe”. To powiedziawszy - często chciałbym
ggplot2
mieć tę funkcję - szczególnie, gdy dane są w formacie szerokim i szybko chcę je wizualizować lub sprawdzić (tj. Wyłącznie do użytku osobistego).Chociaż
tidyverse
biblioteka ułatwia konwersję danych do formatu długiego (takiego,facet_grid()
który zadziała), proces ten nadal nie jest trywialny, jak pokazano poniżej:źródło
sec_axis
.Odpowiedź Hadleya zawiera interesujące odniesienie do raportu Stephena Fewa Osie z podwójną skalą na wykresach Czy są kiedykolwiek najlepszym rozwiązaniem? .
Nie wiem, co oznacza OP z „liczeniem” i „oceną”, ale szybkie wyszukiwanie daje mi Liczenie i stawki , więc otrzymuję dane o wypadkach w North American Mountaineering 1 :
A potem próbowałem zrobić wykres, jak sugeruje niewielu na stronie 7 wyżej wymienionego raportu (i zgodnie z prośbą OP o wykreślenie zliczeń jako wykresu słupkowego, a stawek jako wykresu liniowego):
I to jest wynik:
Ale nie bardzo mi się to podoba i nie jestem w stanie łatwo napisać na nim legendy ...
1 WILLIAMSON, Jed i in. Wypadki w North American Mountaineering 2005. The Mountaineers Books, 2005.
źródło
Wydaje się, że jest to proste pytanie, ale porusza się wokół 2 podstawowych pytań. A) Jak radzić sobie z danymi wieloskalowymi podczas prezentacji na wykresie porównawczym, a po drugie, B) czy można tego dokonać bez pewnych praktyk dotyczących programowania R, takich jak i) topienie danych, ii) faceting, iii) dodawanie kolejna warstwa do istniejącej. Rozwiązanie podane poniżej spełnia oba powyższe warunki, ponieważ dotyczy danych bez konieczności ich ponownego skalowania, a po drugie, wspomniane techniki nie są stosowane.
Oto wynik
Jeśli chcesz dowiedzieć się więcej o tej metodzie, kliknij poniższy link. Jak wykreślić wykres osi 2-y z pasami obok siebie bez ponownego skalowania danych
źródło
Znalazłem tę odpowiedź , która najbardziej mi pomogła, ale okazało się, że były pewne przypadki krawędzi, które nie wydawały się poprawnie obsługiwane, w szczególności przypadki negatywne, a także przypadek, w którym moje granice miały 0 odległości (co może się zdarzyć, jeśli będziemy chwytać nasze limity od maks. / min danych). Testy wydają się wskazywać, że działa to konsekwentnie
Używam następującego kodu. Zakładam, że mamy [x1, x2], które chcemy przekształcić w [y1, y2]. Sposób, w jaki sobie z tym poradziłem, polegał na przekształceniu [x1, x2] na [0,1] (dość prosta transformaton), a następnie [0,1] na [y1, y2].
Kluczowe są tutaj to, że transformujemy pomocniczą oś y za pomocą,
~((.-ylim.prim[1]) *b + ylim.sec[1])
a następnie stosujemy odwrotność do rzeczywistych wartościy = ylim.prim[1]+(Temp-ylim.sec[1])/b)
. Powinniśmy również to zapewnićlimits = ylim.prim
.źródło