言坐標(biāo)軸范圍設(shè)置:從xlim/ylim到coord_cartesian的完整指南)
坐標(biāo)軸范圍大概是數(shù)據(jù)可視化里最容易被當(dāng)成“小事”的參數(shù)了。很多人畫(huà)圖時(shí)不看默認(rèn)的xlim和ylim直到圖出來(lái)才發(fā)現(xiàn)主體數(shù)據(jù)被一個(gè)離群點(diǎn)壓成一條線或者兩組曲線因?yàn)樽鴺?biāo)范圍不一致根本沒(méi)法放在一起比。這篇文章就把“使用xlim(x1,x2)設(shè)定橫坐標(biāo)范圍、使用ylim(y1,y2)設(shè)定縱坐標(biāo)范圍”這件事徹底講透怎么用、什么時(shí)候必須用、以及比參數(shù)本身更重要的——修改坐標(biāo)范圍到底會(huì)不會(huì)改變統(tǒng)計(jì)結(jié)果。這個(gè)主題適合三類(lèi)人剛開(kāi)始用R畫(huà)圖、總被默認(rèn)坐標(biāo)軸坑到的初學(xué)者能用ggplot2和base繪圖但說(shuō)不清xlim與coord_cartesian區(qū)別的進(jìn)階用戶以及經(jīng)常做數(shù)據(jù)匯報(bào)、需要讓圖表更“誠(chéng)實(shí)”的分析師。我盡量用實(shí)際操作說(shuō)話每個(gè)結(jié)論都對(duì)應(yīng)一段可復(fù)現(xiàn)代碼。1. 坐標(biāo)范圍是數(shù)據(jù)可視化的“取景框”1.1 自動(dòng)坐標(biāo)范圍到底是怎么算出來(lái)的先問(wèn)一個(gè)很多人沒(méi)想過(guò)的問(wèn)題不寫(xiě)xlim和ylim時(shí)R到底怎么決定坐標(biāo)軸范圍答案是它并不直接取數(shù)據(jù)的最小值和最大值而是取一個(gè)“看起來(lái)舒服”的擴(kuò)展區(qū)間。base R里默認(rèn)的坐標(biāo)軸風(fēng)格是xaxsr、yaxsr。這個(gè)“r”代表range意思是R會(huì)在數(shù)據(jù)最小值、最大值的基礎(chǔ)上各向外擴(kuò)展約4%的留白。舉個(gè)例子如果x數(shù)據(jù)是0到10默認(rèn)橫軸范圍不會(huì)是精確的0到10而大約是-0.4到10.4。這個(gè)設(shè)計(jì)的本意是防止散點(diǎn)或柱子貼到坐標(biāo)軸上視覺(jué)上更透氣。但你發(fā)現(xiàn)問(wèn)題了嗎自動(dòng)范圍完全由數(shù)據(jù)決定而不是由你想表達(dá)的信息決定。數(shù)據(jù)里有一個(gè)異常大值坐標(biāo)范圍就被拉得很寬剩下的99個(gè)點(diǎn)全擠在一個(gè)小角落里。數(shù)據(jù)分布范圍是0到1中間有個(gè)1000默認(rèn)圖出來(lái)主體部分看起來(lái)就是一條貼在x軸上的直線。這不是畫(huà)圖錯(cuò)誤是“取景框”選錯(cuò)了。1.2 四種必須手動(dòng)調(diào)整坐標(biāo)范圍的場(chǎng)景根據(jù)我自己的使用經(jīng)驗(yàn)手動(dòng)設(shè)置xlim/ylim基本逃不出下面四種場(chǎng)景場(chǎng)景一剔除離群點(diǎn)對(duì)視野的污染。數(shù)據(jù)里有極端值但你關(guān)心的主體區(qū)域在正常范圍內(nèi)這時(shí)把坐標(biāo)范圍限定到合理區(qū)間主體數(shù)據(jù)立刻“顯形”。場(chǎng)景二局部放大。數(shù)據(jù)整體跨度很大你想單獨(dú)看0到1區(qū)間、或者50到60區(qū)間的細(xì)節(jié)就需要用xlim把橫軸裁到對(duì)應(yīng)范圍。場(chǎng)景三多圖對(duì)比時(shí)統(tǒng)一坐標(biāo)。兩張圖放在一起如果各自的坐標(biāo)范圍不同視覺(jué)上的“高低差異”可能完全是一種錯(cuò)覺(jué)。固定坐標(biāo)范圍后才能看出真正的相對(duì)差異。場(chǎng)景四讓圖形符合閱讀預(yù)期。柱狀圖要從0開(kāi)始否則柱子高度的比例會(huì)誤導(dǎo)讀者折線圖反而經(jīng)常裁剪掉零基線用來(lái)放大波動(dòng)的細(xì)節(jié)。這些都需要手動(dòng)設(shè)定。2. 從參數(shù)到函數(shù)xlim/ylim的兩種打開(kāi)方式2.1 base R繪圖函數(shù)里的xlim/ylim參數(shù)在base R里xlim和ylim通常是繪圖函數(shù)的參數(shù)不是獨(dú)立函數(shù)。最常見(jiàn)的寫(xiě)法是plot()x - runif(50, 0, 10) y - x rnorm(50, 0, 2) # 默認(rèn)坐標(biāo)范圍 plot(x, y) # 手動(dòng)設(shè)定橫軸0到10縱軸-5到15 plot(x, y, xlim c(0, 10), ylim c(-5, 15))注意參數(shù)的格式必須是一個(gè)長(zhǎng)度為2的數(shù)值向量即c(下限, 上限)。ggplot2里可以寫(xiě)成xlim(0, 10)這種函數(shù)調(diào)用的形式但base R里寫(xiě)成xlim(0, 10)會(huì)報(bào)錯(cuò)因?yàn)閜lot()的xlim參數(shù)期待一個(gè)向量。hist()、boxplot()、barplot()、stripchart()等高級(jí)繪圖函數(shù)也都接受xlim和ylim參數(shù)。有一個(gè)小技巧如果你只想固定下限或上限另一側(cè)可以用Inf。比如xlim c(0, Inf)表示橫軸從0開(kāi)始上限交給R自動(dòng)決定這在把坐標(biāo)軸對(duì)齊到零點(diǎn)時(shí)很常用。還有一個(gè)冷知識(shí)指定了xlim之后base R默認(rèn)仍然會(huì)做4%的擴(kuò)展。也就是說(shuō)plot(x, y, xlim c(0, 10))畫(huà)出來(lái)的橫軸并不是精確的0到10而是大約-0.4到10.4。如果你必須讓坐標(biāo)軸嚴(yán)格落在0和10上要加上x(chóng)axs i和yaxs i。這個(gè)“i”是internal的意思表示坐標(biāo)軸精確貼合指定范圍。plot(x, y, xlim c(0, 10), ylim c(-5, 15), xaxs i, yaxs i)2.2 ggplot2中的xlim()和ylim()函數(shù)在ggplot2里xlim和ylim是真正的函數(shù)而且有兩種使用方式library(ggplot2) df - data.frame(x runif(50, 0, 10), y runif(50, 0, 10)) # 方式一連續(xù)兩個(gè)參數(shù) ggplot(df, aes(x, y)) geom_point() xlim(0, 10) # 方式二傳入一個(gè)長(zhǎng)度為2的向量 ggplot(df, aes(x, y)) geom_point() xlim(c(0, 10))這兩種寫(xiě)法完全等價(jià)。xlim(0, 10)本質(zhì)上是對(duì)x軸scale的快捷方式等同于scale_x_continuous(limits c(0, 10))。ylim同理。但這里藏著一個(gè)關(guān)鍵區(qū)別很多人在這里踩坑ggplot2的xlim()會(huì)直接丟棄范圍之外的數(shù)據(jù)行然后再做統(tǒng)計(jì)和繪圖。也就是說(shuō)geom_smooth()的擬合線、geom_density()的密度曲線都是基于截取后的子集重新計(jì)算的。如果你只想“放大看”完整數(shù)據(jù)里的某個(gè)局部而不是重新分析子集xlim()不是最好的選擇應(yīng)該用coord_cartesian(xlim c(...))這個(gè)區(qū)別我后面專門(mén)講。2.3 低層控制刻度軸與畫(huà)布邊界base R里還有一種進(jìn)階玩法不滿足于“設(shè)定范圍自動(dòng)刻度”而是自己控制刻度的位置和標(biāo)簽。方法是先畫(huà)圖然后調(diào)用axis()函數(shù)。set.seed(1) x - runif(100, 0, 100) y - x rnorm(100, 0, 10) plot(x, y, xlim c(0, 100), ylim c(0, 120), xaxt n) axis(1, at c(0, 25, 50, 75, 100), labels c(0, 25, 50, 75, 100))xaxt n表示先隱藏默認(rèn)的x軸刻度然后你用axis()自己指定刻度線的位置。這在做論文圖、報(bào)告圖時(shí)特別有用因?yàn)镽自動(dòng)選的刻度經(jīng)常不符合出版要求比如你想要0、20、40、60、80、100這樣的刻度R默認(rèn)可能給出0、25、50、75、100。另外低層繪圖函數(shù)lines()、points()、abline()本身沒(méi)有xlim參數(shù)它們畫(huà)線時(shí)不關(guān)心坐標(biāo)范圍畫(huà)完超出邊框的內(nèi)容會(huì)被直接裁剪掉。想讓某些元素不受坐標(biāo)范圍限制可以設(shè)置par(xpd TRUE)這樣圖形可以畫(huà)到繪圖區(qū)域外面去處理圖例、標(biāo)注時(shí)經(jīng)常用到。3. 三個(gè)實(shí)戰(zhàn)場(chǎng)景坐標(biāo)范圍該這么設(shè)3.1 裁剪離群點(diǎn)讓主體數(shù)據(jù)顯形先構(gòu)造一個(gè)典型場(chǎng)景100個(gè)點(diǎn)均勻分布在0到1之間再加一個(gè)離群點(diǎn)1000。set.seed(123) x - c(runif(100, 0, 1), 1000) y - c(runif(100, 0, 1), 1000) # 默認(rèn)圖主體數(shù)據(jù)被壓成左下角一團(tuán) plot(x, y) # 手動(dòng)設(shè)定范圍看清主體 plot(x, y, xlim c(0, 1.2), ylim c(0, 1.2), pch 16, col steelblue)不設(shè)置坐標(biāo)范圍時(shí)x軸會(huì)跑到1000附近0到1之間的100個(gè)點(diǎn)擠得連形狀都看不出來(lái)。設(shè)置xlim和ylim后離群點(diǎn)被“擠出”視野剩下的點(diǎn)分布在屏幕中央規(guī)律一目了然。但我必須提醒這里只是“視野上”忽略了離群點(diǎn)數(shù)據(jù)本身還在。后續(xù)如果做回歸、算相關(guān)系數(shù)1000這個(gè)值仍然會(huì)參與計(jì)算。坐標(biāo)范圍和數(shù)據(jù)分析是兩個(gè)維度的事不要用畫(huà)圖參數(shù)代替數(shù)據(jù)清洗。3.2 固定坐標(biāo)范圍讓多圖對(duì)比不騙人做分組對(duì)比時(shí)最忌諱的就是每張子圖的坐標(biāo)范圍各自為政。人的視覺(jué)對(duì)“相對(duì)位置”極其敏感如果A組的圖縱軸是0到50B組的圖縱軸是0到100B組數(shù)據(jù)在視覺(jué)上會(huì)被“壓縮”看起來(lái)比A組平緩很多但這不是數(shù)據(jù)的真實(shí)差異而是坐標(biāo)范圍造成的錯(cuò)覺(jué)??匆粋€(gè)最樸素的例子set.seed(2024) a - rnorm(50, mean 5, sd 1) b - rnorm(50, mean 6, sd 1) par(mfrow c(1, 2)) plot(a, ylim c(0, 10), main A組) plot(b, ylim c(0, 10), main B組) par(mfrow c(1, 1))兩幅圖都限定ylim為0到10A組和B組之間的均值差異就可以直接通過(guò)點(diǎn)的高低比較。如果讓R自動(dòng)決定坐標(biāo)范圍A組可能顯示為0到8B組顯示為2到10粗看會(huì)以為兩組波動(dòng)程度差距很大實(shí)際上標(biāo)準(zhǔn)差幾乎一樣。ggplot2里對(duì)應(yīng)的操作是facet_wrap()或facet_grid()中的scales參數(shù)。scales fixed默認(rèn)值就是所有子圖共用同一個(gè)坐標(biāo)范圍這是對(duì)比圖的安全選擇scales free則允許每個(gè)子圖自己決定范圍用于數(shù)據(jù)量級(jí)差異過(guò)大、放在一起根本看不見(jiàn)的情況。我的經(jīng)驗(yàn)是優(yōu)先f(wàn)ixed只有確實(shí)有子圖被壓扁時(shí)才用free。3.3 局部放大同一組數(shù)據(jù)的不同區(qū)間有一類(lèi)場(chǎng)景很常見(jiàn)數(shù)據(jù)從0到100你既想看頭部0到10的細(xì)節(jié)又想看中間40到60的趨勢(shì)。用subset篩數(shù)據(jù)再畫(huà)圖當(dāng)然可以但有一個(gè)問(wèn)題只要數(shù)據(jù)一變映射到坐標(biāo)軸上的擬合線、置信區(qū)間都會(huì)基于子集重新計(jì)算已經(jīng)不是原始數(shù)據(jù)在這些區(qū)間上的表現(xiàn)了。更穩(wěn)妥的做法是畫(huà)兩次原數(shù)據(jù)圖只改xlimset.seed(10) x - seq(0, 100, length.out 200) y - sin(x / 10) rnorm(200, 0, 0.1) # 看0到10區(qū)間 plot(x, y, xlim c(0, 10)) # 看40到60區(qū)間 plot(x, y, xlim c(40, 60))這樣能保證兩次展示的是同一份數(shù)據(jù)、同一個(gè)坐標(biāo)系只是“取景框”不同。你會(huì)發(fā)現(xiàn)0到10區(qū)間里的鋸齒波動(dòng)在完整視圖里根本看不出來(lái)。局部放大不是為了隱瞞什么而是讓讀者注意到整體圖上被淹沒(méi)的細(xì)節(jié)。這個(gè)需求在ggplot2里同樣建議配合geom_smooth一起理解。如果你用xlim(40, 60)擬合線只基于40到60的數(shù)據(jù)重新算如果你用coord_cartesian(xlim c(40, 60))擬合線仍然基于全部200個(gè)點(diǎn)只是觀察窗口縮小了。后者才真正做到“放大同一份數(shù)據(jù)”。4. 五個(gè)坐標(biāo)軸范圍的坑每個(gè)我都踩過(guò)4.1 xlim截?cái)鄶?shù)據(jù)coord_cartesian縮放視圖這是ggplot2用戶最容易踩的坑我單獨(dú)放在第一個(gè)講。很多人的直覺(jué)是xlim(0, 10)就是把橫軸窗口拉近圖形內(nèi)容不變。但實(shí)際上x(chóng)lim()先刪除范圍外的數(shù)據(jù)再執(zhí)行幾何對(duì)象的計(jì)算最后才畫(huà)圖。一個(gè)立即產(chǎn)生影響的例子是geom_smooth()library(ggplot2) set.seed(42) df - data.frame(x 1:100, y sin(1:100 / 10) rnorm(100, 0, 0.2)) # 效果一先截?cái)?shù)據(jù)再擬合置信區(qū)間基于20到80的子集 ggplot(df, aes(x, y)) geom_point() geom_smooth() xlim(20, 80) # 效果二完整數(shù)據(jù)擬合只是視圖放大到20到80 ggplot(df, aes(x, y)) geom_point() geom_smooth() coord_cartesian(xlim c(20, 80))第一張圖的平滑曲線在窗口邊緣可能會(huì)出現(xiàn)明顯彎曲甚至趨勢(shì)反轉(zhuǎn)因?yàn)檫吔绺浇臄?shù)據(jù)被截掉了一部分?jǐn)M合樣本不完整第二張圖才是“原數(shù)據(jù)的局部放大”平滑趨勢(shì)與全圖完全一致。判斷一張圖是否被截?cái)噙€有個(gè)簡(jiǎn)單方法看置信區(qū)間在邊界處是不是突然收窄如果是多半是數(shù)據(jù)被截?cái)嗔?。?yīng)用原則只想讓眼睛看到局部用coord_cartesian想真正基于局部子集重新統(tǒng)計(jì)再用xlim()。4.2 hist的組距不會(huì)跟著xlim走改xlim對(duì)散點(diǎn)圖、折線圖基本只是視野問(wèn)題但對(duì)直方圖會(huì)有隱藏影響。hist()的組距breaks默認(rèn)基于完整數(shù)據(jù)范圍來(lái)計(jì)算即使你在hist()里設(shè)置了xlimR也是先用完整數(shù)據(jù)算好組距然后只顯示范圍內(nèi)的部分柱子。看這段代碼set.seed(7) d - c(rnorm(1000, 0, 1), runif(10, 50, 60)) hist(d, xlim c(-5, 5))你預(yù)期看到0附近的分布但因?yàn)閿?shù)據(jù)里混了10個(gè)50到60之間的值R默認(rèn)把breaks鋪到很寬的范圍每個(gè)組距被拉大導(dǎo)致-5到5區(qū)間里的柱子只有幾根根本看不清分布形狀。正確做法是先篩掉離群點(diǎn)或者手動(dòng)指定breakshist(d[d -5 d 5], breaks 50, xlim c(-5, 5))或者對(duì)全量數(shù)據(jù)指定足夠細(xì)的組距再限制xlimhist(d, breaks seq(-60, 60, by 0.2), xlim c(-5, 5))記住一句話直方圖里xlim只影響“展示哪一段”不影響“怎么分組”。想讓分組合理得先把breaks控制好。4.3 日期軸、因子軸不能直接填數(shù)字很多人在處理時(shí)間序列時(shí)直接寫(xiě)xlim c(20240101, 20241231)結(jié)果圖形空白或者報(bào)錯(cuò)。原因是R里的日期是一個(gè)Date對(duì)象底層雖然是數(shù)字但坐標(biāo)軸的limits要求傳入相同類(lèi)型的值。base R里date軸的正確寫(xiě)法是dates - seq(as.Date(2024-01-01), as.Date(2024-12-31), by day) vals - cumsum(rnorm(length(dates))) plot(dates, vals, xlim as.Date(c(2024-01-15, 2024-03-01)), type l)ggplot2里處理時(shí)間序列時(shí)可以在scale層做library(ggplot2) df - data.frame(date dates, value vals) ggplot(df, aes(date, value)) geom_line() scale_x_date(limits as.Date(c(2024-01-15, 2024-03-01)))注意連續(xù)兩個(gè)月數(shù)據(jù)本來(lái)有366個(gè)點(diǎn)xlim這樣一寫(xiě)范圍外的數(shù)據(jù)點(diǎn)并不會(huì)顯示。但這和4.1節(jié)說(shuō)的一樣xlim會(huì)截?cái)鄶?shù)據(jù)如果只是放大看也得用coord_cartesian(xlim as.Date(c(...)))。因子軸也有自己的坑。假設(shè)x軸是因子型變量包含“低”“中”“高”三個(gè)水平直接xlim(低, 高)在ggplot2里是可以的但如果你限定的值不在因子水平里會(huì)報(bào)錯(cuò)或出空白。離散軸的limits本質(zhì)是“允許顯示哪些類(lèi)別”而不是“數(shù)值邊界”理解這一點(diǎn)就不會(huì)迷惑了df2 - data.frame(group factor(c(低, 中, 高), levels c(低, 中, 高)), value c(1, 2, 3)) ggplot(df2, aes(group, value)) geom_col() scale_x_discrete(limits c(低, 高))這樣畫(huà)出來(lái)只有一個(gè)“低”柱和一個(gè)“高”柱“中”被篩掉了。注意順序limits里的順序就是軸上類(lèi)別的順序。4.4 對(duì)數(shù)坐標(biāo)軸的邊界選擇用log x或者scale_x_log10()時(shí)坐標(biāo)范圍的下限不能是0或負(fù)數(shù)。對(duì)數(shù)在0處沒(méi)有定義xlim c(0, 100)在普通坐標(biāo)下沒(méi)問(wèn)題但一旦取對(duì)數(shù)R會(huì)抱怨或者畫(huà)出一片空白。x - seq(1, 100, length.out 100) y - x^0.5 # 正常 plot(x, y, log x, xlim c(1, 100)) # 報(bào)錯(cuò)或圖像異常0不能取對(duì)數(shù) plot(x, y, log x, xlim c(0, 100))ggplot2同理。使用scale_x_log10(limits c(...))時(shí)下限一定要大于0。如果你處理的數(shù)據(jù)本身包含0常見(jiàn)做法是先加一個(gè)很小的偏移量比如x 0.1再取對(duì)數(shù)。還有一種情況對(duì)數(shù)坐標(biāo)下要求坐標(biāo)軸刻度對(duì)齊某些特定數(shù)字比如1、10、100、1000可以在limits里精確指定邊界再讓breaks也對(duì)應(yīng)這些值圖看起來(lái)會(huì)非常規(guī)整。4.5 坐標(biāo)軸標(biāo)簽被裁掉怎么辦設(shè)定坐標(biāo)范圍后偶爾會(huì)出現(xiàn)圖邊緣的刻度標(biāo)簽被截掉一半的情況。原因通常是圖形設(shè)備尺寸有限而坐標(biāo)范圍邊界上的文字、標(biāo)簽超出了繪圖區(qū)域。最簡(jiǎn)單的處理是給繪圖區(qū)域留出更多外部邊距。base R里用par(mar c(bottom, left, top, right))par(mar c(5, 5, 2, 2)) plot(x, y, xlim c(0, 1.2), ylim c(0, 1.2))ggplot2則可以通過(guò)theme()調(diào)整plot.marginggplot(df, aes(x, y)) geom_point() coord_cartesian(xlim c(0, 10)) theme(plot.margin margin(1, 2, 1, 1, cm))還有一種常見(jiàn)情況你在圖上用text()或annotate()添加了額外標(biāo)注標(biāo)注點(diǎn)正好落在坐標(biāo)范圍邊界外被裁掉了??梢杂胮ar(xpd TRUE)允許繪制超出區(qū)域或者干脆把ylim略微擴(kuò)大一點(diǎn)給標(biāo)注留位置。我的習(xí)慣是統(tǒng)一“先設(shè)定核心范圍再給標(biāo)簽和注釋留10%的余量”這樣既保證主體清晰又不會(huì)出現(xiàn)文字被切的問(wèn)題。5. 坐標(biāo)軸范圍設(shè)定的排查清單與個(gè)人習(xí)慣5.1 遇到坐標(biāo)異常時(shí)的排查清單坐標(biāo)范圍的問(wèn)題通常不復(fù)雜但出錯(cuò)時(shí)容易繞來(lái)繞去。我把排錯(cuò)步驟整理成一張可以直接對(duì)照的表現(xiàn)象可能原因解決辦法坐標(biāo)軸范圍被拉得異常大數(shù)據(jù)里有離群值或錯(cuò)誤值如1e6先range(x, na.rmTRUE)檢查數(shù)據(jù)再設(shè)定xlim/ylim指定xlim后圖形仍然超出base R默認(rèn)4%擴(kuò)展加上x(chóng)axsi, yaxsi用ggplot2畫(huà)日期圖xlim報(bào)錯(cuò)limits類(lèi)型與軸的scale類(lèi)型不匹配用as.Date()或scale_x_date(limits...)xlim后統(tǒng)計(jì)線形狀改變xlim截?cái)嗔藬?shù)據(jù)再統(tǒng)計(jì)需要“放大視圖”時(shí)改用coord_cartesian()直方圖柱子太少組距受完整數(shù)據(jù)影響與xlim無(wú)關(guān)手動(dòng)指定breaks或先篩數(shù)據(jù)對(duì)數(shù)坐標(biāo)軸下圖形空白limits包含0或負(fù)數(shù)把limits下限改成大于0的值或加偏移量圖邊緣文字被裁掉坐標(biāo)范圍太窄、邊距不足調(diào)節(jié)par(mar)或theme(plot.margin)擴(kuò)大ylim排查時(shí)我的順序是先檢查數(shù)據(jù)本身有沒(méi)有NaN、Inf、異常大值再確認(rèn)坐標(biāo)范圍的數(shù)值類(lèi)型是否匹配軸的刻度類(lèi)型最后才懷疑繪圖函數(shù)的參數(shù)使用錯(cuò)誤。超過(guò)一半的問(wèn)題出在前兩步。5.2 我畫(huà)圖時(shí)固定的幾個(gè)操作習(xí)慣第一先畫(huà)默認(rèn)圖不改任何坐標(biāo)范圍。這一步的目的是看數(shù)據(jù)全貌包括有沒(méi)有離群值、分布形狀是什么樣的。很多人一上來(lái)就xlim、ylim手寫(xiě)一通結(jié)果把一個(gè)重要異常值直接藏掉了自己還不知道。第二用range()和extendrange()隨時(shí)確認(rèn)邊界。寫(xiě)代碼前先跑一下range(x, na.rm TRUE) extendrange(x, f 0.05)extendrange()可以按比例擴(kuò)展數(shù)據(jù)范圍得到比較合理的繪圖邊界。我通常拿它生成初版xlimplot(x, y, xlim extendrange(x, f 0.05), ylim extendrange(y, f 0.05))第三多圖對(duì)比必須統(tǒng)一坐標(biāo)范圍沒(méi)有例外。不管是用par(mfrow)、facet_wrap還是手動(dòng)拼圖只要目的是對(duì)比不同組、不同時(shí)間段坐標(biāo)范圍不一致就等于數(shù)據(jù)造假。第四柱狀圖從0開(kāi)始折線圖可以“斷軸”。柱子的高度代表數(shù)值大小不從0開(kāi)始會(huì)讓柱子的視覺(jué)比例失真。折線圖和散點(diǎn)圖關(guān)注的是波動(dòng)和趨勢(shì)可以裁剪掉沒(méi)有數(shù)據(jù)的空白區(qū)域讓細(xì)節(jié)更清楚。這個(gè)選擇不是技術(shù)問(wèn)題而是表達(dá)問(wèn)題。第五發(fā)表用的圖要控制主刻度數(shù)量。坐標(biāo)范圍一寬R會(huì)自作主張塞很多刻度線圖面很亂。我一般把主刻度控制在3到6個(gè)之間用axis()或scale_x_continuous(breaks)手動(dòng)指定。5.3 坐標(biāo)范圍就是數(shù)據(jù)敘事的一部分最后分享一點(diǎn)個(gè)人體會(huì)。坐標(biāo)范圍從來(lái)不是單純的繪圖細(xì)節(jié)它決定讀者從同一份數(shù)據(jù)里看到什么“故事”。同一條上升曲線把橫軸拉長(zhǎng)趨勢(shì)顯得平緩把縱軸壓窄波動(dòng)顯得劇烈。自媒體時(shí)代有一句常用的話叫“圖表會(huì)說(shuō)話”說(shuō)到底圖表語(yǔ)言里最具操控性的就是坐標(biāo)范圍。我自己在檢查圖表時(shí)會(huì)刻意問(wèn)三個(gè)問(wèn)題這個(gè)xlim把哪些數(shù)據(jù)排除了這個(gè)ylim是真的需要這么窄還是為了讓差異看起來(lái)更大如果換一組尺度的數(shù)據(jù)這張圖的結(jié)論還成立嗎這三個(gè)問(wèn)題問(wèn)完能攔住不少誤導(dǎo)性的圖。坐標(biāo)范圍這個(gè)參數(shù)看起來(lái)只是兩個(gè)數(shù)字實(shí)際上它是圖上所有信息的邊界。搞清楚xlim和ylim的機(jī)制、分清截?cái)鄶?shù)據(jù)與縮放視圖的區(qū)別、養(yǎng)成固定坐標(biāo)對(duì)比的習(xí)慣你就掌握了數(shù)據(jù)可視化里最重要的一項(xiàng)基本功。畫(huà)圖這件事很多時(shí)候不是技術(shù)不夠而是對(duì)“邊界”的理解不到位。