Mukku John Blog

取り組んでいること を つらつら と

ggplot2を使って、軸を制御する-4

R グラフィックス クックブック 25回目

ggplot2パッケージを利用して、軸を制御していきます。
今回は、軸の線を強調したり、対数軸を用いてみます。

軸の線の強調

こちらのグラフをベースにします。
f:id:MukkuJohn:20161024221725p:plain

x軸・y軸に線を引くためには、theme()を使い、axis.line引数を指定します。

#x軸・y軸に線を引き、強調する
ベースプロット + 
  theme(axis.line = element_line(colour="black"))

f:id:MukkuJohn:20161024221859p:plain
x軸・y軸に黒線が引かれ、くっきりしました。


プロット領域の境界線を持つ場合は、あえて消す指定を行う必要があります。
例えば、theme_bw()を使うような場合です。

ベースプロット + 
  theme_bw()

f:id:MukkuJohn:20161024222251p:plain

上のプロットのように、境界線がある場合は、ブランクを指定してから追加します。

#panel.border引数に、ブランクを指定します
#axis.line引数に、線を指定します
ベースプロット + theme_bw() +
  theme(panel.border = element_blank(),
        axis.line = element_line(colour="black"))

f:id:MukkuJohn:20161024222518p:plain

element_line()ですが、size引数で線の太さを指定できます。

ベースプロット + theme_bw() +
  theme(panel.border = element_blank(),
        axis.line = element_line(colour="black",size=4))

f:id:MukkuJohn:20161024222801p:plain

左下を見ると、微妙に開いています。
重ねて表示するためには、lineend引数にsquareを指定します。

ベースプロット + theme_bw() +
  theme(panel.border = element_blank(),
        axis.line = element_line(colour="black",size=4,lineend="square"))

f:id:MukkuJohn:20161024222811p:plain

対数

対数を使うと、軸上の距離が割合で表現できます。
今まで扱っていたのは、線形軸と呼びます。軸上の距離は一定の変化量です。

R: Brain and Body Weights for 28 Speciesデータセットを使います。
動物の体重(kg)と脳の重さ(g)のデータセットです。

> head(Animals)
                    body brain
Mountain beaver     1.35   8.1
Cow               465.00 423.0
Grey wolf          36.33 119.5
Goat               27.66 115.0
Guinea pig          1.04   5.5
Dipliodocus     11700.00  50.0

> str(Animals)
'data.frame':	28 obs. of  2 variables:
 $ body : num  1.35 465 36.33 27.66 1.04 ...
 $ brain: num  8.1 423 119.5 115 5.5 ...

x軸に体重、y軸に脳の重さをマッピングし、行の名前をラベルに表示します。

ggplot(Animals, aes(x=body,y=brain,label=rownames(Animals))) + 
  geom_text(size=3)

f:id:MukkuJohn:20161024223532p:plain
これだと、体重や脳の重さが大きいデータポイントのせいで、軸が拡張され
ほとんどのデータポイントが左下に集まってしまっています。

このような場合、軸を対数軸に変更し、軸上の距離を割合で表現した方が良いです。
対数軸を使うには、scale_x_log10()scale_y_log10()を使います。

ベースプロット + 
  scale_x_log10() + scale_y_log10()

f:id:MukkuJohn:20161024224303p:plain
データの分布が見たいので、散布図を使っています。データポイントの値が見たいわけではないです。

scale_x_log10()scale_y_log10()を使うと、目盛りが自動で設定されます。
目盛りを指定するためには、breaks引数を指定します。

ベースプロット + 
  scale_x_log10(breaks=10^(-1:5)) + scale_y_log10(breaks=10^(0:3))

f:id:MukkuJohn:20161024224600p:plain

x軸を見ると1e-01、1e+00、1e+01と表現されていますが、
指数表記に変換するためには、scalesライブラリのtrans_format()を使います。

library(scales)
ベースプロット + 
  scale_x_log10(breaks=10^(-1:5),
                labels=trans_format("log10",math_format(10^.x))) + 
  scale_y_log10(breaks=10^(0:3),
                labels=trans_format("log10",math_format(10^.x)))

f:id:MukkuJohn:20161024225044p:plain

scale_x_log10()scale_y_log10()を使い、log10の対数を扱いましたが
自然対数はlog2などの対数を扱うこともできます。

#x軸は自然対数、y軸はlog2です。軸で基数が異なります。
ベースプロット + 
  scale_x_continuous(trans = log_trans(),
                     breaks=trans_breaks("log",function(x) exp(x)),
                     labels=trans_format("log",math_format(e^.x))) +
  scale_y_continuous(trans=log2_trans(),
                     breaks=trans_breaks("log2",function(x) 2^x),
                     labels=trans_format("log2",math_format(2^.x)))

f:id:MukkuJohn:20161024225511p:plain

散布図を使って、x軸・y軸の両方の軸に対数を使いましたが、
片方の軸だけに指定することもできます。
f:id:MukkuJohn:20161024230110p:plain
2010年以降は指数関数的に増えています。対数軸の出番です。

#y軸だけを対数軸にします。目盛りを指定します。
上のグラフ +
  scale_y_log10(breaks=c(2,10,50,250))

f:id:MukkuJohn:20161024230150p:plain
上のグラフより、変化が理解できますね。

対数軸の目盛り

対数軸に目盛りを追加するには、annotation_logticks()を使います。

ベースプロット + annotation_logticks() + 
  scale_x_log10(breaks = 10^(-1:5),
                labels = trans_format("log10", math_format(10^.x))) +
  scale_y_log10(breaks = 10^(0:3),
                labels = trans_format("log10", math_format(10^.x)))

f:id:MukkuJohn:20161024230649p:plain
長い目盛り線が10の累乗、中間の長さの目盛り線が5の累乗を指しています。

プロットを見ると、目盛り記号の色(灰色?)と目盛り線の色(黒)が異なり、
補助目盛り線(薄い白い線)が5の累乗の位置からずれています。

目盛り記号の色と目盛り線の色を合わせるには、theme_bw()を使います。

