R言語による電子カルテデータの二次利用

~R言語初心者がデータ処理を楽しめるように基本的内容中心のサイトです~

ggplot2で臨床経過図を、簡単に作成する

はじめに

研修医の頃は、学会発表等で症例の経過図を作らされたものです(パワポで)。カンファレンスでも経過図使って上級医に説明したり、何十回作ったかわかりません(涙)。

こういうやつ↓

f:id:r_beginner:20180623131148j:plain

通常、バイタルデータや血液データをエクセルで入力してプロットし、グラフ画像を並べて配置。グラフの上には使用した薬剤の経過を図示して、プレゼンすることが多いかと思います。
もちろんこだわりの経過図ができると満足感はありますが、ちょっとした経過図は簡単に作成したいものです。

そこで、あまりこだわる必要の無い経過図は、なるべく自動化しましょう。というのが今回のブログです。

サンプルデータの準備

1. 薬剤使用歴
2. 体重の経過
3. 肝機能(ALT)の経過

今回は、適当に作ったサンプルデータをダウンロードしてプロットしてみます。実際は、エクセル等でCSVファイルを作って、read.csv等で読み込んで使うことになるかと思います。

library(RCurl)
url <- getURL("https://raw.githubusercontent.com/Algo1970/EHR_data/master/drug_dataset.csv")
Drug_df <- read.csv(text = url, header = TRUE)
Drug_df

f:id:r_beginner:20180623135854j:plain

このような横長?データが出力されているかと思います。
プロット用に縦長データに変形します。今回はtidy::gatherを使いました。あとでプロットするときのために日付はDate型にしておきます。

Drug_df_long = tidyr::gather(Drug_df, key="category", value = "date", start_date, end_date)
Drug_df_long$date = as.Date(Drug_df_long$date)
Drug_df_long

f:id:r_beginner:20180623135958j:plain

同様に、体重、肝機能のデータも落としてきます。

url <- getURL("https://raw.githubusercontent.com/Algo1970/EHR_data/master/BW_dataset.csv")
BW_df <- read.csv(text = url, header = TRUE)
BW_df$date = as.Date(BW_df$date)
head(BW_df)

f:id:r_beginner:20180623140252j:plain

url <- getURL("https://raw.githubusercontent.com/Algo1970/EHR_data/master/ALT_dataset.csv")
ALT_df <- read.csv(text = url, header = TRUE)
ALT_df$date = as.Date(ALT_df$date)
head(ALT_df)

f:id:r_beginner:20180623140317j:plain

これで準備は整いました。3つのサンプルデータは、練習のためデータの開始日をあえてずらしてあります。

プロット

シンプルに3つのプロットを並べてみると、いろいろ問題点が見えてきます。

library(ggplot2)
library(gridExtra)
# drug_plot
p1 = ggplot(Drug_df_long, aes(x=date, y=drug_name)) + geom_line()
# BW_plot
p2 = ggplot(data = BW_df, aes(date, BW)) + geom_line()
# ALT_plot
p3 = ggplot(data = ALT_df, aes(date, ALT)) + geom_line()
# plotの配置
grid.arrange(p1, p2, p3, layout_matrix = matrix(1:3, nrow=3))

f:id:r_beginner:20180623143425j:plain

問題点
  • 薬剤名の文字数が多いので、薬剤プロットが右にずれる
  • データの開始日が違うので、日付がずれる

いろいろ方法はあるのかもしれませんが、時間もなかったので薬剤名、体重、ALT等y軸のラベルは削除し、geom_textで表示します(y軸のラベルの文字幅の影響が少なければ、そのままでも良いかもしれません)。
日付のズレは、3つのデータセットの日付のminとmaxを求めて、x軸をxlim(最小値, 最大値)で指定しておきます。

# 日付調整
library(dplyr)
Drug_min_date = Drug_df_long$date %>% min()
BW_min_date = BW_df$date %>% min()
ALT_min_date = ALT_df$date %>% min()
minDate = min(Drug_min_date, BW_min_date, ALT_min_date)

Drug_min_date = Drug_df_long$date %>% max()
BW_min_date = BW_df$date %>% max()
ALT_min_date = ALT_df$date %>% max()
maxDate = max(Drug_min_date, BW_min_date, ALT_min_date)

p1 = ggplot(Drug_df_long, aes(x=date, y=drug_name)) + 
  geom_line() + 
  xlim(minDate, maxDate) + 
  labs(y= "", title = "drug") +
  theme(axis.text.y = element_blank())
p2 = ggplot(data = BW_df, aes(date, BW)) + 
  geom_line() + 
  xlim(minDate, maxDate) + 
  labs(y= "", title = "BW") +
  theme(axis.text.y = element_blank())
