logo xDuLieu.com

Trang trướcVẽ biểu đồ với phụ kiện ggplot2 

Để làm quen với việc vẽ biểu đồ được dễ dàng, ta đã sử dụng các công cụ cơ bản. Tuy nhiên ta thấy rằng để có những biểu đồ có chất lượng về khoa học và mỹ thuật, ta tốn nhiều công sức và trong nhiều trường hợp, kết quả vẫn không được như ý. Trong các trường hợp ấy ta nên chuyển sang dùng phụ kiện ggplot2.

Khái quát về ggplot2

 

Nguyên lý cơ bản của phụ kiện này dựa trên khái niệm "Grammar of Graphics" đề xuất bởi Leland Wilkinson (2005) và được Hadley Wickham phát triển (2009). Theo đó, biểu đồ được xem như một câu văn gồm một số thành phần và người vẽ kết hợp các thành phần ấy để tạo thành biểu đồ. Như vậy, ngoại trừ một số ràng buộc, như dữ liệu, ta có thể kết hợp các thành phần ấy theo nhiều cách khác nhau để tạo ra biểu đồ như ý ta mong muốn.

Một đặc điểm khác của phương pháp vẽ này là "lớp": ta xem biểu đồ gồm một số lớp chồng lên nhau. Các lớp này độc lập nhau và mỗi lớp lại có một số đặc điểm và chức năng riêng. Như vậy ta có thể chia một biểu đồ phức tạp thành một số lớp có cấu trúc đơn giản, có thể thực hiện chỉ bằng một câu lệnh. Điểm đặc biệt là các lớp này có thể sử dụng các nguồn dữ liệu khác nhau và có các phương pháp thể hiện khác nhau.

Với sự kết hợp các điểm vừa nêu, ta có thể thực hiện rất nhiều loại biểu đồ có chất lượng cao cả về mặt khoa học và mỹ thuật. Tuy nhiên, phương pháp vẽ này vẫn còn trong giai đoạn phát triển nên một số chức năng vẫn còn hạn chế như thực hiện các biểu đồ liên quan đến đồ họa 3 chiều hay các biểu đồ cần có tính tương tác. Mặt khác, cú pháp và cấu trúc các dòng lệnh sẽ có một số điểm khác biệt, ta có thể gập một vài khó khăn khi bắt đầu làm quen.

Bạn có thể tìm hiểu thêm về phụ kiện này tại trang web "An implementation of the Grammar of Graphics".


Các thành phần của biểu đồ

 

Theo ggplot2 biểu đồ là sự kết hợp của các thành phần sau:

  • Dữ liệu : là thành phần rất quan trọng vì biểu đồ dùng để thể hiện các nét đặc trưng của dữ liệu. Khi sử dụng ggplot2 dữ liệu phải ở dạng bảng và trong một số trường hợp cần được khai báo một cách tường minh:
    data = bang_du_lieu.
  • Đối tượng hình học (geometric hay geom) cho ta biết dạng thể hiện của dữ liệu như điểm, đường, hình.
  • Thuộc tính thẩm mỹ (aesthetic hay aes) (như màu sắc hay kích thước) là cách trình bày các đối tượng hình học. Trong nhiều trường hợp, cách trình bày này cũng thể hiện một tính chất nào đó của dữ liệu.
  • Biến đổi số liệu (statistic transformation hay stat): ta có thể xử lý trực tiếp số liệu từ bảng hay biến đổi thành dạng khác hợp lý hơn. Khi ấy ta có thể đưa thêm biến mới vào bảng dữ liệu.
  • Hệ tọa độ (coordinate system hay coord) được dùng để xác định vị trí của các đối tượng hình học. Hệ tọa độ thông dụng nhất là hệ tọa độ vuông góc xy mà ta đã quen thuộc. Đôi khi, một vài chi tiết của hệ tọa độ được điều chỉnh để các lớp ăn khớp nhau.
  • Các ghi chú trên biểu đồ.
  • Diện (faceting hay facet) : cần dùng khi vẽ nhiều biểu đồ con trong cùng một vùng không gian.

Liên kết thuộc tính thẩm mỹ với dữ liệu

Một trong các điểm đặc biệt của ggplot2 là ta có thể liên kết (mapping) các thuộc tính thẩm mỹ với dữ liệu (có kiểu yếu tố). Điều này có nghĩa là khi giá trị của của dữ liệu thay đổi, thuộc tính cũng thay đổi theo. Nhờ đó sự nhận biết các đặc điểm của dữ liệu được rõ ràng hơn.

Ta sẽ làm quen với các chức năng và cách sử dụng những thành phần này trong các phần tiếp theo.


Làm quen với ggplot2 qua hàm qplot

 