ベースプロット + annotation_logticks() +
  scale_x_log10(breaks = 10^(-1:5),
                labels = trans_format("log10", math_format(10^.x))) +
  scale_y_log10(breaks = 10^(0:3),
                labels = trans_format("log10", math_format(10^.x))) +
  theme_bw()

f:id:MukkuJohn:20161024232811p:plain
目盛り記号の色と目盛り線の色が合いました!

補助目盛り線と5の累乗の位置を合わせるには、minor_breaks()を使います。
minor_breaks()の引数に、自身で計算した値を設定する必要があります。
x軸、y軸ともにlog10なので、log10(5*10^累乗値) ⇒ log10(5) + 累乗値 です。

ベースプロット + annotation_logticks() +
  scale_x_log10(breaks = 10^(-1:5),
                labels = trans_format("log10", math_format(10^.x)),
                minor_breaks = log10(5) + -2:5) +
  scale_y_log10(breaks = 10^(0:3),
                labels = trans_format("log10", math_format(10^.x)),
                minor_breaks = log10(5) + -1:3) +
  theme_bw() +
  coord_fixed()

f:id:MukkuJohn:20161024232436p:plain
補助目盛り線と、中間の5の累乗の位置が合いました!

今日の全部入り

  • 軸の線を強調する
  • 対数軸を使用する
  • 対数軸の目盛り記号と目盛り線の色をそろえる
  • 補助目盛り線と対数軸の中間線の位置をそろえる
ベースプロット + annotation_logticks() +
  scale_x_log10(breaks = 10^(-1:5),
                labels = trans_format("log10", math_format(10^.x)),
                minor_breaks = log10(5) + -2:5) +
  scale_y_log10(breaks = 10^(0:3),
                labels = trans_format("log10", math_format(10^.x)),
                minor_breaks = log10(5) + -1:3) +
  theme_bw() +
  coord_fixed() +
  theme(panel.border = element_blank(),
        axis.line = element_line(colour="grey60",size=.1,lineend="square"))

f:id:MukkuJohn:20161024233110p:plain


次回は、円形グラフを扱ってみます。

Power BIの軸や凡例の並び順を調べてみた

Power BI Desktop

2016/10/25追記

このツールですが、軸や凡例の並び順が指定できません。
できます。

powerbi.microsoft.com

並び順の指定はこちら
mukkujohn.hatenablog.com


これから下は、指定方法が分からない状況で、どうせ文字コードだよねということを
確認している内容です。



英数字を利用している部分はいいのですが、
日本語を軸や凡例にマッピングすると、何順なのかさっぱりです。

グラフの書式を確認しても、並び順を指定できそうな感じがしません。
それ以上に、目盛りラベルのフォントサイズ大きくしたいんですが、、、。
f:id:MukkuJohn:20161016132236p:plain

UIで提供されていないのであれば、ツール側で勝手にやっているはずで、
思いつくのが、文字コードか?なので、文字コード通りか調べてみました。
どの文字コードが調べても出てきませんでした。。。おそらくUTF-8だろうと仮定して進めます。

利用するデータ

同じデータをUTF-8とShift-JIS(ANSI)で用意しました。

名前 科目 点数
数学 80
国語 60
社会 50
英語 90
理科 70
数学 70
国語 80
社会 60
英語 90
理科 40
数学 10
国語 30
社会 40
英語 20
理科 100

文字コードの並び順については、このサイトを利用させて頂きました。
ash.jp

名前列でSJISUTF-8で並び順が異なる文字を利用しています。

JIS SJIS EUC UTF-8 UTF-16
26 20 3A34 8DB2 BAB4 E4BD90 4F50
45 04 4D24 9743 CDA4 E4BD91 4F51
35 02 4322 9241 C3A2 E4BD86 4F46

並び順は下記の順番です。

文字コード 1 2 3
UTF-8
Shift-JIS

Power BI Desktop

まずは、Power BI Desktopを使って確認していきます。

UTF-8版のCSVと、Shift-JIS版のCSVを両方取り込みます。

UTF-8版のインポート
f:id:MukkuJohn:20161016143402p:plain

Shift-JIS版のインポート
f:id:MukkuJohn:20161016143529p:plain

x軸に名前、y軸に点数をマッピングします。
f:id:MukkuJohn:20161016143850p:plain

見づらいですが、x軸の上から確認すると佐→但→佑となっています。
(目盛りラベルを大きくしたいと、すごい思いました。)

意外な感じですが、Shift-JISで並んでいるようです。

凡例

x軸に科目、y軸に点数、凡例に名前をマッピングします。
f:id:MukkuJohn:20161016145034p:plain

凡例はフォントサイズが大きくできるので確認しやすいです。
こちらも、佐→但→佑となっています。

データのエクスポート

グラフからエクスポートしたデータファイルの文字コードを確認してみます。
このように、グラフの右上の…からエクスポートします。
f:id:MukkuJohn:20161016145329p:plain

Notepadで開いて確認してみます。

UTF-8ファイルデータのグラフからエクスポートしたファイルを選びます。
開く時に、UTF-8を指定します。
f:id:MukkuJohn:20161016145900p:plain

文字化けはしていません。
エクスポートするとUTF-8になるのでしょうか?
f:id:MukkuJohn:20161016150030p:plain


今度は、開く時にANSIを指定します。
f:id:MukkuJohn:20161016150153p:plain

文字化けしました。
f:id:MukkuJohn:20161016150250p:plain

Shift-JISファイルデータも結果は同じでした。


これまでをまとめると、Power BI Desktop上の軸や凡例はShift-JISで並んでいて、
データをエクスポートすると、UTF-8です。

Power BI Service

Power BI Desktopで作成したレポートを発行し、ブラウザで確認します。

佐→但→佑となっています。
f:id:MukkuJohn:20161016151012p:plain

凡例

佐→但→佑となっています。
f:id:MukkuJohn:20161016151047p:plain

データのエクスポート

Power BI Desktopからエクスポートした時と同様、UTF-8になっています。

Shift-JISでの確認

予想に反して、軸や凡例の並び順がShift-JISで行われているそうなので、
Shift-JISコードでの前後文字で確認しました。

