Blogul lui Zhenguo Zhang https://fortune9.netlify.app/2026/08/30/r-understanding-position-dodge-and-position-dodge2-in-ggplot2/ –
În ggplot2când se afișează date grupate de-a lungul axelor categoriale (cum ar fi diagrame cu bare grupate, diagrame cu case sau bare de eroare), evitarea orizontală este utilizată pentru a preveni suprapunerea elementelor la fiecare poziție categorială. ggplot2 oferă două funcții principale de poziție de eschiv: position_dodge() şi position_dodge2().
În această postare, vom explora:
- Cum
widthparametrul inposition_dodge()interacționează cu geom-ul părintewidth. - Diferențele de bază dintre
position_dodge2()şiposition_dodge()inclusiv de ce se schimbăwidthînposition_dodge2()adesea nu are efect vizual. - Cum
preserve = "single"se comportă atunci când elementele unei variabile de grup lipsesc la un anumit nivel al axei x.
Definiția termenilor
Pentru a menține explicațiile noastre clare și consecvente pe parcursul acestei postări, definim două concepte cheie:
- nivelul axei x: Valoarea sau categoria discretă pe axa x. În exemplele noastre folosind
mtcarsnivelul axei x estecyl(cu niveluri4,6și8). - variabila de grup: variabila care împarte articolele în subgrupuri la fiecare nivel de axa x, de obicei mapată la un aspect estetic
fillsaucolor. În exemplele noastre, variabila de grup estegear(cu niveluri3,4și5). - elemente eschivate: marcajele vizuale individuale (de ex. bare) corespunzătoare fiecărui nivel al variabilei de grup la un anumit nivel pe axa x.
library(ggplot2) library(patchwork)
1. Cel width Parametrul in position_dodge()
Ce face width controla?
În position_dodge(width = ...), width specifică durata totală de eschivare (interval) pe axa x în care toate elementele eschivate pentru un anumit nivel a axei x sunt dispuse una lângă alta.
În mod implicit, dacă nu furnizați în mod explicit width la position_dodge()ea își moștenește valoarea de la geom-ul părinte (de exemplu, geom_bar() implicit la width = 0.9).
Interacțiunea dintre geom_bar(width) şi position_dodge(width)
geom_bar(width = ...): Setează lățimea fizică totală alocată barelor la fiecare nivel al axei x. Lățimea individuală a barei este derivată prin împărțirea acestei valori la numărul de elemente de la acel nivel al axei x.position_dodge(width = ...): Setează distanța totală pe axa x de-a lungul căreia sunt calculate și distanțate pozițiile centrale ale elementelor evitate.
Ambii parametri folosesc unități de coordonate pe axa x (unde distanța dintre nivelurile discrete axa x adiacente este 1.0).
Să examinăm modul în care variația ambilor parametri afectează aspectul folosind mtcars set de date (media grafică mpg peste nivelul axei x cylcu variabila de grup gear mapat la fill):
# Base plot configuration
base_p <- ggplot(mtcars, aes(x = factor(cyl), y = mpg, fill = factor(gear))) +
labs(x = "Cylinders (x-axis level)", y = "Mean MPG", fill = "Gear (group variable)") +
theme_minimal(base_size = 11)
# Case 1: Default matching widths (0.9 / 0.9)
# Bars touch neatly within each x-axis level
p1 <- base_p +
geom_bar(
stat = "summary",
fun = "mean",
width = 0.9,
position = position_dodge(width = 0.9)
) +
ggtitle("1. Matching widths (0.9 / 0.9)", subtitle = "Bars touch neatly within each x-axis level")
# Case 2: geom_bar width (0.5) < dodge width (0.9)
# Dodging span is 0.9, but bars are narrower -> gaps appear between bars
p2 <- base_p +
geom_bar(
stat = "summary",
fun = "mean",
width = 0.5,
position = position_dodge(width = 0.9)
) +
ggtitle("2. geom_bar(0.5) < dodge(0.9)", subtitle = "Gaps created between dodged elements")
# Case 3: geom_bar width (0.9) > dodge width (0.5)
# Dodging span is narrower than bar widths -> bars overlap
p3 <- base_p +
geom_bar(
stat = "summary",
fun = "mean",
width = 0.9,
position = position_dodge(width = 0.5)
) +
ggtitle("3. geom_bar(0.9) > dodge(0.5)", subtitle = "Dodged elements overlap")
# Case 4: Both changed to 0.6
# Group as a whole is narrower, bars touch, larger separation between x-axis levels
p4 <- base_p +
geom_bar(
stat = "summary",
fun = "mean",
width = 0.6,
position = position_dodge(width = 0.6)
) +
ggtitle("4. Both set to 0.6", subtitle = "Compact cluster, wider space between x-axis levels")
(p1 | p2) / (p3 | p4)