Để bước đầu làm quen với cú pháp của ggplot2, ta sẽ sử dụng hàm qplot để vẽ biểu đồ xy cho biết mối tương quan giữa năng lượng và hàm lượng lipit trong các sản phẩm thịt.

Trước hết ta cần kích hoạt phụ kiện này và bảng dữ liệu Thit.csv. Để có thể phân biệt dữ liệu theo hàm lượng protein trong thịt, ta tạo thêm biến yProtein kiểu yếu tố và đưa biến này vào bảng dữ liệu với các lệnh sau:

> yProtein = cut(Thit$Protein_g, breaks=c(0,10,20,100),
labels=c("Protein thấp","Protein trung bình","Protein cao")) > Thit <- cbind(Thit, yProtein)

Sau đó vẽ biểu đồ xy bằng câu lệnh sau:

> qplot(Lipit_g, NangLuong_kcal, data=Thit, geom="point",
xlab="Hàm lượng Lipit (%)", ylab="Năng lượng (kcal/100g)", color=yProtein, shape=yProtein, size=I(4))

Trong câu lệnh này, ngoài hai đối số xlabylab để ghi tên các trục mà ta đã biết, còn có:

  • Lipit_gNangLuong_kcal là hai biến x và y tương ứng với trục hoành và trục tung để xây dựng biểu đồ xy.
  • geom = point : là đối tượng hình học trình bày trên biểu đồ. Trong đồ thị này ta dùng các điểm để thể hiện các cặp số xy.
  • color = yProteinshape = yProtein : ta liên kết hai thuộc tính thẩm mỹ là màu và hình dáng của các điểm với biến yProtein.
  • size = I(4) : ta thay đổi kích thước các điểm để nhìn rõ hơn. Giá trị của đối số này là độ lớn tương đối (giá trị mặc định là 2) so với độ lớn chuẩn. Nếu ta khai báo size = 4 thì R sẽ tạo ra một biến mới tên là 4 và kích thước điểm sẽ không được như ý ta muốn.

Kết quả thực hiện lệnh vẽ được trình bày trên Hinh 1.

Hình 1 Biểu đồ xy vẽ bằng hàm qplot của phụ kiện ggplot2

Qua biểu đồ này, ta thấy các điểm tương ứng với các mức protein khác nhau được biểu diễn bằng các màu khác nhau và các hình khác nhau. Ngoài các đối số được khai báo, các đối số khác có giá trị mặc định như màu nền của biểu đồ, đường ô lưới, chọn độ lớn các trục. Nhìn chung các đối số này đã được lựa chọn cẩn thận để thu được một biểu đồ có chất lượng tốt. Tất nhiên là ta có thể thay đổi cho phù hợp với các yêu cầu cụ thể.

Ta sẽ thực hiện thêm một thí dụ với biểu đồ tần số xem xét sự phân bố của hàm lượng canxi trong các loại thịt bằng câu lệnh sau:

> qplot(Canxi_mg, data=Thit, geom="histogram", binwidth=20,
fill=yProtein, xlab="Hàm lượng Canxi (mg/100g)")

Và ta có biểu đồ tần số trên Hinh 2.

Hình 2 Biểu đồ tần số vẽ bằng hàm qplot của phụ kiện ggplot2

Trong trường hợp này, do ta vẽ biểu đồ tần số nên geom = histogram. Đối số binwidth xác lập kích thước các khoảng chia; fill = yProtein xác lập màu tô của biểu đồ tần số phụ thuộc vào mức độ Protein trong thịt.


Vẽ bằng ggplot

 

Trong phần trên, ta đã sử dụng hàm qplot để thực hiện hai biểu đồ và ta đã hình dung được phần nào khả năng của ggplot2. Tuy nhiên với qplot, ta chỉ vẽ được biều đồ với 1 lớp. Để tận dung hết sức mạnh của ggplot2 ta nên thực hiện theo cách vẽ nhiều lớp qua một số dòng lệnh.

Chuẩn bị với hàm ggplot

Ta sẽ khởi đầu bằng cách chuẩn bị biểu đồ trống với cú pháp:

ggplot(bang_dul_lieu, aes(bien)) + 

Trong đó :

  • bang_du_lieu : tên của bảng dữ liệu. Khác với qplot, ta có thể dùng cách khai báo rút gọn, không cần khai báo tường minh
  • aes là hàm khai báo tên các biến mà dữ liệu được sử dụng để vẽ biểu đồ. Ta có thể không khai báo hàm này ở đây.
  • Ta có thể khai báo thêm các đối số cần thiết.
  • Dấu + để báo cho R biết là sau đó còn ít nhất một lệnh để vẽ lớp.

Thí dụ để vẽ Hình 1, ta khởi đầu với câu lệnh:

> ggplot(Thit, aes(Lipit_g, NangLuong_kcal)) +

Hoặc đơn giản hơn :

> ggplot(Thit) +