JIS SJIS EUC UTF-8 UTF-16
26 19 3A33 8DB1 BAB3 E4BA9B 4E9B
26 20 3A34 8DB2 BAB4 E4BD90 4F50
26 21 3A35 8DB3 BAB5 E58F89 53C9

となるはずです。

先ほどの手順と同様に、文字コードUTF-8版とShift-JIS版のファイルを使います。
UTF-8
f:id:MukkuJohn:20161016153030p:plain

Shift-JIS版
f:id:MukkuJohn:20161016153055p:plain

同じグラフを使って、軸と凡例の並び順を確認します。
f:id:MukkuJohn:20161016153500p:plain
軸は、となっています。
(目盛りラベルを大きくしたいぃぃぃぃ。)

凡例も、となっています。
f:id:MukkuJohn:20161016153532p:plain

Power BI Serviceに発行して確認しても、同じ結果でした。
f:id:MukkuJohn:20161016154140p:plain
f:id:MukkuJohn:20161016154152p:plain

まとめ

Power BIにおける日本語データの扱いは下記のようです。

  • 軸や凡例の並び順:Shift-JIS(ANSI)
  • エクスポート:UTF-8

困るのがこの辺でしょうねぇ。

  1. エクスポートしたCSVファイルを、ファイルクリックからExcelで開く
  2. Shift-JISコードの並び順とは、違う順番を使う

1つ目は、既定でShift-JIS(ANSI)になっているだけなので、
ファイルクリックからExcelを起動する事をやめましょう。

新規でExcelを起動して、データタブからインポートする形で取り込みましょう。
取り込む途中で文字コードが指定できます。

2016/10/25追記
並び順は指定できます。


2つ目は、佐藤、鈴木、田中とか、あいうえお順だと順番変わるんですよね。

  • あいうえお順:佐藤 → 鈴木 → 田中
  • Shift-JIS順:佐藤 → 田中 → 鈴木

なので、並び順にはこだわらない or 並び順用の列を追加する かな。

ただ、並び順用に、1.佐藤 2.鈴木 3.田中の列を用意して、マッピングすると
その値が使われるので、「1.」この部分何?となります。
f:id:MukkuJohn:20161016160548p:plain


並び順の指定目盛りラベルを大きくするをしてほしいものです。

ggplot2を使って、軸を制御する-3

R グラフィックス クックブック 24回目

ggplot2パッケージを利用して、軸を制御していきます。
今回は、目盛りラベル/軸ラベルのテキストを制御します。

目盛りラベルのテキスト

こちらのグラフのy軸の目盛りラベルを対象にします。
f:id:MukkuJohn:20161011203535p:plain
y軸の目盛りラベルは、50、55、60、65、70で設定されています。


目盛りを変更するためには、scale_y_continuous()breaks引数を指定します。

#目盛りを、50,56,60,66,72に設定します。
ベースのグラフ + 
  scale_y_continuous(breaks=c(50,56,60,66,72))

f:id:MukkuJohn:20161011210248p:plain

この50,56,60,66,72の目盛りのテキスト(ラベル)を変更するためには、
scale_y_continuous()labels引数を指定します。

ベースのグラフ + 
  scale_y_continuous(breaks=c(50,56,60,66,72),
                     labels=c("Tiny","Really\nshort","Short","Medium","Tallish"))

f:id:MukkuJohn:20161011210508p:plain

このbreaks引数とlabels引数の要素数は、同じである必要があります。
素数が異なる場合は、エラーになります。

Error: Breaks and labels have unequal lengths

labels引数ですが、別途作成したフォーマッタ関数を指定できます。

#インチをフィートとインチの形式に変換します
footinch_formatter <- function(x){
  foot <- floor(x/12)
  inch <- x %% 12
  return(paste(foot,"'",inch,"\"",sep=""))
}

footinch_formatter(56:64)
[1] "4'8\""  "4'9\""  "4'10\"" "4'11\"" "5'0\""  "5'1\""  "5'2\""  "5'3\""  "5'4\"" 

上で作成した関数をlabels引数に指定します。

#ggplotが自動で設定した目盛り値を変換してグラフに設定します
ベースのグラフ + 
  scale_y_continuous(labels=footinch_formatter)

f:id:MukkuJohn:20161011211103p:plain


さらに目盛りのテキスト(ラベル)は、theme()axis.text.y引数に、
element_text()を設定することで、体裁を設定できます。
(x軸の場合は、axis.text.x引数)

設定項目 element_text()の引数
角度 angle
水平位置 hjust(0:左揃え~1:右揃え)
垂直位置 vjust(0:下揃え~1:上揃え)
サイズ size
colour
スタイル face(bold or italic)
フォントファミリー family

まとめて指定する場合は、こんな感じになります。

ベースのグラフ + 
  scale_y_continuous(breaks=c(50,56,60,66,72),
                     labels=c("Tiny","Really\nshort","Short","Medium","Tallish")) +
  theme(axis.text.y = element_text(angle = 30, hjust = 1, 
                                   vjust = 0 , size = rel(1.5), 
                                   colour = "darkred", face = "italic"))

f:id:MukkuJohn:20161011213241p:plain

軸ラベルのテキスト

軸ラベル(x軸やy軸のタイトル)を変更する方法は、3通りあります。

  1. xlab()ylab()を使う
  2. labs()x引数とy引数を指定する
  3. scale_x_continuous()scale_y_continuous()name引数を指定する

下の3つは全て同じ結果が得られます。

ベースのグラフ + 
  xlab("Age in years") + ylab("Height in inches")

ベースのグラフ + 
  labs(x = "Age in years", y = "Height in inches")

ベースのグラフ + 
  scale_x_continuous(name = "Age in years") +
  scale_y_continuous(name = "Height in inches")

f:id:MukkuJohn:20161011213605p:plain

軸ラベルも、目盛りラベルと同様に、テキストの体裁を変更できます。
theme()の引数が微妙に異なります。

軸ラベル 目盛りラベル
axis.title.y axis.text.y

(x軸は、yの部分をxにします)

axis.title.y引数に、element_text()を指定します。

ベースのグラフ + ylab("Height\n(inches)") +
  theme(axis.title.y=
          element_text(angle=0,
                       face="italic",
                       colour="darkred",
                       size=14))

