在 偏摩爾體積測定-數據處理 中基本完成了數據處理,解決了切線以及截距值的添加,但這樣的圖,始終還是少了點東西。因此,在原來的基礎之上:
q1 + q2 + q3 + q4 + q5 + q6 +
plot_layout(ncol = 3,byrow = F) +
plot_annotation(tag_levels = 'a',
tag_suffix = ')',
title = '偏摩爾體積的測定',
caption = '2020/10/27',
theme = theme(plot.title = element_text(
family = 'op_m'
),
plot.caption = element_text(
family = 'op_m'
))
)圖像:
首先: 由於一直以來都是採用 theme_classic() 作為基礎主題來改造。而 ggplot2 默認橫縱坐標軸在末端處有所延長,並不會直接相交,這也就是為什麼 x = 0 處為什麼不是 y 軸,而需要自行添加虛線來顯示切線的交點,即對應的截距值。同時 右側也不顯示 第二個 y 軸,即達到雙坐標軸的設想。同時,按理來說,把「水」、「乙醇」這兩個標籤放到坐標軸以外的範圍來顯示會更加合理一些,更能符合通用的習慣。
因此,先解決橫坐坐標軸不能直接相交的問題:
ggplot(dd, aes(x,y)) +
geom_point() +
geom_line(data = xsp(dd,n)) +
labs(x = expression(G[2]),y = expression(frac(1,rho))) +
scale_x_continuous(breaks = seq(0,1,by = 0.2),
limits = c(0,1),
expand = c(0,0)) +
scale_y_continuous( sec.axis = sec_axis(~. ,
name = expression(frac(1,rho))
))圖像:
這一塊,通過 scale_x_continuous() 的 expand 參數來控制擴展的範圍,將值設置為 c(0,0) 即避免了兩端出現延長。但這種方式並不是 「True or False」的方式, y 軸 也需要通常操作才能完成,因此,這裡就需要更加快速地完成 expand 的設置。
coord_cartesian(
xlim = NULL,
ylim = NULL,
expand = TRUE,
default = FALSE,
clip = "on"
)而坐標軸的控制,則是由 coord_xx 系列函數來完成。常規使用的為直角坐標系,因此,改用 coord_cartesian() 函數,其中參數 expand 值為邏輯值,僅能選擇 true 或 false, 這樣的話,來開啟全局控制,一次性避免坐標軸延長擴展範圍。
同時另一個參數:clip = 'on' 也是接下來需要使用到的參數。
ggplot(dd, aes(x,y)) +
geom_point() +
geom_line(data = xsp(dd,n)) +
coord_cartesian(expand = F) +
labs(x = expression(G[2]),y = expression(frac(1,rho))) +
scale_x_continuous(breaks = seq(0,1,by = 0.2),
limits = c(0,1)
) +
scale_y_continuous(
sec.axis = sec_axis(~. ,
name = expression(frac(1,rho))
))圖像:
但這樣的後果是:兩端的點直接被坐標軸或是邊界掩藏了一半的內容,這顯示是不合理的,因此開始 expand = F 後,需要手動改變坐標軸範圍來延長區域,以顯示所有的點並避免坐標軸重疊!
而第二坐標軸,則由 scale_y_continuous() 中的 sec.axis 來控制,其接受 sec_axis() 函數的設定值。這一點,可以通過該函數的幫助信息來詳細地了解,因此不再一一闡述。
所以,接下來要做的就是改善坐標軸範圍,接下來嘗試添加繪圖區域以外的問題(這取決於第二個參數 clip)
但是,這裡面仍然有注意事項:
ggplot(dd, aes(x,y)) +
geom_point() +
geom_line(data = xsp(dd,n)) +
coord_cartesian(clip = 'off',expand = F) +
labs(x = expression(G[2]),y = expression(frac(1,rho))) +
scale_x_continuous(breaks = seq(0,1,by = 0.2),
limits = c(0,1)
) +
scale_y_continuous( sec.axis = sec_axis(~. ,
name = expression(frac(1,rho))
)) +
annotate('label',x = 0:1, y = 0.78,
label = c('水','乙醇'),
hjust = c(0,1))圖像:
問題出在:clip = 'off' 即意味著:可以在繪圖區域以外的可見區域內添加數據點或其他內容,只要可見即可,但是:上面的圖中,顯示是以 label 的縱坐標值作為繪圖區域的縱坐標下限來使用,這樣的話,文本依然在繪圖區域內部,而不能達到想要的效果。
但,給 scale_y_continuous() 添加坐標軸範圍後:
scale_y_continuous(limits = c(0.84,1.3),...)
Warning message:
Removed 2 rows containing missing values (geom_label).
返回的警告信息,已經說明了:此時會移除 label 信息,及原有的 label 圖層無法被添加,已經被自動移除。因此,這種做法,顯然是不合理的。所以在改變 clip 的值時,必須在 coord_cartesian() 中添加 ylim 的值!
即:
ggplot(dd, aes(x,y)) +
geom_point() +
geom_line(data = xsp(dd,n)) +
coord_cartesian(ylim = c(0.84,1.3),clip = 'off',expand = F) +
labs(x = expression(G[2]),y = expression(frac(1,rho))) +
scale_x_continuous(breaks = seq(0,1,by = 0.2),
limits = c(0,1)
) +
scale_y_continuous( sec.axis = sec_axis(~. ,
name = expression(frac(1,rho))
)) + the() +
annotate('label',x = 0:1, y = 0.78,
label = c('水','乙醇'),
hjust = c(0,1))
但,這樣的圖:
不顯示警告信息,但依舊沒有顯示這兩個標籤,問題只能出在下端的距離上。
plot.margin:
margin around entire plot (unit with the sizes
of the top, right, bottom, and left marginsplot.margin 用於控制 plot 區域距離四周邊界的大小,其接收 margin() ,用於對 距離頂端、右側、底部、左側區域的空白間隔進行設置,很顯然上面的圖中底部空白間隔太小,從而導致 label 無法顯示,因此改為:
margin(t = 0, r = 0, b = 0, l = 0, unit = "pt")margin() 默認的單位為 pt, 這一點需要注意。
ggplot(dd, aes(x,y)) +
geom_point() +
geom_line(data = xsp(dd,n)) +
coord_cartesian(ylim = c(0.84,1.3),clip = 'off',expand = F) +
labs(x = expression(G[2]),y = expression(frac(1,rho))) +
scale_x_continuous(breaks = seq(0,1,by = 0.2),
limits = c(0,1)
) +
scale_y_continuous( sec.axis = sec_axis(~. ,
name = expression(frac(1,rho))
)) + the() +
annotate('label',x = 0:1, y = 0.78,
label = c('水','乙醇'),
hjust = c(0,1)) +
theme(plot.margin = margin(4,4,60,4))在最後,添加 theme(plot.margin = margin(4,4,60,4)) 來擴大底部空白部分的高度:
這一處的調整,通常是不斷調整參數,運行後來得到合適的效果。暫時沒有辦法可以一次調節到位。
接下來的操作,就類似於之前,添加切線和截距值。
完成 p1, p2, p3, p4, p5, p6 的繪圖後,繼續拼圖:
q1 + q2 + q3 + q4 + q5 + q6 +
plot_layout(ncol = 3,byrow = F) +
plot_annotation(tag_levels = 'a',
tag_suffix = ')',
title = '偏摩爾體積的測定',
caption = '2020/10/27',
theme = theme(plot.title = element_text(
family = 'op_m',size = 16
),
plot.caption = element_text(
family = 'op_m',size = 14
))
)
ggsave('mole-2.pdf',width = 297,height = 210,
units = 'mm',scale = 1.1)
PNG('vm-A.pdf','A.png')圖像:
保存為 A4 紙張大小便於直接列印,同時 利用 scale 參數來控制縮放比例,以避免文本重疊。到此,這樣的圖,可能會更加符合日常習慣。
要點:
1/ 切線的添加
2/ 雙坐標軸圖的建立
3/ 繪圖區域以外的範圍內添加內容,該如何顯示?
既要關閉 clip , 又要不斷地修改 plot.margin 的值!
4/ patchwork + ggsave() 的 scale 參數的使用
以上實際問題,其實提醒了我們:
當你逐漸習慣了 ggplot2 的便捷性的時候,一旦遇到 ggplot2 無法直接解決的問題,你就只能「沮喪 + 無助」. 要善於利用一些方法來實現更多的功能,並且善於查閱幫助文檔來更加全面地掌握 ggplot2 的不被注意的參數以及功能。
最近,想到的 ggplot2 暫時無法支持的功能:
低水平繪圖函數(二)中展示了一幅:
f <- function(x) 2*x^2
plot(f,-3,3,ylim =c(0,20),bty = 'l')
x1 <- seq(-1,2,0.01)
y1 <- lapply(x1,f)
xt <- c(-1,x1,2)
yt <- c(-.8,y1,-.8)
polygon(xt,yt,density =14)
polygon(x1,y1, col ="tomato")圖像:
這裡面的多邊形,有一個很重要的參數:density = 14, 決定了填充的線條的密度,以及默認線條方向為:45度角。
而 ggplot2 的解決辦法為:
l1 <- data.frame(x = x1, y = map_dbl(x1,f))
l2 <- data.frame(x = xt, y = as.numeric(yt))
ggplot(l1,aes(x,y)) +
geom_polygon(fill = 'tomato') +
geom_polygon(data = l2,
fill = 'grey78')圖像:
但問題是,並不能添加紋理,即原圖中的 45度角方向的直線構成的圖案,僅僅是通過 顏色、填充色、線條類型、透明度等來做出改變。類似的更為多樣化的紋理填充,就更不能支持。
density :
the density of shading lines, in lines per inch.
The default value of NULL means that no shading
lines are drawn. A zero value of density means no
shading nor filling whereas negative values and NA
suppress shading (and so allow color filling).
事實上,一方面這樣的需求並不多見,往往見於很久很久之前的作圖要求中,現在的話,一般都不會選擇做黑白圖像,所以這樣的需求,並不是很頻繁。
其次,目前全部使用 R base 來繪圖的,已經越來越少見。很多人都已經忘記了 polygon() 還有這樣的功能,這並不是說,我們就應該拐回去,重新學習低水平繪圖函數。但這仍是 ggplot2 無法做到的一個功能。
或許,以後真的會有可以直接添加陰影效果的解決方案。正像 ggplot2 當初推出第二坐標軸的解決方案一樣,以及能夠在繪圖區域以外的範圍顯示其他的內容。。。
遇到 ggplot2 不能實現的需求,往往就只能「哭泣」,這也是沒辦法的事,因此,習慣就好。 加切線就是一個需要自己想辦法的挑戰。
---end---