Còn đối với Hình 2, câu lệnh đầu tiên là :

> ggplot(Thit, aes(Canxi_mg)) +

Vẽ biểu đồ với hàm geom_XXX

Trong các câu lệnh tiếp theo, ta sẽ vẽ thêm biểu đồ nằm trong một hay nhiều lớp. Cú pháp thông thường cho mỗi lớp là:

 geom_XXX(lien_ket, bang_du_lieu, doi_so) +

Trong cú pháp này thì :

  • geom_XXX : xác lập loại biểu đồ ta muốn thể hiện như geom_line để vẽ biểu đồ dạng đường nối các điểm, geom_bar để vẽ biểu đồ thanh.
  • lien_ket : khai báo mối liên kết (mapping) giữa thuộc tính thẩm mỹ và biến. Thông thường liên kết này được khai báo bằng hàm aes.
  • bang_du_lieu : tên bảng dữ liệu. Nếu đã được khai báo ở hàm ggplot thì không cần khai báo lại.
  • Ta cũng lưu ý là thứ tự của hàm aes và bảng dữ liệu trong câu lệnh này ngược với trong hàm ggplot
  • doi_so : khai báo giá trị của các đối số. Nếu đối số của thuộc tính thẩm mỹ được khai báo ở đây (setting) thì sẽ không liên kết với biến nào.
  • Dấu + chỉ cần thiết nếu sau đó ta còn câu lệnh khác để vẽ thêm lớp hay hiệu chỉnh biểu đồ.

Như vậy, cấu trúc câu lệnh này có thể rất đơn giản như:

   geom_point()

nếu dữ liệu, biến đã được khai báo trong ggplot, ta vẽ với các đối số có giá trị mặc định, không có lớp nào được vẽ thêm và không cần hiệu chỉnh gì.

Thí dụ để vẽ Hình 2 (chưa hoàn chỉnh) ta dùng các câu lệnh sau:

> ggplot(Thit, aes(Canxi_mg)) +
geom_histogram(aes(fill=yProtein), binwidth=20)

Trong câu lệnh thứ hai, ta không phải khai báo biến Canxi_mg và bảng dữ liệu Thit trong hàm aes vì chúng đã được khai báo trước trong ggplot. Ta chỉ khai báo thêm đối số fill=yProtein liên quan đến màu tô các thanh (thuộc tính thẩm mỹ) và đối số binwidth = 20 để xác lập khoảng chia.

Thí dụ ta muốn vẽ lại Hình 1 và bổ sung thêm đường thể hiện xu hướng chung của tương quan giữa hàm lượng lipid và năng lượng của thịt (Hình 3) thì ta sử dụng các câu lệnh sau:

> ggplot(Thit, aes(Lipit_g, NangLuong_kcal)) +
geom_point(aes(color=yProtein, shape=yProtein), size=I(4)) +
geom_smooth()

Hình 3 Biểu đồ xy gồm một số lớp

Ta thấy lệnh geom_smooth() đã bổ sung thêm đường thể hiện xu hướng chung của mối tương quan giữa hàm lượng lipid và năng lượng của thịt. Ta cũng lưu ý thêm rằng đây không phải là đường thẳng.


Hiệu chỉnh biểu đồ

Ngoại trừ một số đối số được chúng ta lựa chọn và xác lập, các đối số khác được giữ ở giá trị mặc định. Mặc dù các giá trị này đã được lựa chọn cẩn thận nhưng trong một số trường hợp biểu đồ chưa đạt các yêu cầu cụ thể. Vì vậy ta cần hiệu chỉnh thêm.

Một điểm khó khăn cho những người bắt đầu làm quen với ggplot2 là số hàm và đối số dùng cho công việc này rất nhiều và cách sử dụng cũng khá phức tạp. Trong khuôn khổ của chuyên đề này, chúng tôi chỉ có thể giới thiệu với bạn một vài trường hợp thông dụng.

Đặt tên cho các trục

Theo mặc định, ggplot2 sẽ lấy tên các biến để đặt tên cho các trục. Điều này không thích hợp cho nhiều trường hợp, đặc biệt cho tiếng Việt. Để đặt tên cho các trục ta có thể dùng hàm xlab cho trục x, ylab cho trục y, hay labs cho cả hai trục. Thí dụ ta muốn đặt lại tên hai trục cho biểu đồ trên Hình 40, ta có thể dùng các câu lệnh:

+ xlab("Hàm lượng Lipit (%)") + 
+ ylab(Năng lượng (kcal/100 g))

hay câu lệnh :

+ labs(x = "Hàm lượng Lipit (%)", y = "Năng lượng (kcal/100 g)")

Xác định giời hạn các trục