f:id:MukkuJohn:20161011220046p:plain


この記事の全部入りは、こんな感じになります。

#目盛りラベルも軸ラベルも設定します
ベースのグラフ + 
  scale_y_continuous(breaks=c(50,56,60,66,72),
                     labels=c("Tiny","Really\nshort","Short","Medium","Tallish"),
                     name = "Height\n(inches)") +
  theme(axis.text.y = element_text(angle = 30, hjust = 1, 
                                   vjust = 0 , size = rel(1.5), 
                                   colour = "darkred", face = "italic"),
        axis.title.y = element_text(angle = 0, face = "bold",
                                    colour = "grey",size = 15,
                                    vjust = 1), 
        axis.title.x = element_text(hjust = 1,size = rel(2)))

f:id:MukkuJohn:20161011220649p:plain

ggplot2を使って、軸を制御する-2

R グラフィックス クックブック 23回目

ggplot2パッケージを利用して、軸を制御していきます。
今回は、軸のスケール比や目盛り軸を手動で設定します。

軸のスケール

こちらのデータセットを使います。
ハーフマラソンフルマラソンのタイムのデータです。

> str(marathon)
'data.frame':	520 obs. of  2 variables:
 $ Half: num  66.8 67.9 68.7 69.9 70 ...
 $ Full: num  141 147 148 157 147 ...

> head(marathon)
      Half     Full
1 66.80000 141.4833
2 67.88333 147.2667
3 68.70000 147.8833
4 69.90000 156.7500
5 69.95000 147.4333
6 70.11667 150.0000
sp <- ggplot(marathon, aes(x=Half, y=Full)) + geom_point()
sp

f:id:MukkuJohn:20161008150150p:plain

x軸が30m間隔、y軸が50m間隔になっていますが、どちらの軸も同じ指標です。
同じ指標ですので、軸は同じ間隔に揃えた方が、分布が分かりやすいです。

同じ間隔に揃えるためには、coord_fixed()を使い、さらに、
scale_y_continuous()scale_x_continuous()breaks引数を指定します。

#0-420の間を30間隔にします
sp + coord_fixed() +
  scale_y_continuous(breaks=seq(0,420,30))+
  scale_x_continuous(breaks=seq(0,420,30))

f:id:MukkuJohn:20161008151144p:plain

この散布図は、ハーフマラソンフルマラソンのタイムの分布のため
x軸のハーフマラソン側を、y軸のフルマラソンのスケールの1/2にした方が伝わりやすいかもしれません。

スケール比率を変更するためには、coord_fixed()ratio引数を指定します。

sp + coord_fixed(ratio=1/2) +
  scale_y_continuous(breaks=seq(0,420,30))+
  scale_x_continuous(breaks=seq(0,420,15))

f:id:MukkuJohn:20161008151446p:plain

目盛りの位置

ここからは、R: Results from an Experiment on Plant Growthを使います。

p <- ggplot(PlantGrowth, aes(x=group,y=weight)) + 
  geom_boxplot()
p

f:id:MukkuJohn:20161008152052p:plain

デフォルトで適切な位置に目盛りを設定してくれますが、手動で設定するためには、
scale_y_continuous()scale_x_continuous()breaks引数を指定します。

p + scale_y_continuous(breaks=c(4,4.25,4.5,5,6,8))

f:id:MukkuJohn:20161008152233p:plain

指定した目盛りが適用されるのは、主目盛り線になります。
補助目盛り線は、主目盛り線の中間の位置に描かれます。

等間隔で、breaks引数を指定する際に、seq()関数や:演算子を使うと楽です。

> seq(4,7,by=.5)
[1] 4.0 4.5 5.0 5.5 6.0 6.5 7.0
> 5:10
[1]  5  6  7  8  9 10

離散値の軸に対しては、scale_x_discrete()scale_y_discrete()関数に、
limits引数を指定して、順序の設定と要素の除外を行い、
breaks引数を指定して、ラベルの表示設定を行います。

#trt2とctrl列だけを表示して、ctrlだけラベルで設定する
p + scale_x_discrete(limits=c("trt2","ctrl"),breaks="ctrl") 

f:id:MukkuJohn:20161008153118p:plain

目盛りとラベルの非表示

目盛りのラベルを非表示にする場合は、theme()axis.text.y引数や
axis.text.x引数に、element_blank()を指定します。

#y軸の目盛りラベルを非表示にします
p + theme(axis.text.y = element_blank())

f:id:MukkuJohn:20161008153639p:plain

チョコっと出ている黒い目盛り記号を非表示するには、
axis.ticks引数に、element_blank()を指定します。

#軸の指定がないため、両方の軸の目盛り記号が非表示になります。
p + theme(axis.ticks = element_blank(), axis.text.y = element_blank())

f:id:MukkuJohn:20161008153948p:plain

主目盛り線を非表示にするには、
scale_y_continuous()scale_x_continuous()関数の
breaks引数に、NULLを指定します。

#y軸の目盛り線を非表示にします。
p + scale_y_continuous(breaks=NULL)

f:id:MukkuJohn:20161008154148p:plain


目盛りに関して、制御できる項目は3か所です。

  • 目盛りラベル
  • 目盛り記号(黒いチョッとだけで出てる線)
  • 目盛り線

軸内の位置指定は、軸が連続値か離散値で指定方法が異なります。

  • 連続値:breaksで指定する(非表示にするには、NULLを指定する)
  • 離散値:limitsで指定する(非表示にするには、その要素を含めない)

目盛りラベル、目盛り線は、軸ごとに制御可能ですが、
目盛り記号だけは、両軸に適用されてします。

次回は、目盛りラベルのテキストや、軸ラベルのテキストを制御します。

ggplot2を使って、軸を制御する-1

R グラフィックス クックブック 22回目

ggplot2パッケージを利用して、軸を制御していきます。

そもそもデフォルトで、適切な軸を表示してくれますが、
軸ラベルや、目盛りの数、位置を制御することで、見る人の解釈を助けます。

利用するデータ、ベースのグラフ

R: Results from an Experiment on Plant Growthデータセットを使います。

x軸にgroup、y軸にweightをマッピングした箱ひげ図をベースにします。

