Trong Matlab, để vẽ một heatmap mượt (độ phân giải cao) rất đơn giản. Rờ tất nhiên cũng có thể làm được điều đó. Bài viết ngắn sau đây trình bày cách interpolate và vẽ ra một heatmap thật mịn trong Matlab và R.
Bài viết bằng 2 ngôn ngữ để bạn tiện so sánh.
Những bạn nào muốn tìm hiểu hoặc trao đổi thêm về Matlab, mình rất sẵn lòng. Trong bối cảnh Data Science, mình nghĩ nếu thời gian cho phép, linh động trong nhiều ngôn ngữ lập trình đôi khi cũng cần thiết.
Dữ liệu test bao gồm số đo nồng độ X (value) từ 8 giờ sáng đến 6 giờ chiều và ở nhiều độ sâu khác nhau từ 0m đến 1.5m. Với heatmap cho bộ dữ liệu này ta sẽ có bức tranh nồng dộ X theo chiều sâu và theo thời gian.
Dữ liệu như sau
## X depth hour value hour1
## 1 1 0.0 10 60.98073 2017-10-13 10:00:00
## 2 2 0.1 10 61.82500 2017-10-13 10:00:00
## 3 3 0.2 10 66.85545 2017-10-13 10:00:00
## 4 4 0.3 10 59.94337 2017-10-13 10:00:00
## 5 5 0.4 10 63.57632 2017-10-13 10:00:00
## 6 6 0.5 10 45.16756 2017-10-13 10:00:00
Dùng ggplot2 để vẽ heatmap nhưng không interpolate, bức tranh sẽ rất loang lổ.
Dùng chế độ interpolate mặc định, bức tranh mịn hơn hẳn
Tự interpolate.
Interpolate 2 chiều bằng gói akima.
Các bước trên được thực hiện bởi đoạn code sau đây.
library(tidyverse)
#1. Import data
rm(list = ls())
df <- read.csv("/39_smooth_heatmap/smooth_heatmap.csv")
df$hour1 <- strptime(as.character(df$hour),"%H",tz="")
df$value <- df$value/100
df <- df[df$depth<1.5,]
raw <- df
#Plot Heatmap ######################
########################################
#No interpolation
ggplot(data = raw, aes(x=hour1,y=depth,fill = value)) + geom_tile()+
scale_y_reverse() + geom_raster(aes(fill = value),interpolate = F)+
scale_fill_gradient(low="green", high="darkgreen") + theme_minimal()+
scale_x_datetime(date_breaks = "1 hour", date_labels = "%H") +
xlab("") + theme(legend.position="top") + ylab("depth(m)")
#Interpolation with ggplot
ggplot(data = raw, aes(x=hour1,y=depth,fill = value)) + geom_tile()+
scale_y_reverse() + geom_raster(aes(fill = value),interpolate = T)+
scale_fill_gradient(low="green", high="darkgreen") + theme_minimal()+
scale_x_datetime(date_breaks = "1 hour", date_labels = "%H") +
xlab("") + theme(legend.position="top") + ylab("depth(m)")
#Manual interpolation
#Interpolate by depth
df <- list()
sequence <- c(8,9,10,11,12,13,14,15,16,17,18)
sequence <- c(0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1,1.1,1.2,1.3,1.4)
for (i in sequence){
ind <- which(raw$depth == i)
mat <- raw[ind,]
xout <- seq(0,max(mat$hour),by = 0.01)
yout <- approx(mat$hour, mat$value, xout = xout)$y
dframe <- data.frame(hour = xout, depth =i,value = yout)
n = i-7
df[[n]] <- dframe
}
df <- do.call(rbind,df)
df$hour1 <- strptime(as.character(df$hour),"%H",tz="")
ggplot(data = df, aes(x=hour1,y=depth,fill = value)) + geom_tile()+
scale_y_reverse() + geom_raster(aes(fill = value),interpolate = T)+
scale_fill_gradient(low="green", high="darkgreen") + theme_minimal()+
scale_x_datetime(date_breaks = "1 hour", date_labels = "%H") +
xlab("") + theme(legend.position="top") + ylab("depth(m)")
library(akima)
x= raw$hour
y= raw$depth
z= raw$value
a<- interp(x, y, z, xo=seq(min(x), max(x), length = 100),
yo=seq(min(y), max(y), length = 100), linear = TRUE,
extrap=FALSE, duplicate = "error", dupfun = NULL)
df1 <- data.frame(value = a$z)
image(as.matrix(df1), xlab = 'Hour', ylab = 'Depth')
Đoạn code sau đây để vẽ trong Matlab
clear all
%% Import data
filename = '/39_smooth_heatmap/smooth_heatmap.csv';
delimiter = ',';
startRow = 2;
formatSpec = '%q%q%q%q%[^\n\r]';
fileID = fopen(filename,'r');
data = textscan(fileID, formatSpec, 'Delimiter', delimiter, 'TextType', 'string', 'HeaderLines' ,startRow-1, 'ReturnOnError', false, 'EndOfLine', '\r\n');
fclose(fileID);
df = [str2double(data{1,2}) str2double(data{1,3}) str2double(data{1,4})];
ind = find(df(:,1) < 1.5);
df = df(ind,:);
Depth = df(:,1);
Hour = df(:,2);
Value = df(:,3);
Value = Value /100;
%% Plot heatmap
A = reshape(Value,15,11);
mat = A;
%// Define integer grid of coordinates for the above data
[X,Y] = meshgrid(1:size(mat,2), 1:size(mat,1));
%// Define a finer grid of points
[X2,Y2] = meshgrid(1:0.01:size(mat,2), 1:0.01:size(mat,1));
%// Interpolate the data and show the output
outData = interp2(X, Y, mat, X2, Y2, 'linear');
imagesc(outData);
%// Cosmetic changes for the axes
set(gca, 'XTick', linspace(1,size(X2,2),size(X,2)));
set(gca, 'YTick', linspace(1,size(X2,1),size(X,1)));
set(gca, 'XTickLabel', 8:18);
set(gca, 'YTickLabel', 0:0.1:1.4);
%% Editting plot
xlabel('Hour');
ylabel('Depth (m)');
zlabel('value');
Hình trong Matlab