ggplot2 בונה גרפים משכבות
ggplot2 היא חבילת השרטוט הנפוצה ביותר ב-R, והסיבה שאנשים נשבעים בה היא רעיון עיצובי: הדקדוק של הגרפיקה (grammar of graphics). Base R נותן לכם פונקציה אחת לכל תרשים, plot(), hist(), barplot(), ולכל אחת ארגומנטים משלה. ggplot2 נותנת לכם במקום זאת קבוצה קטנה של חלקים שאפשר להרכיב: מערך נתונים, מיפוי מעמודות לתכונות חזותיות ושכבות ציור, שמתחברים עם + לכל תרשים. למדו את הדקדוק פעם אחת, וכל סוג תרשים חדש הוא אותו משפט עם מילה אחת שהוחלפה. כבונוס, ברירות המחדל (רקע אפור, צירים הגיוניים, מקרא אוטומטי) נראות ייצוגיות בלי שום מאמץ עיצובי.
זו חבילת הרחבה, ולכן היא צריכה התקנה חד-פעמית וטעינה בכל סשן:
install.packages("ggplot2") # once, on your machine
library(ggplot2) # at the top of every script that uses it
ציפייה אחת שכדאי להכיר מראש: ggplot2 רוצה data frame (לא וקטורים נפרדים), רצוי בפורמט long מסודר: שורה אחת לכל תצפית, עמודה אחת לכל משתנה. אם הנתונים שלכם בפורמט wide, pivot שלהם לפורמט long קודם בדרך כלל מעלים את מה שנראה כמו בעיית שרטוט.
המודל המנטלי: נתונים, מיפוי, גיאומטריה
כל ggplot עונה על שלוש שאלות, אחת לכל חלק:
- נתונים: איזה data frame?
ggplot(mtcars, ...) - מיפוי: אילו עמודות מניעות אילו תכונות חזותיות?
aes(x = wt, y = hp) - גיאומטריה: איך לצייר את התצפיות?
+ geom_point()
הנה האנטומיה, רכיב אחר רכיב:
ggplot(mtcars, aes(x = wt, y = hp)) +
geom_point()
ggplot(mtcars, ...)מתחילה גרף שנתוני ברירת המחדל שלו הםmtcars. בעצמה היא מציירת לוח אפור ריק: עדיין אין שכבות.aes(x = wt, y = hp)הוא המיפוי האסתטי: המיקום האופקי מגיע מהעמודהwt, המיקום האנכי מ-hp. שימו לב שכותבים שמות עמודות חשופים, לאmtcars$wt: המיפוי מוערך בתוך הנתונים שסיפקתם.+ geom_point()מוסיפה שכבה שמציירת כל שורה כנקודה. ה-+הוא באמת חיבור של שכבות: הגרף הוא אובייקט שבונים בהדרגה, ואפשר להמשיך להוסיף, geom נוסף, תוויות, ערכת עיצוב, כל אחד עם עוד+.
הריצו את זה ותקבלו את אותו תרשים פיזור של משקל מול כוחות סוס כמו בגרסת base R במדריך לתרשים פיזור, על לוח אפור עם קווי רשת לבנים. החליפו את geom_point() ב-geom_line() ואותו מיפוי הופך לתרשים קווי: זה הדקדוק שעושה את העבודה שלו.
ה-geoms שבאמת תשתמשו בהם
תריסר geoms מכסים כמעט את כל העבודה היומיומית:
geom_point() # scatter plot: two numeric variables
geom_line() # line chart: trends over an ordered variable
geom_col() # bar chart from pre-computed heights (needs y)
geom_bar() # bar chart that counts raw rows for you (no y)
geom_histogram() # distribution of one numeric variable (set binwidth)
geom_boxplot() # distributions compared across groups
geom_smooth() # fitted trend line; method = "lm" for straight
שכבות נערמות זו על זו, ושם ggplot2 מתחילה לנצח את base R ביכולת הביטוי: geom_point() + geom_smooth(method = "lm") הוא תרשים פיזור עם קו רגרסיה וגם רצועת ביטחון, בשורה קריאה אחת. מכיוון שגרפים הם אובייקטים, אפשר גם לשמור בסיס ולהסתעף ממנו:
p <- ggplot(mtcars, aes(x = wt, y = hp)) + geom_point()
p + geom_smooth(method = "lm") # one variant
p + geom_smooth() # another (loess curve)
מיפוי מול הגדרה: הבלבול הקלאסי של aes()
הטעות היחידה שכל מתחיל ב-ggplot2 עושה, בדרך כלל בשבוע הראשון: לשים צבע מילולי בתוך aes(). הכלל קצר, בתוך aes() פירושו "משתנה עם הנתונים"; מחוץ לו פירושו "הגדרה קבועה", ושני המיקומים עושים דברים שונים לגמרי:
# MAPPING: color varies by a column - each cylinder count gets its own
# color, and a legend appears automatically
ggplot(mtcars, aes(x = wt, y = hp, color = factor(cyl))) +
geom_point(size = 2)
# SETTING: every point is literally steelblue - no legend, no mapping
ggplot(mtcars, aes(x = wt, y = hp)) +
geom_point(color = "steelblue", size = 2)
והמלכודת עצמה:
# WRONG: "blue" inside aes() is treated as data, not as a color
ggplot(mtcars, aes(x = wt, y = hp, color = "blue")) +
geom_point()
זה מצייר נקודות בצבע ורוד-סלמון עם מקרא שהערך היחיד בו מסומן "blue". למה: aes() ממפה עמודות לתכונות, ולכן color = "blue" יוצר עמודה מזויפת עם קטגוריה אחת שהערך שלה הוא המילה "blue" בכל מקום, ו-ggplot מקצה לקטגוריה הזו את צבע ברירת המחדל הראשון שלה, שבמקרה הוא סלמון אדמדם. אם התכוונתם "תצבעו את הנקודות בכחול", הצבע הולך מחוץ למיפוי: geom_point(color = "blue"). אותו כלל חל על size, shape, fill ו-alpha. (שימו לב גם ל-factor(cyl) בדוגמת המיפוי: cyl מספרי, ועטיפה שלו ב-factor() מבקשת צבעים נפרדים לכל קבוצה במקום מדרג צבעים רציף.)
תוויות, facets וערכות עיצוב
labs() נותנת שם לכל דבר במקום אחד, וגרף לא גמור עד שיש לו תוויות אמיתיות:
ggplot(mtcars, aes(x = wt, y = hp, color = factor(cyl))) +
geom_point(size = 2) +
labs(title = "Horsepower vs. weight",
x = "Weight (1000 lbs)",
y = "Horsepower",
color = "Cylinders")
Facets הן תכונת הדגל של ggplot2: פיצול גרף אחד לריבוי גרפים קטנים, לוח אחד לכל קבוצה, עם צירים משותפים כך שהלוחות מושווים בהגינות:
ggplot(mtcars, aes(x = wt, y = hp)) +
geom_point() +
facet_wrap(~ cyl)
מופיעים שלושה לוחות, אחד לכל אחת מהמכוניות עם 4, 6 ו-8 צילינדרים, מסודרים ברשת עם ערך הקבוצה ככיתוב מעל כל לוח. ב-base R זה מעשה להטוטנות עם par(mfrow) וגבולות משותפים ידניים; כאן זו שורה אחת. Facets מתגמלים נתונים מסודרים, ולכן ggplot2 משתלבת באופן טבעי כל כך עם צינור של dplyr: סננו וסכמו, ואז העבירו את התוצאה ישר ל-ggplot().
ערכות עיצוב (themes) מעצבות מחדש את כל מה שאינו נתונים בקריאה אחת: + theme_minimal() (רקע לבן ונקי), + theme_bw(), + theme_classic() (רק צירים, בלי רשת), או ברירת המחדל האפורה. בחרו אחת לכל פרויקט והיו עקביים: דוח שבו כל האיורים חולקים ערכת עיצוב נקרא כמסמך אחד ולא כאלבום גזירים.
שמירה עם ggsave(), ומתי base R עדיין בסדר
ggsave() כותבת את הגרף האחרון לדיסק, ומסיקה את הפורמט מסיומת הקובץ:
ggsave("hp-vs-weight.png", width = 8, height = 5) # last plot shown
ggsave("hp-vs-weight.pdf", plot = p, width = 8, height = 5) # a saved object
width ו-height הם באינצ'ים כברירת מחדל; הגדירו אותם במפורש, כי גדלי הגופנים משתנים לפי ממדי הפלט, וברירות המחדל כמעט אף פעם לא מתאימות למקום שאליו האיור הולך.
ולגבי מתי לטרוח: למבט של חמש שניות על משתנה אחד במהלך ניתוח, plot() של base R וחברותיה דורשות פחות הקלדה ואפס תלויות: אין פרס על שימוש ב-ggplot2 בכל מקום. ggplot2 מצדיקה את עצמה ברגע שאיור כולל קבוצות, מקראות, facets או קהל: הדקדוק גדל למורכבות שהשרטוט הבסיסי מתמודד איתה רק במאמץ.
מה לקחת מכאן
- ggplot2 מרכיבה כל תרשים מנתונים + מיפוי
aes()+ שכבות geom, שמחוברים עם+; למדו את הדקדוק פעם אחת והשתמשו בו לכל סוג תרשים. aes()ממפה עמודות לתכונות חזותיות: שמות עמודות חשופים, שמוערכים בתוך ה-data frame שלכם.- בתוך
aes()= משתנה עם הנתונים (ומקבל מקרא); מחוץ לו = הגדרה קבועה.aes(color = "blue")הוא הבאג הקלאסי. labs()לכותרות,facet_wrap(~ group)לריבוי גרפים קטנים,theme_minimal()וחברותיה לעיצוב,ggsave()עם ממדים מפורשים לייצוא.- מבט מהיר לבד: base R. קבוצות, facets או קהל: ggplot2.
בזה נסגר הפרק על שרטוט. מכאן, הצעד הטבעי הבא הוא סטטיסטיקה תיאורית, לתת מספרים לצורות שהגרפים האלה חושפים.
שאלות נפוצות
מה זה ggplot2 ב-R?
ggplot2 היא חבילת השרטוט הפופולרית ביותר ב-R. במקום פונקציה אחת לכל סוג תרשים, מרכיבים כל גרף מאותם שלושה חלקים: data frame, מיפוי aes() מעמודות לתכונות חזותיות, ושכבה אחת או יותר של geom_*(), שמחוברים עם +. היא חלק מה-tidyverse.
איך מתקינים את ggplot2?
הריצו install.packages("ggplot2") פעם אחת, ואז library(ggplot2) בראש כל סקריפט שמשתמש בה. ההתקנה שמה את החבילה על המחשב שלכם; library() טוענת אותה לסשן הנוכחי.
מה עושה aes() ב-ggplot2?
aes() ממפה עמודות בנתונים שלכם לתכונות חזותיות: aes(x = wt, y = hp, color = factor(cyl)) אומר שהמיקום האופקי מגיע מ-wt, המיקום האנכי מ-hp, וצבע הנקודה ממספר הצילינדרים. כל מה שבתוך aes() משתנה עם הנתונים; כל מה שמחוצה לו הוא הגדרה קבועה.
למה הנקודות שלי ב-ggplot לא בצבע שביקשתי?
שמתם את הצבע בתוך aes(): aes(color = "blue") לא קובע צבע, הוא ממפה קטגוריה מומצאת בשם "blue", ולכן ggplot בוחרת צבע ברירת מחדל משלה ומוסיפה מקרא. כדי לקבוע צבע מילולי, שימו אותו מחוץ למיפוי: geom_point(color = "blue").