p <- ggplot(PlantGrowth, aes(x=group,y=weight)) + 
  geom_boxplot()
p

f:id:MukkuJohn:20161003214042p:plain

x軸とy軸を反転する

散布図は、x軸とy軸にマッピングしている変数を交換すれば良いですが
他の幾何オブジェクトは、交換するとグラフとして成り立ちません。

#箱ひげ図で、x軸とy軸の変数を交換してみる...
> ggplot(PlantGrowth, aes(x=weight, y=group)) +
+ geom_boxplot()
Warning messages:
1: position_dodge requires constant width: output may be incorrect 
2: position_dodge requires non-overlapping x intervals 

f:id:MukkuJohn:20161003214535p:plain
マッピングを交換した箱ひげ図…そもそも成り立ちません。

このように、x軸とy軸を同等に扱わないグラフの
x軸とy軸を交換には、coord_flip()を使います。

p + coord_flip()

f:id:MukkuJohn:20161003214932p:plain


ベースのグラフは、x軸の左から、"ctrl","trt1","trt2"となっていますが、
交換後のグラフは、y軸の下から、"ctrl","trt1","trt2"となっています。

交換前後で、左から始まりが、下から始まりに変わりました。

左から右へ読んでいたグラフを、下から上へ読むことを許容できれば良いのですが、
出来ない場合は、順序の並び順を制御して、上から始まりに変えられます。

#x軸に対して、並び替えを逆にします。
p + coord_flip() + 
  scale_x_discrete(limits = rev(levels(PlantGrowth$group)))

f:id:MukkuJohn:20161003215647p:plain
上から始まりになりました。

連続値の軸の範囲を設定する

x軸やy軸の範囲を設定するには、xlim()ylim()を使います。

#y軸の表示範囲を0から、weightの最大値までにします。
p + ylim(0, max(PlantGrowth$weight))

f:id:MukkuJohn:20161003220044p:plain
3.5から6の範囲で表示されていた箱ひげ図を、0から6の範囲で表示になったため
箱がつぶれているように見えます。これでは、データ分布が分からないですね。

上のグラフは、ylim()を使いましたが、scale_y_continuous()も同じです。

#ylim(0, max(PlantGrowth$weight))と同じです。
p + scale_y_continuous(limits = c(0, max(PlantGrowth$weight)))


例えば、ylim()で範囲を設定し、scale_y_continuous()で目盛り線を消す場合など、
ylim()scale_y_continuous()と同時に使う場合は、注意が必要です。

p + ylim(0,10) + scale_y_continuous(breaks=NULL)

f:id:MukkuJohn:20161003220917p:plain
目盛り線が消えていますが、y軸の範囲が設定されていません。

p + scale_y_continuous(breaks=NULL) + ylim(0,10)

f:id:MukkuJohn:20161003220926p:plain
y軸の範囲が設定されていますが、目盛り線が消えていません。

両方同時に利用すると、後者の関数だけ適用されます。
これを避けるためには、scale_y_continuous()だけを利用します。

p + scale_y_continuous(limits=c(0, 10), breaks=NULL)

f:id:MukkuJohn:20161003221138p:plain
0から10の範囲を設定していますが、目盛り線を消したので分かりません。。。

この範囲指定ですが、範囲外のデータは除去してグラフが作成されます。

#グラフは、weightが5~6.5の値だけが考慮される
p + scale_y_continuous(limits=c(5,6.5))
Warning message:
Removed 13 rows containing non-finite values (stat_boxplot). 

13行除去されているエラーメッセージが出ています。
f:id:MukkuJohn:20161003221358p:plain

ylim()scale_y_continuous()を使って、範囲を狭める場合、
範囲外のデータは除去されるため、グラフにズームインすることはできません。

データを除去せず、ズームイン・アウトする場合は、coord_cartesian()を使います。

#データは除去されず、5~6.5の範囲に寄る
p + coord_cartesian(ylim = c(5,6.5))

f:id:MukkuJohn:20161003222148p:plain

最後に、片方向のみに範囲を拡張するには、expand_limits()を使います。

p + expand_limits(y=0)

f:id:MukkuJohn:20161003222426p:plain

expand_limits()ですが、拡張のため範囲を狭める関数ではありません。
そのため、データが存在するポイントを指定しても無視された感じで動きます。

#そもそもどこを基準に、y=5に拡張しているのか分からないですが、、、
p + expand_limits(y=5)

f:id:MukkuJohn:20161003222602p:plain

連続値を逆転する

ベースのグラフは、下から上に向けて、数値が大きくなっていきますが、
上から下に向けて、数値を大きくします。
読みづらい気もしますが、逆転するためには、scale_y_reverse()を使います。

p + scale_y_reverse()

f:id:MukkuJohn:20161003222734p:plain


ylim()の引数で、上限値~下限値の順で指定すると、同様の結果が得られます。

p + ylim(6.5, 3.5)

f:id:MukkuJohn:20161003222946p:plain

軸を逆転して、範囲も設定する場合は、scale_y_reverse()limits引数を指定します。

#範囲外のデータは除去されることに注意です
p + scale_y_reverse(limits=c(5,3))
Removed 17 rows containing non-finite values (stat_boxplot). 

f:id:MukkuJohn:20161003223143p:plain

離散値軸の順番を変更する

ベースのグラフのx軸は、左から"ctrl","trt1","trt2"となっています。
この並びを変更するためには、scale_x_discrete()を使います。

p + scale_x_discrete(limits=c("trt1","ctrl","trt2"))

f:id:MukkuJohn:20161003223744p:plain

このscale_x_discrete()ですが、一部の要素だけを図に表示することもできます。

#ctrl列を除きます
p + scale_x_discrete(limits=c("trt1","trt2"))

f:id:MukkuJohn:20161003224025p:plain

今回は、軸の入れ替えや逆転、範囲などを制御しました。

次回は、スケール比や、目盛り軸を制御します。

ggplot2を使って、注釈を入れる-2

R グラフィックス クックブック 21回目

ggplot2パッケージを利用して、図内に注釈を入れます。

前回の記事で、annotate()を使ってテキストや線分、網掛けや
gridパッケージを使って矢印を、図内にプロットしました。
mukkujohn.hatenablog.com


