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.

1.Dữ Liệu

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')  

2. Matlab

Đ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