p3 = ggplot(data = ALT_df, aes(date, ALT)) + 
  geom_line() + 
  xlim(minDate, maxDate) + 
  labs(y= "", title = "ALT") +
  theme(axis.text.y = element_blank())
grid.arrange(p1, p2, p3, layout_matrix = matrix(1:3, nrow=3))

f:id:r_beginner:20180623145821p:plain

これで日付、グラフのズレがなくなりました。あとは、薬剤名、数値をgeom_textで貼り付けて、お化粧するだけです。

サンプルプロット1(グレイ)

# plot_gray
p1 = ggplot(Drug_df_long, aes(x=date, y=drug_name)) + 
  geom_line(size=10, alpha = 0.4) +
  geom_text(aes(label = drug_name), color="black", size = 6, check_overlap = T) +
  xlim(minDate, maxDate) + 
  labs(x = "", y= "", title = "Drug") +
  theme_minimal() + 
  theme(panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        axis.text.x = element_blank(), 
        axis.text.y = element_blank()) 
p2 = ggplot(data = BW_df, aes(date, BW)) + 
  geom_line(color = "black", size = 3, alpha = 0.3) + 
  geom_point(color = "black", size = 3.5, alpha = 0.2) +
  geom_text(aes(label = BW), color="black", size = 6, check_overlap = T) +
  xlim(minDate, maxDate) + 
  labs(x = "", y= "", title = "BW") +
  theme_minimal() + 
  theme(panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        axis.text.x = element_blank(), 
        axis.text.y = element_blank()) 
p3 = ggplot(data = ALT_df, aes(date, ALT)) + 
  geom_line(color = "black", size = 3, alpha = 0.3) + 
  geom_point(color = "black", size = 3.5, alpha = 0.2) +
  geom_text(aes(label = ALT), color="black", size = 6, check_overlap = T) +
  xlim(minDate, maxDate) + 
  labs(x = "", y= "", title = "ALT") +
  theme_minimal() + 
  theme(panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        axis.text.x = element_text(size = 15), 
        axis.text.y = element_blank()) 
grid.arrange(p1, p2, p3, layout_matrix = matrix(1:3, nrow=3))

f:id:r_beginner:20180623151819p:plain

サンプルプロット2(カラー)

配色はお好みで…

# plot_color
p1 = ggplot(Drug_df_long, aes(x=date, y=drug_name, colour = drug_name)) + 
  geom_line(size=10, alpha = 0.4) +
  geom_text(aes(label = drug_name), size = 6, check_overlap = T) +
  scale_colour_discrete(guide=FALSE) + 
  xlim(minDate, maxDate) + 
  labs(x = "", y= "", title = "Drug") +
  theme_minimal() + 
  theme(panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        axis.text.x = element_blank(), 
        axis.text.y = element_blank()) 
p2 = ggplot(data = BW_df, aes(date, BW)) + 
  geom_line(color = "orange", size = 3, alpha = 0.5) + 
  geom_point(color = "orange", size = 3.5, alpha = 0.2) +
  geom_text(aes(label = BW), color="black", size = 6, check_overlap = T) +
  xlim(minDate, maxDate) + 
  labs(x = "", y= "", title = "BW") +
  theme_minimal() + 
  theme(panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        axis.text.x = element_blank(), 
        axis.text.y = element_blank()) 
p3 = ggplot(data = ALT_df, aes(date, ALT)) + 
  geom_line(color = "darkblue", size = 3, alpha = 0.3) + 
  geom_point(color = "darkblue", size = 3.5, alpha = 0.2) +
  geom_text(aes(label = ALT), color="black", size = 6, check_overlap = T) +
  xlim(minDate, maxDate) + 
  labs(x = "", y= "", title = "ALT") +
  theme_minimal() + 
  theme(panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        axis.text.x = element_text(size = 15), 
        axis.text.y = element_blank()) 
grid.arrange(p1, p2, p3, layout_matrix = matrix(1:3, nrow=3))

f:id:r_beginner:20180623152600p:plain

私はいつも、最上段が薬剤経過で、時々症状の経過を加え、二段から三段、四段組ぐらいの経過図が多いので、関数化してサッとプロットできるようにして使用しています。
ホントは、汎用的な関数にしたいなと思っているのですが、今は追い込まれているので今度にします。

IBDの難治例とか、原因不明の慢性肝炎、多剤使用している薬剤性肝障害等、経過図を書くと病態がわかりやすくなるので、すこしでも参考になればとブログを書いてみました。