今回は、色をあえて変えることでの強調表示やエラーバー - Wikipediaを扱います。

強調表示

こちらのデータセットを使います。
R: Results from an Experiment on Plant Growth

> str(PlantGrowth)
'data.frame':	30 obs. of  2 variables:
 $ weight: num  4.17 5.58 5.18 6.11 4.5 4.61 5.17 4.53 5.33 5.14 ...
 $ group : Factor w/ 3 levels "ctrl","trt1",..: 1 1 1 1 1 1 1 1 1 1 ...

強調表示を行う下準備として、group列の値が"trt1"である事を示す列を追加します。

pg <- PlantGrowth
pg$h1 <- "no"
pg$h1[pg$group=="trt1"] <- "yes"

> str(pg)
'data.frame':	30 obs. of  3 variables:
 $ weight: num  4.17 5.58 5.18 6.11 4.5 4.61 5.17 4.53 5.33 5.14 ...
 $ group : Factor w/ 3 levels "ctrl","trt1",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ h1    : chr  "no" "no" "no" "no" ...

h1列でグループ化した箱ひげ図をプロットします。

p <- ggplot(pg,aes(x=group,y=weight,fill=h1)) +
  geom_boxplot()
p

f:id:MukkuJohn:20160929200129p:plain
このグラフですと、どのグループの箱を見れば良いか分かりません。

そこであえて、塗りつぶしの色を手動で設定することで、
目につく箱を指定します。

手動で塗りつぶし色を指定するためには、scale_fill_manual()を使います。

#yes or no の2つの値であるh1をfillにマッピングしているため、
#塗りつぶし色も2色を指定する
p + scale_fill_manual(values=c("grey85","#FFDDCC"))

f:id:MukkuJohn:20160929200622p:plain

3levelsのgroup列をfillにマッピングした場合は、
scale_fill_manual()で3色指定します。

ggplot(PlantGrowth,aes(x=group,y=weight,fill=group)) +
  geom_boxplot() +
  scale_fill_manual(values=c("grey85","lightblue","#FFDDCC"))

f:id:MukkuJohn:20160929200836p:plain

levels数より多く指定しても、多い部分は無視されて図がプロットされます。

逆にlevels数に満たない場合はエラーになります。

Error: Insufficient values in manual scale. 3 needed but only 1 provided.

エラーバー

こちらのデータから、Cultivarがc39であるデータセットを使います。

> str(cabbage_exp)
'data.frame':	6 obs. of  6 variables:
 $ Cultivar: Factor w/ 2 levels "c39","c52": 1 1 1 2 2 2
 $ Date    : Factor w/ 3 levels "d16","d20","d21": 1 2 3 1 2 3
 $ Weight  : num  3.18 2.8 2.74 2.26 3.11 1.47
 $ sd      : num  0.957 0.279 0.983 0.445 0.791 ...
 $ n       : int  10 10 10 10 10 10
 $ se      : num  0.3025 0.0882 0.311 0.1408 0.2501 ...

subset()を使って、条件に合致するデータだけ選択・取得します。

ce <- subset(cabbage_exp, Cultivar == "c39")

棒グラフを作成します。

ggplot(ce, aes(x=Date,y=Weight)) +
  geom_bar(fill="white",colour="black",stat = "identity") 

f:id:MukkuJohn:20160929201857p:plain

上のグラフにエラーバーを追加しますが、
データセット内に、平均の標準偏差であるse列があるため、
この値を、geom_errorbar()を使って、追加します。

#y軸に対して、開始値:ymin~終了値:ymaxとして指定します。
#widthは、エラーバーの幅です。良さげな値を模索して指定します。
上のグラフ +
  geom_errorbar(aes(ymin=Weight-se,ymax=Weight+se),width=.2)

f:id:MukkuJohn:20160929202131p:plain

折れ線グラフでも同様です。

#折れ線→マーク→エラーバーの順でプロットしてます。
ggplot(ce, aes(x=Date,y=Weight)) +
  geom_line(aes(group=1)) +
  geom_point(size=4) +
  geom_errorbar(aes(ymin=Weight-se,ymax=Weight+se),width=.2)

f:id:MukkuJohn:20160929202606p:plain

このエラーバーですが、グループ化された棒グラフや折れ線グラフの場合、
pisitionを横にずらす必要があります。

ずらさないと、エラーバーがどちらのグループのバーか分かりません。
f:id:MukkuJohn:20160929202741p:plain

エラーバーをずらす場合は、geom_errorbar()内で
positionを指定します。

ggplot(cabbage_exp, aes(x=Date,y=Weight,fill=Cultivar)) +
  geom_bar(position="dodge",stat="identity")+
  geom_errorbar(aes(ymin=Weight-se,ymax=Weight+se),
                position = position_dodge(.9),width=.2)

f:id:MukkuJohn:20160929203018p:plain

折れ線グラフ

#複数回利用するため、オブジェクトに格納
pd <- position_dodge(.3)
#エラーバー → 折れ線 → マークの順にプロット
ggplot(cabbage_exp,aes(x=Date,y=Weight,colour=Cultivar,group=Cultivar))+
  geom_errorbar(aes(ymin=Weight-se,ymax=Weight+se),
                width=.2,size=.25,colour="black",position=pd)+
  geom_line(position=pd)+
  geom_point(position=pd,size=2.5)

f:id:MukkuJohn:20160929203248p:plain

ファセット

各ファセットに注釈を入れていきます。
mpg. ggplot2 2.1.0データセットを使います。