Đối với các biến có giá trị số, ggplot2 sẽ tìm các giá trị thấp nhất và cao nhất của biến. Sau đó chọn ra các cực biên và chia độ các trục dựa trên các giá trị này theo thứ tự từ thấp đến cao. Trong một số trường hợp ta có thể thay đổi điều ấy bằng các hàm có dạng xlim(a, b)ylim(c, d). Như ta thấy, các hàm này đều có hai đối số, a và b ứng với cực trái và cực phải của trục hoành, c và d ứng với cực dưới và cực trên của trục tung. Ta cũng lưu ý rằng ta có thể chọn a > b và/hay c > d.


Vẽ nhiều biểu đồ với facet

 

ggplot2 cũng có công cụ facet giúp ta thực hiện ma trận của nhiều biểu đồ con. Điều lý thú là tính năng này cũng có khả năng liên kết với dữ liệu như các thuộc tính thẩm mỹ. Công cụ này gồm hai dạng là facet_gridfacet_wrap.

facet_grid

Cú pháp thông dụng của hàm này là:

facet_grid(bien_dong ~ bien_cot, margin)

Trong đó :

  • bien_dongbien_cot là các biến quyết định sự thể hiện các biểu đồ con theo dòng và theo cột. Giá trị mặc định của đối số này là . ~ . nghĩa là ta chỉ có một biểu đồ. Nếu đối số này là . ~ bien_cot thì ma trận biểu đồ có một dòng và nhiều cột. Nếu đối số này là bien_dong ~ . thì ma trận biểu đồ có nhiều dòng và một cột.
  • margin : Ta hình dung ma trận các biểu đồ như một bảng tham khảo chéo (contingency table). Thông thường bảng này có thêm một cột ở biên phải cho ta biết tổng của các ô trên một dòng, thêm một dòng ở phía dưới cho ta biết tổng của các ô trên một cột. Tương tự như vậy, nếu margin = TRUE thì ma trận chúng ta cũng có thêm một cột ở biên phải và một dòng ở bên dưới (ký hiệu là "(all)") với ý nghĩa tương tự. Trái lại nếu margin = FALSE thì không trình bày thêm.
    Ta cũng có thể chỉ cần thêm dòng hay cột biên bằng cú pháp margin = ten_bien với ten_bien là tên của biến dòng hay biến cột (có liên kết) mà ta muốn thêm.

Ta sẽ phát triển thí dụ trên Hình 3 và áp dụng các điểm trên. Ta muốn xem xét ảnh hưởng của hàm lượng lipid đến năng lượng của thịt và tác động của mức protein và sắt đến ảnh hưởng này. Đoạn lệnh để thực hiện việc ấy là:

> yProtein=cut(Thit$Protein_g, breaks=c(0,10,20,100),
labels=c("Protein thâp","Protein trung bình","Protein cao")) > ySat=cut(Thit$Sat_mg, breaks=c(0,5,100), labels=c("Săt thâp","Săt cao"))
> Thit <- cbind(Thit, yProtein, ySat)
> ggplot(Thit, aes(Lipit_g, NangLuong_kcal)) + geom_point(aes(color=yProtein, shape=yProtein), size=I(3)) +
geom_smooth() +
facet_grid(ySat ~ yProtein, margin=T) +
ylim(0,800) + labs(x="Hàm lượng Lipit (%)", y="Năng Lượng (kcal/100 g)")

Kết quả được thể hiện trên Hình 4.

Hình 4 Ma trận các biểu đồ xy

Quan sát Hình 4 ta thấy :

  • Ngoài hai dòng tương ứng với hai mức hàm lượng sắt, ta có thêm một dòng NA. Đó là tập hợp của các phần tử không ghi giá trị hàm lượng sắt và ta cũng không loại bỏ các phần tử này bằng cú pháp na.rm = TRUE.
  • Ta có thêm cột biên bên phải và dòng dưới cũng có ký hiệu all do ta khai báo margin = T trong hàm facet_grid

facet_wrap

Cú pháp thông dụng của hàm này là :

facet_wrap( ~ bien)

Qua đó ta có thể hình dung rằng các biểu đồ con sẽ tạo thành một băng dài có chiều rộng băng là 1 (biểu đồ con) và chiều dài là số mức của bien. Tuy nhiên nếu số mức này khá lớn thì băng này sẽ xếp lại thành một số lớp do đó hình thành một số dòng và mỗi dòng có một số cột. Nếu ta không khai báo gì thêm, ggplot2 sẽ cố gắng sắp xếp sao cho số dòng và số cột bằng nhau hay sự chênh lệch giữa số dòng và số cột không quá lớn (thường số cột nhiều hơn số dòng). Ta có thể can thiệp và sự sắp xếp này bằng cách khai báo số dòng bằng đối số nrow hay khai báo số cột bằng đối số ncol.



Trang trướcVề đầu chương 


Trang web này được cập nhật lần cuối ngày 25/11/2018

R