Ich muss ein Balkendiagramm mit der Anzahl und ein Liniendiagramm mit der Rate in einem Diagramm zeichnen. Ich kann beide getrennt ausführen, aber wenn ich sie zusammenstelle, geom_bar
überlappt sich die Skalierung der ersten Ebene (dh der ) mit der zweiten Schicht (dh die geom_line
).
Kann ich die Achse von geom_line
nach rechts verschieben?
ggplot2
Aufrufe anzuzeigenscale_y_*
, die derzeit aufgerufen wirdsec.axis
.Antworten:
Manchmal möchte ein Kunde zwei y-Skalen. Es ist oft sinnlos, ihnen die "fehlerhafte" Rede zu geben. Aber ich mag es, wenn ggplot2 darauf besteht, die Dinge richtig zu machen. Ich bin sicher, dass ggplot tatsächlich den durchschnittlichen Benutzer über die richtigen Visualisierungstechniken aufklärt.
Vielleicht können Sie Facettierung und Skalierung verwenden, um die beiden Datenreihen zu vergleichen? - siehe zB hier: https://github.com/hadley/ggplot2/wiki/Align-two-plots-on-a-page
quelle
In ggplot2 ist dies nicht möglich, da ich glaube, dass Diagramme mit separaten y-Skalen (keine y-Skalen, die Transformationen voneinander sind) grundlegend fehlerhaft sind. Einige Probleme:
Die sind nicht invertierbar: Wenn ein Punkt im Plotbereich angegeben ist, können Sie ihn nicht eindeutig einem Punkt im Datenbereich zuordnen.
Sie sind im Vergleich zu anderen Optionen relativ schwer richtig zu lesen. Weitere Informationen finden Sie in einer Studie zu Dual-Scale- Datendiagrammen von Petra Isenberg, Anastasia Bezerianos, Pierre Dragicevic und Jean-Daniel Fekete.
Sie können leicht manipuliert werden, um irrezuführen: Es gibt keine eindeutige Möglichkeit, die relativen Skalen der Achsen anzugeben, sodass sie manipuliert werden können. Zwei Beispiele aus dem Junkcharts-Blog: eins , zwei
Sie sind willkürlich: Warum nur 2 Skalen, nicht 3, 4 oder 10?
Vielleicht möchten Sie auch Stephen Fews langwierige Diskussion zum Thema Dual-Scaled Axes in Graphs lesen. Sind sie jemals die beste Lösung? .
quelle
Ab ggplot2 2.2.0 können Sie eine solche Sekundärachse hinzufügen (entnommen aus der Ankündigung von ggplot2 2.2.0 ):
quelle
Mit den obigen Antworten und einigen Feinabstimmungen (und was auch immer es wert ist) können Sie hier zwei Skalen erreichen
sec_axis
:Nehmen Sie einen einfachen (und rein fiktiven) Datensatz an
dt
: Fünf Tage lang wird die Anzahl der Unterbrechungen im Vergleich zur Produktivität verfolgt:(Die Bereiche beider Spalten unterscheiden sich um etwa Faktor 5).
Der folgende Code zeichnet beide Serien, die die gesamte y-Achse belegen:
Hier ist das Ergebnis (über Code + einige Farboptimierungen):
Der Punkt (mit der Ausnahme ,
sec_axis
wenn die Y_SCALE Angabe ist zu multiplizieren jeden Wert die zweite Datenreihe mit 5 , wenn der Serie angeben. Um die Etiketten direkt im sec_axis Definition zu erhalten, braucht es dann dividiert durch 5 (und Formatierung). So Ein entscheidender Teil des obigen Codes befindet sich*5
in der geom_line und~./5
in sec_axis (eine Formel, die den aktuellen Wert.
durch 5 teilt ).Im Vergleich (ich möchte die Ansätze hier nicht beurteilen) sehen zwei Diagramme übereinander so aus:
Sie können selbst beurteilen, welcher die Nachricht besser transportiert („Stören Sie die Menschen bei der Arbeit nicht!“). Ich denke, das ist eine faire Art zu entscheiden.
Der vollständige Code für beide Bilder (es ist nicht wirklich mehr als das, was oben steht, nur vollständig und betriebsbereit) ist hier: https://gist.github.com/sebastianrothbucher/de847063f32fdff02c83b75f59c36a7d Eine ausführlichere Erklärung finden Sie hier: https: // sebastianrothbucher. github.io/datascience/r/visualization/ggplot/2018/03/24/two-scales-ggplot-r.html
quelle
Es gibt häufig vorkommende Duell-y-Achsen, z. B. den Klimatographen , der die monatliche Temperatur und den Niederschlag anzeigt. Hier ist eine einfache Lösung, die von Megatrons Lösung verallgemeinert wird, indem Sie die Untergrenze der Variablen auf etwas anderes als Null setzen können:
Beispieldaten:
Stellen Sie die folgenden zwei Werte auf Werte ein, die nahe an den Datengrenzen liegen (Sie können damit herumspielen, um die Positionen der Diagramme anzupassen; die Achsen sind weiterhin korrekt):
Im Folgenden werden die erforderlichen Berechnungen basierend auf diesen Grenzwerten durchgeführt und der Plot selbst erstellt:
Wenn Sie sicherstellen möchten, dass die rote Linie der rechten y-Achse entspricht, können Sie
theme
dem Code einen Satz hinzufügen :welche färbt die rechte Achse:
quelle
ylim.prim
undylim.sec
.Sie können einen Skalierungsfaktor erstellen, der auf das zweite Geom und die rechte y-Achse angewendet wird. Dies leitet sich aus Sebastians Lösung ab.
Hinweis: Verwenden von
ggplot2
v3.0.0quelle
Das technische Rückgrat für die Lösung dieser Herausforderung wurde vor etwa 3 Jahren von Kohske [ KOHSKE ] bereitgestellt . Das Thema und die technischen Details seiner Lösung wurden hier in Stackoverflow an mehreren Stellen erörtert [IDs: 18989001, 29235405, 21026598]. Daher werde ich nur eine bestimmte Variation und eine erläuternde Anleitung unter Verwendung der obigen Lösungen bereitstellen.
Nehmen wir an, wir haben einige Daten y1 in Gruppe G1, auf die einige Daten y2 in Gruppe G2 in irgendeiner Weise bezogen sind, z. B. Bereich / Skala transformiert oder mit etwas Rauschen. Man möchte also die Daten zusammen auf einem Plot mit der Skala von y1 links und y2 rechts darstellen.
Wenn wir jetzt unsere Daten zusammen mit so etwas zeichnen
es passt nicht gut zusammen, da der kleinere Maßstab y1 offensichtlich durch den größeren Maßstab y2 zusammengebrochen wird .
Der Trick, um dieser Herausforderung zu begegnen, besteht darin, beide Datensätze technisch gegen die erste Skala y1 zu zeichnen , die zweite jedoch gegen eine sekundäre Achse mit Beschriftungen zu melden, die die ursprüngliche Skala y2 zeigen .
Deshalb erstellen wir eine erste Hilfsfunktion CalcFudgeAxis, die Features der neuen Achse berechnet und sammelt, die angezeigt werden sollen. Die Funktion kann nach Belieben geändert werden (diese ordnet y2 nur dem Bereich von y1 zu ).
was einige ergibt:
Jetzt habe ich Kohskes Lösung in die zweite Hilfsfunktion PlotWithFudgeAxis eingewickelt (in die wir das ggplot-Objekt und das Hilfsobjekt der neuen Achse werfen):
Jetzt kann alles zusammengestellt werden: Der folgende Code zeigt, wie die vorgeschlagene Lösung in einer täglichen Umgebung verwendet werden kann . Der Plotaufruf zeichnet jetzt nicht mehr die Originaldaten y2, sondern eine geklonte Version yf (die im vorberechneten Hilfsobjekt FudgeAxis enthalten ist ), die im Maßstab y1 ausgeführt wird . Die ursprüngliche ggplot Objet dann mit manipuliert wird Kohske die Hilfsfunktion PlotWithFudgeAxis eine zweite Achse Erhaltung der Skalen hinzuzufügen y2 . Es zeichnet auch die manipulierte Handlung.
Dies wird nun wie gewünscht mit zwei Achsen dargestellt, y1 links und y2 rechts
Die obige Lösung ist, um es klar zu sagen, ein begrenzter wackeliger Hack. Während es mit dem ggplot-Kernel spielt, werden einige Warnungen ausgegeben, dass wir Post-the-Fact-Skalen usw. austauschen. Es muss mit Vorsicht behandelt werden und kann in einer anderen Einstellung zu unerwünschtem Verhalten führen. Außerdem muss man möglicherweise mit den Hilfsfunktionen herumspielen, um das gewünschte Layout zu erhalten. Die Platzierung der Legende ist ein solches Problem (sie würde zwischen dem Bedienfeld und der neuen Achse platziert; deshalb habe ich sie fallen gelassen). Die Skalierung / Ausrichtung der 2-Achsen ist ebenfalls etwas schwierig: Der obige Code funktioniert gut, wenn beide Skalen die "0" enthalten, andernfalls wird eine Achse verschoben. Also definitiv mit einigen Verbesserungsmöglichkeiten ...
Wenn on das Bild speichern möchte, muss der Anruf in das Gerät open / close gewickelt werden:
quelle
Der folgende Artikel hat mir geholfen, zwei von ggplot2 generierte Diagramme in einer einzelnen Zeile zu kombinieren:
Mehrere Grafiken auf einer Seite (ggplot2) von Cookbook for R.
Und so könnte der Code in diesem Fall aussehen:
quelle
multiplot
stackoverflow.com/a/51220506Für mich war es schwierig, die Transformationsfunktion zwischen den beiden Achsen herauszufinden. Ich habe myCurveFit dafür verwendet.
Die Transformationsfunktion finden
Transformationsfunktion:
f(y1) = 0.025*x + 2.75
Transformationsfunktion:
f(y1) = 40*x - 110
Plotten
Beachten Sie, wie die Transformationsfunktionen im
ggplot
Aufruf verwendet werden, um die Daten "on-the-fly" zu transformieren.Der erste
stat_summary
Aufruf ist derjenige, der die Basis für die erste y-Achse festlegt. Der zweitestat_summary
Aufruf wird aufgerufen, um die Daten zu transformieren. Denken Sie daran, dass alle Daten die erste y-Achse als Basis verwenden. Damit müssen die Daten für die erste y-Achse normalisiert werden. Dazu benutze ich die Transformationsfunktion für die Daten:y=packetOkSinr*40 - 110
Um nun die zweite Achse zu transformieren, verwende ich die entgegengesetzte Funktion innerhalb des
scale_y_continuous
Aufrufs :sec.axis=sec_axis(~.*0.025+2.75, name="y_second")
.quelle
coef(lm(c(-70, -110) ~ c(1,0)))
undcoef(lm(c(1,0) ~ c(-70, -110)))
. Sie könnten eine Hilfsfunktion wieequationise <- 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]]))) }
Wir könnten definitiv ein Grundstück mit zwei Y-Achsen unter Verwendung der Basis-R-Funktion erstellen
plot
.quelle
Sie können
facet_wrap(~ variable, ncol= )
eine Variable verwenden, um einen neuen Vergleich zu erstellen. Es ist nicht auf der gleichen Achse, aber es ist ähnlich.quelle
Ich erkenne Hadley (und andere) an und stimme ihm zu , dass separate Y-Skalen "grundlegend fehlerhaft" sind. Trotzdem - ich wünschte oft, ich
ggplot2
hätte die Funktion - insbesondere dann, wenn die Daten im Großformat vorliegen und ich die Daten schnell visualisieren oder überprüfen möchte (dh nur für den persönlichen Gebrauch).Während die
tidyverse
Bibliothek das Konvertieren der Daten in ein Langformat ziemlich einfach macht (so dass diesfacet_grid()
funktioniert), ist der Prozess immer noch nicht trivial, wie unten dargestellt:quelle
sec_axis
.Die Antwort von Hadley gibt einen interessanten Hinweis auf Stephen Fews Bericht Dual-Scaled Axes in Graphs. Sind sie jemals die beste Lösung? .
Ich weiß nicht, was das OP mit "Zählungen" und "Rate" bedeutet, aber eine schnelle Suche gibt mir Zählungen und Raten , sodass ich einige Daten über Unfälle im nordamerikanischen Bergsteigen 1 erhalte :
Und dann habe ich versucht, das Diagramm so zu erstellen, wie es nur wenige auf Seite 7 des oben genannten Berichts vorgeschlagen haben (und der Aufforderung von OP gefolgt, die Anzahl als Balkendiagramm und die Raten als Liniendiagramm grafisch darzustellen):
Und das ist das Ergebnis:
Aber ich mag es nicht sehr und ich kann nicht einfach eine Legende darauf schreiben ...
1 WILLIAMSON, Jed et al. Unfälle im nordamerikanischen Bergsteigen 2005. The Mountaineers Books, 2005.
quelle
Es scheint eine einfache Frage zu sein, aber es verwirrt um zwei grundlegende Fragen. A) Umgang mit multiskalaren Daten während der Darstellung in einem Vergleichsdiagramm und zweitens B) ob dies ohne einige Faustregelpraktiken der R-Programmierung wie i) Schmelzen von Daten, ii) Facettieren, iii) Hinzufügen möglich ist eine weitere Ebene zu der vorhandenen. Die unten angegebene Lösung erfüllt beide oben genannten Bedingungen, da sie Daten verarbeitet, ohne sie neu skalieren zu müssen, und zweitens werden die genannten Techniken nicht verwendet.
Hier ist das Ergebnis,
Wenn Sie mehr über diese Methode erfahren möchten, folgen Sie bitte dem unten stehenden Link. So zeichnen Sie ein 2-y-Achsendiagramm mit Balken nebeneinander, ohne die Daten neu zu skalieren
quelle
Ich habe diese Antwort gefunden mir am meisten half, fand aber heraus, dass es einige Randfälle gab, die nicht richtig zu behandeln schienen, insbesondere negative Fälle, und auch den Fall, dass meine Limits einen Abstand von 0 hatten (was passieren kann, wenn wir greifen unsere Grenzen von max / min Daten). Tests scheinen darauf hinzudeuten, dass dies konsistent funktioniert
Ich benutze den folgenden Code. Hier nehme ich an, wir haben [x1, x2], die wir in [y1, y2] transformieren wollen. Ich habe damit umgegangen, indem ich [x1, x2] in [0,1] (eine ausreichend einfache Transformation) und dann [0,1] in [y1, y2] transformiert habe.
Die wichtigsten Teile hier sind, dass wir die sekundäre y-Achse mit transformieren
~((.-ylim.prim[1]) *b + ylim.sec[1])
und dann die Umkehrung auf die tatsächlichen Werte anwendeny = ylim.prim[1]+(Temp-ylim.sec[1])/b)
. Das sollten wir auch sicherstellenlimits = ylim.prim
.quelle