> str(mpg)
'data.frame':	234 obs. of  11 variables:
 $ manufacturer: Factor w/ 15 levels "audi","chevrolet",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ model       : Factor w/ 38 levels "4runner 4wd",..: 2 2 2 2 2 2 2 3 3 3 ...
 $ displ       : num  1.8 1.8 2 2 2.8 2.8 3.1 1.8 1.8 2 ...
 $ year        : int  1999 1999 2008 2008 1999 1999 2008 1999 1999 2008 ...
 $ cyl         : int  4 4 4 4 6 6 6 4 4 4 ...
 $ trans       : Factor w/ 10 levels "auto(av)","auto(l3)",..: 4 9 10 1 4 9 1 9 4 10 ...
 $ drv         : Factor w/ 3 levels "4","f","r": 2 2 2 2 2 2 2 1 1 1 ...
 $ cty         : int  18 21 20 21 16 18 18 18 16 20 ...
 $ hwy         : int  29 29 31 30 26 26 27 26 25 28 ...
 $ fl          : Factor w/ 5 levels "c","d","e","p",..: 4 4 4 4 4 4 4 4 4 4 ...
 $ class       : Factor w/ 7 levels "2seater","compact",..: 2 2 2 2 2 2 2 2 2 2 ...

この形でマッピングします。

  • x軸:displ-ピストンが動ける容積(リットルで表現)
  • y軸:hwy-ガロンあたり走れる距離(マイルで表現)(高速で実験)
  • ファセット:drv-駆動方式

まずは、上記のマッピングでプロットします。

p <- ggplot(mpg, aes(x=displ,y=hwy)) + 
  geom_point() + 
  facet_grid(. ~ drv)
p

f:id:MukkuJohn:20160929205822p:plain

各ファセットに注釈を追加するには、
geom_text()と注釈用のデータフレームを使います。

#上のグラフは、drvでファセットにしているので
#「drv」という列名と値を合わせる必要があります。
f_labels <- data.frame(drv = c("4","f","r"), 
                       label = c("4wd","Front","Rear"))
> f_labels
  drv label
1   4   4wd
2   f Front
3   r  Rear

p + geom_text(x=6, y=40,aes(label=label),data=f_labels)

f:id:MukkuJohn:20160929210209p:plain

ファセットに指定した"drv"列の値と
注釈用データフレームの"drv"列の値が一致させる必要があります。

一致していないとこんなグラフになってしまいます。

#あえて、FFを指定して、一致させないようにしています。
ng_lables <- data.frame(drv=c("4","FF","r"), 
                        label = c("4wd","Front","Rear"))
p + geom_text(x=6, y=40,aes(label=label),data=ng_lables)

f:id:MukkuJohn:20160929211005p:plain

注釈に使うデータフレームですが、ファセットに指定した列以外に、
複数の列を用意して、geom_text()を複数回指定できます。

#この様に、drv列以外に、formula列とr2列を用意します
> labels
  drv                              formula                  r2
1   4 italic(y) == 30.68 -2.88 * italic(x) italic(R^2) == 0.65
2   f italic(y) == 37.38 -3.60 * italic(x) italic(R^2) == 0.36
3   r italic(y) == 25.78 -0.92 * italic(x) italic(R^2) == 0.04

#回帰式を引いて
p + geom_smooth(method=lm,se=FALSE)+
#formula列の値を数式として追加して
  geom_text(x=3,y=40,aes(label=formula),
            data=labels,parse = TRUE,hjust=0) +
#r2列の値も数式として追加します
  geom_text(x=3,y=35,aes(label=r2),
            data=labels,parse = TRUE,hjust=0)

f:id:MukkuJohn:20160929212346p:plain


geom_text()を使って注釈を追加しましたが、
annotate()を使うとどうなるか確認してみます。

#テキスト
p + annotate("text",x=6,y=42,label="label text")

f:id:MukkuJohn:20160929211614p:plain

#線分
p + annotate("segment",x = 3,xend = 6,y=30,yend=40)

f:id:MukkuJohn:20160929211648p:plain

#網掛け
p + annotate("rect",xmin = 3,xmax = 6,ymin=30,ymax=40,
             fill="lightblue",alpha=.3)

f:id:MukkuJohn:20160929211719p:plain

annotate()を使うと全ての図に同じ内容が適用されますね。
前回の記事では、geom_text()を使うと、データの数だけプロットされました。

ファセットの場合は、geom_text()とデータフレームの組み合わせが正しいようです。


注釈を入れるのは、この記事で終わりです。
次回の記事からは、を制御する方法を扱っていきます。

ggplot2を使って、注釈を入れる-1

R グラフィックス クックブック 20回目

ggplot2パッケージを利用して、図内に注釈を入れます。

注釈

データの解釈をサポートするために、図内に注釈を入れるのですが、
注釈自体は、いろいろあります。

  1. テキスト(文字列、数式)
  2. 線(線分、矢印)
  3. 網掛け
  4. 強調
  5. エラーバー

これらを、1個ずつ取り上げます。

最後にファセットグリッドで、グループ化された全ての図に
注釈を入れる方法を取り上げます。

テキスト(文字列、数式)

annotate()を使います。
第1引数に、textを指定します。

まずは、注釈を入れる図を用意します。
データセットR: Old Faithful Geyser Dataを使います。

p <- ggplot(faithful, aes(x=eruptions, y=waiting)) +
  geom_point()

p

f:id:MukkuJohn:20160928214115p:plain

文字列の注釈を入れます。

#注釈を入れる位置を、x軸/y軸の値で指定します。
#文字列は、label引数に指定します。
p + 
  annotate("text", x=3,   y=48, label="Group 1") +
  annotate("text", x=4.5, y=65, label="Group 2")

f:id:MukkuJohn:20160928214458p:plain

x軸/y軸が、連続値の場合は、Infを用いて、
図のコーナーに文字列を配置することができます。

コーナーに配置する場合は、hjustvjustで調整する必要があります。

p +
  annotate("text",x=-Inf,y=Inf,label="Upper Left",hjust=-.2,vjust=2) +
  annotate("text",x=mean(range(faithful$eruptions)),y=-Inf,label="Bottom Middle",vjust=-.4)

f:id:MukkuJohn:20160928215021p:plain

注釈文字列のフォントや斜体、色やサイズも指定できます。

p + 
  annotate("text", x=3, y=48, label="Group 1",
           family="serif",fontface="italic",colour="darkred",size=3) +
  annotate("text", x=4.5, y=65, label="Group 2",
           family="serif",fontface="italic",colour="blue",size=10)

f:id:MukkuJohn:20160928214723p:plain


文字列を注釈に入れる際には、geom_text()は使わない方が良いです。
geom_text()は、データの数だけ、繰り返し実行されてしまいます。