După cum sa demonstrat: – Creștere width în geom_bar() mărește lățimea individuală a elementelor evitate la acel nivel al axei x. – Creste width în position_dodge() mărește intervalul total de eschivare pe care sunt răspândite elementele. – Când ambele valori sunt egale, elementele ocolite din fiecare nivel de axa x se ating între ele fără a se suprapune sau a lăsa goluri.
2. Diferențele între position_dodge2() şi position_dodge()
în timp ce position_dodge() a fost conceput inițial pentru geomuri simple cu poziții cu lățime fixă (cum ar fi geom_bar şi geom_col), position_dodge2() a fost introdus pentru a gestiona geoms cu lățimi variabile sau intervale explicite (xmin la xmax), ca geom_boxplot(), geom_rect()și geom_linerange().
Diferențele cheie:
- Ambalare bazată pe limită vs. Compensarea sloturilor fixe:
position_dodge()împarte lățimea totală de eschivare la nivelul axei x în sloturi fixe și plasează fiecare nivel al variabilei de grup în slotul său desemnat.position_dodge2()împachetează elemente (pentru diferite niveluri ale variabilei de grup) secvenţial unul lângă altul folosind casetele de delimitare ale geoms-urilor.
- The
widthParametrul nu are efect vizual înposition_dodge2()cu Baruri:- Deoarece
position_dodge2()aranjează barele pe baza intervalelor lor de delimitare precalculate, mai degrabă decât să calculeze decalajele slotului central dintr-un interval de eschivare, schimbândwidthînposition_dodge2()nu produce nicio modificare în rezultatul graficului atunci când lățimile barelor sunt deja definite de geom-ul părinte. - Lățimile barelor trebuie controlate direct prin
geom_bar(width = ...).
- Deoarece
- Încorporat
paddingşireverseSprijin:padding: Adaugă spațiu proporțional între elementele eschivate la același nivel al axei x, fără a necesita nepotrivirea manuală a lățimilor de geom și de eschiv.reverse = TRUE: inversează ordinea de reprezentare de la stânga la dreapta a variabilei de grup fără a fi nevoie să se modifice nivelurile factorilor.
Demo: width Nu are efect în position_dodge2()
Mai jos, comparăm position_dodge2(width = 0.3) împotriva position_dodge2(width = 0.9). Observați că cele două diagrame sunt complet identice:
# Changing width in position_dodge2 produces identical output
p_d2_w03 <- base_p +
geom_bar(
stat = "summary",
fun = "mean",
position = position_dodge2(width = 0.3)
) +
ggtitle("position_dodge2(width = 0.3)", subtitle = "Width parameter has no visual effect")
p_d2_w09 <- base_p +
geom_bar(
stat = "summary",
fun = "mean",
position = position_dodge2(width = 0.9)
) +
ggtitle("position_dodge2(width = 0.9)", subtitle = "Identical layout to width = 0.3")
p_d2_w03 | p_d2_w09


Crearea spațiere cu padding și inversarea ordinii cu reverse
În loc să modifice width, position_dodge2() oferă padding şi reverse parametri:
# Using padding and reverse in position_dodge2
p_dodge2_demo <- base_p +
geom_bar(
stat = "summary",
fun = "mean",
position = position_dodge2(padding = 0.2, reverse = TRUE)
) +
labs(
title = "position_dodge2(padding = 0.2, reverse = TRUE)",
subtitle = "Built-in bar padding and reversed order of group variable"
)
p_dodge2_demo


3. Manipularea elementelor lipsă cu preserve = "single"
O diferență funcțională semnificativă între position_dodge() şi position_dodge2() apare atunci când anumite niveluri ale variabilei de grup sunt absente la un nivel specific pe axa x.
Să inspectăm numărul de observații de-a lungul cyl (nivelul axei x) și gear (variabila de grup) in mtcars:
table(mtcars$cyl, mtcars$gear) ## ## 3 4 5 ## 4 1 8 2 ## 6 2 4 1 ## 8 12 0 2
La nivelul axei x cyl = 8variabila de grup gear conţine observaţii pentru angrenaje 3 (12 mașini) și 5 (2 mașini), dar gear = 4 lipsește complet (0 mașini).
Când stabilim preserve = "single" pentru a vă asigura că toate lățimile individuale ale barelor rămân uniforme pe toate nivelurile axei x:
position_dodge(preserve = "single"): Păstrează alocările de slot fixe. Deoarecegear = 4lipsește lacyl = 8lasa a gol gol la mijloc undegear = 4ar locui în mod normal.position_dodge2(preserve = "single"): Păstrează lățimea barei individuale în timp ce recentrând elementele eschivate rămaseîmpachetându-le unul lângă altul fără a lăsa un gol.
# position_dodge with preserve = "single"
p_dodge_single <- base_p +
geom_bar(
stat = "summary",
fun = "mean",
position = position_dodge(preserve = "single")
) +
labs(
title = "position_dodge(preserve = 'single')",
subtitle = "Leaves an empty gap for missing gear = 4 at cyl = 8"
)
# position_dodge2 with preserve = "single"
p_dodge2_single <- base_p +
geom_bar(
stat = "summary",
fun = "mean",
position = position_dodge2(preserve = "single")
) +
labs(
title = "position_dodge2(preserve = 'single')",
subtitle = "Re-centers remaining elements (no gap at cyl = 8)"
)
# Side-by-side comparison
p_dodge_single | p_dodge2_single


Rețineți că dacă setați preserve = „total”, atunci nu veți vedea nicio diferență, deoarece barele sunt reîntinse pentru a vă asigura că barele de la fiecare nivel categorial ocupă toată lățimea atribuită acelui nivel.
Rezumat
| Cazuri de utilizare primară | Geome simple 1D cu lățime fixă (geom_bar, geom_col) |
Interval și geome cu lățime variabilă (geom_boxplot, geom_rect, geom_linerange) și bare |
Rolul de width Parametru |
Setează intervalul total de eschivare pe fiecare nivel al axei x | Nu are niciun efect vizual asupra barelor cu lățime geom predefinită |
Elemente lipsă (preserve="single") |
Lasă slotul gol / gol la nivelul lipsă | Recentrează împreună elementele eschivate rămase |
| Umplutură între elemente | Manual (geom_bar(width) < position_dodge(width)) |
Încorporat prin padding = ... argument |
| Ordine inversă de trasare | Necesită renivelarea variabilei de grup | Încorporat prin reverse = TRUE argument |
– https://fortune9.netlify.app/2026/08/30/r-understanding-position-dodge-and-position-dodge2-in-ggplot2/ –