#Group 2の文字列がオーバープロットです。
#透過を0.1に指定していますが、
#透過が分からないくらい重ねてプロットされています。
p + 
  annotate("text", x=3, y=48, label="Group 1",
           family="serif",fontface="italic",colour="darkred",size=10) +
  geom_text(x=4.5,y=65,label="Group 2", alpha=.1)

f:id:MukkuJohn:20160928215219p:plain


文字列に数式表現を使う場合は、parse引数に、TRUEを指定します。

p <- ggplot(data.frame(x=c(-3,3)),aes(x=x)) + 
  stat_function(fun = dnorm)

#parse=TRUEで、labelが数式表現であることを指定します。
p + annotate("text", x=2, y=0.3, parse=TRUE,
             label="frac(1,sqrt(2 * pi)) * e ^ {-x^2 / 2}") 

f:id:MukkuJohn:20160928215608p:plain

数式表現内で、プレーンテキストを使う場合は、プレーンテキスト部分を
シングルクォーテーションでくくります。

#Function: 部分がプレーンテキストです。
p + annotate("text", x=2, y=0.3, parse=TRUE,
             label="'Function: ' * y==frac(1,sqrt(2 * pi)) * e ^ {-x^2 / 2}") 

f:id:MukkuJohn:20160928215740p:plain

線(線分、矢印)

線により使う関数が異なります。

  1. 水平線:geom_hline()
  2. 垂直線:geom_vline()
  3. 傾きがある線:geom_abline()

このデータセットを使います。
R: Risk Factors Associated with Low Infant Birth Weight

グループ化に用いる列をファクタにして、ラベルを設定します。

birthwt1 <- birthwt
birthwt1$smoke <- factor(birthwt1$smoke) 
birthwt1$smoke <- revalue(birthwt1$smoke, c("0"="No Smoke","1"="Smoke"))

まずは、注釈なしでプロットします。

p <- ggplot(birthwt1, aes(x=age,y=bwt,colour=smoke)) + 
  geom_point()
p

f:id:MukkuJohn:20160928220354p:plain

水平線と、垂直線を追加します。

#線を引く位置を、水平線ならy軸の値、垂直線ならx軸の値で指定します。
p + geom_hline(yintercept=2000) + geom_vline(xintercept=20)

f:id:MukkuJohn:20160928220616p:plain

傾きのある線を追加します。

#y=slope * 100 + interceptの傾きのある線を図示します。
p + geom_abline(intercept=500,slope=100) 

f:id:MukkuJohn:20160928221126p:plain

別途、算出した値の線を追加することもできます。
グループ化している項目ごとに、平均値を算出します。

library(plyr)
bw_means <- ddply(birthwt1,"smoke",summarise,bwt=mean(bwt))
bw_means
     smoke      bwt
1 No Smoke 3055.696
2    Smoke 2771.919

上で算出した、グループ化項目と平均値のデータフレームを
水平線に設定します。

p + geom_hline(aes(yintercept=bwt,colour=smoke),data=bw_means,
               linetype="dashed",size=1)

f:id:MukkuJohn:20160928221442p:plain

軸が離散値の場合は、ファクタのレベルを指定することで
水平線、垂直線を追加できます。

x軸が離散値の図を、サンプルに使います。

pb <- ggplot(birthwt1,aes(x=smoke,y=bwt)) + geom_point()
pb

f:id:MukkuJohn:20160928221739p:plain

離散値としているsmoke列は、ファクタで、
1つ目のNo Smokeのレベルは1、2つ目のSmokeのレベルは2となっています。

> str(birthwt1$smoke)
 Factor w/ 2 levels "No Smoke","Smoke": 1 1 2 2 2 1 1 1 2 2 ...

ファクタのレベルを指定することで、線を引くことができます。

#ファクタのレベルを数値で指定します。
pb + geom_vline(xintercept=2)

f:id:MukkuJohn:20160928222044p:plain

上は、ファクタのレベルを数値で指定しましたが、
which(levels())を用いることで、名称から指定することもできます。

pb + 
  geom_vline(xintercept = which(levels(birthwt1$smoke)=="No Smoke"))

f:id:MukkuJohn:20160928222219p:plain


今までは「線」を扱ってきましたが、ここからは「線分」を追加していきます。
線分は、annotate()を使い、引数に、"segment"を指定します。

この図を使います。
f:id:MukkuJohn:20160928222522p:plain

線分を追加するには、x軸の開始値と終了値、y軸の開始値と終了値を指定します。

#x軸は、x~xendで指定します。
#y軸は、y~yendで指定します。
上のグラフ + annotate("segment", x=1950,xend=1980, y=-.25,yend=0.25,
             colour="blue", size=3)

f:id:MukkuJohn:20160928222903p:plain

矢印や、線分の両端をT字にするためには、gridパッケージのallow()を使います。

library(grid)
#矢印はarrow()
p + annotate("segment",x=1850,xend=1820,y=-.8,yend=-.95,colour="blue",
             size=2,arrow=arrow())+
#両端がT字にするには、ends引数を指定します。
  annotate("segment",x=1950,xend=1980,y=-.25,yend=-.25,
           arrow=arrow(ends = "both",angle = 90,length = unit(.2,"cm")))

f:id:MukkuJohn:20160928223226p:plain

網掛け

annotate()を使います。引数は、rectです。
範囲の指定が、線分とちょっと異なります。

#x軸は、xmin~xmaxで指定します
#y軸は、ymin~ymaxで指定します
p + annotate("rect",xmin=1950,xmax=1980,ymin=-1,ymax=1,
             alpha=.1,fill="blue") +
  annotate("rect",xmin=1800,xmax=2000,ymin=-1,ymax=-.5,
           alpha=.1,fill="green")

f:id:MukkuJohn:20160928223435p:plain


今までの注釈は、端から端までの線を除き、全てannotate()を使っています。

  • 文字列:annotate("text",~)
  • 線分:annotate("segment",~)
  • 網掛け:annotate("rect",~)

注意点は、データの数だけプロットされるgeom_text()を使わないことです。


次回は、強調表示とエラーバー、グリッドで分割された図を扱います。