ggplot2の積み上げグラフで並び順を手動で設定する方法

Rでグラフを描く場合に便利なggplot2ですが、積み上げグラフを描くときに積み上げ順が自動で設定されて困ったので手動で設定する方法をまとめておきます。

環境：Win10, R 3.4.4 (x64), ggplot2 2.2.1
#普通に作成してみる
とりあえずライブラリを読み込みます。

```R
 install.packages("ggplot2") #ライブラリをまだインストールしていない場合
 library(ggplot2)
```

まずは`read.csv`コマンドでデータを読み込みます。
それぞれの環境に合わせてファイル名を変更するなり、MySQLなどのデータベースに接続して読み込むなりしてください。

```R
 dt <- read.csv("data.csv") #dtという変数に"data.csv"の内容を読み込む
```
以下はcsvのサンプルデータで本記事ではこのデータを用いて解説します。
<details><summary>サンプルデータ</summary><div>

```csv:data.csv
"counter","length","category"
50,0,NA
97,1,NA
122,2,NA
214,3,NA
134,4,NA
63,5,NA
204,0,"エンターテイメント"
633,1,"エンターテイメント"
400,2,"エンターテイメント"
315,3,"エンターテイメント"
292,4,"エンターテイメント"
490,5,"エンターテイメント"
14,0,"音楽"
100,1,"音楽"
151,2,"音楽"
186,3,"音楽"
552,4,"音楽"
131,5,"音楽"
130,1,"歌ってみた"
170,2,"歌ってみた"
2989,3,"歌ってみた"
1282,4,"歌ってみた"
347,5,"歌ってみた"
11,0,"演奏してみた"
86,1,"演奏してみた"
35,2,"演奏してみた"
125,3,"演奏してみた"
41,4,"演奏してみた"
34,5,"演奏してみた"
8,0,"踊ってみた"
40,1,"踊ってみた"
35,2,"踊ってみた"
555,3,"踊ってみた"
886,4,"踊ってみた"
127,5,"踊ってみた"
29,0,"VOCALOID"
33,1,"VOCALOID"
107,2,"VOCALOID"
1200,3,"VOCALOID"
750,4,"VOCALOID"
176,5,"VOCALOID"
2,1,"ニコニコインディーズ"
9,2,"ニコニコインディーズ"
26,3,"ニコニコインディーズ"
32,4,"ニコニコインディーズ"
11,5,"ニコニコインディーズ"
41,0,"動物"
104,1,"動物"
87,2,"動物"
72,3,"動物"
8,4,"動物"
17,5,"動物"
3,0,"料理"
20,1,"料理"
38,2,"料理"
53,3,"料理"
64,4,"料理"
25,5,"料理"
9,0,"自然"
11,1,"自然"
2,2,"自然"
2,4,"自然"
4,5,"自然"
2,0,"旅行"
3,1,"旅行"
13,2,"旅行"
27,3,"旅行"
26,4,"旅行"
27,5,"旅行"
33,0,"スポーツ"
90,1,"スポーツ"
44,2,"スポーツ"
12,3,"スポーツ"
17,4,"スポーツ"
20,5,"スポーツ"
6,1,"ニコニコ動画講座"
2,3,"ニコニコ動画講座"
5,4,"ニコニコ動画講座"
4,5,"ニコニコ動画講座"
7,2,"車載動画"
4,3,"車載動画"
5,4,"車載動画"
11,5,"車載動画"
137,0,"歴史"
11,1,"歴史"
25,2,"歴史"
7,3,"歴史"
1,4,"歴史"
1,5,"歴史"
20,0,"政治"
12,1,"政治"
17,2,"政治"
20,3,"政治"
47,4,"政治"
39,5,"政治"
62,0,"科学"
62,1,"科学"
13,2,"科学"
33,3,"科学"
13,4,"科学"
33,5,"科学"
8,1,"ニコニコ技術部"
69,2,"ニコニコ技術部"
26,3,"ニコニコ技術部"
17,4,"ニコニコ技術部"
13,5,"ニコニコ技術部"
3,0,"ニコニコ手芸部"
1,2,"ニコニコ手芸部"
2,3,"ニコニコ手芸部"
1,4,"ニコニコ手芸部"
15,0,"作ってみた"
31,1,"作ってみた"
26,2,"作ってみた"
142,3,"作ってみた"
66,4,"作ってみた"
19,5,"作ってみた"
348,0,"アニメ"
363,1,"アニメ"
224,2,"アニメ"
147,3,"アニメ"
294,4,"アニメ"
81,5,"アニメ"
302,0,"ゲーム"
289,1,"ゲーム"
241,2,"ゲーム"
354,3,"ゲーム"
372,4,"ゲーム"
385,5,"ゲーム"
1,0,"実況プレイ動画"
27,1,"実況プレイ動画"
51,2,"実況プレイ動画"
46,3,"実況プレイ動画"
111,4,"実況プレイ動画"
124,5,"実況プレイ動画"
14,0,"東方"
50,1,"東方"
63,2,"東方"
285,3,"東方"
181,4,"東方"
80,5,"東方"
25,0,"アイドルマスター"
342,1,"アイドルマスター"
396,2,"アイドルマスター"
223,3,"アイドルマスター"
141,4,"アイドルマスター"
78,5,"アイドルマスター"
10,0,"ラジオ"
20,1,"ラジオ"
12,2,"ラジオ"
1,3,"ラジオ"
68,0,"描いてみた"
42,1,"描いてみた"
116,2,"描いてみた"
97,3,"描いてみた"
23,4,"描いてみた"
20,5,"描いてみた"
899,0,"例のアレ"
1004,1,"例のアレ"
966,2,"例のアレ"
423,3,"例のアレ"
237,4,"例のアレ"
207,5,"例のアレ"
13,0,"日記"
104,1,"日記"
75,2,"日記"
133,3,"日記"
99,4,"日記"
117,5,"日記"
83,0,"その他"
473,1,"その他"
286,2,"その他"
693,3,"その他"
381,4,"その他"
149,5,"その他"
```
</div></details>
中身を少し解説すると、このデータはニコニコ動画で一定期間にランキング入りした動画のうちカテゴリ・動画長さ別の動画数です。
元データは多いのでサンプルでは動画長5分以下に絞っています。

まずは普通に読み込んだデータフレームから、lengthを横軸としてcategoryごとに積み上げた棒グラフを作成してみます。

```R
ggplot(dt, aes(x=length,y=counter))+geom_bar(stat="identity",aes(fill=category))+labs(x="Length [m]",y="Numer of Videos")
```
![data_def.png](https://qiita-image-store.s3.amazonaws.com/0/133088/abd9df2b-3191-b042-20cf-4bb00dfc485b.png)
たったこれだけで上のようなグラフが完成しました。簡単ですね。
ところで、ファイルを読み込んだ時点ではcategoryがジャンル順に並んでいましたが、グラフにするとアルファベット順(50音順)に勝手に並び替えられてしまっています。ここから本題に入ります。

#積み上げ順を指定してグラフを作成する
積み上げ順を指定するには、データフレームのcategoryを因子型(Factor)とした上で、順序をlevelsで指定します。
ここではcategory2という列を追加して設定してみます。

```R
dt$category2 <- factor(dt$category, levels = c('エンターテイメント','音楽','歌ってみた','演奏してみた','踊ってみた','VOCALOID','ニコニコインディーズ','動物','料理','自然','旅行','スポーツ','ニコニコ動画講座','車載動画','歴史','政治','科学','ニコニコ技術部','ニコニコ手芸部','作ってみた','アニメ','ゲーム','実況プレイ動画','東方','アイドルマスター','ラジオ','描いてみた','例のアレ','日記','その他'))
```
levelsで指定したベクトルの順序がこのあとのグラフ積み上げ順となります。なお、元データにあったものをfactorで指定しなかった場合にはNA扱いになるので注意してください。

では先ほどと同じグラフをcategory2で積み上げてグラフを作成してみます。先ほどのコマンドの`category`を`category2`にするだけです。

```R
ggplot(dt, aes(x=length,y=counter))+geom_bar(stat="identity",aes(fill=category2))+labs(x="Length [m]",y="Numer of Videos")
```
![data_ord.png](https://qiita-image-store.s3.amazonaws.com/0/133088/12194a61-b8a1-6a94-471e-607c3e0652de.png)
無事にfactorで指定した順に積み上げることが出来ました。
凡例がcategory2になってしまいましたが、

```R
+scale_fill_discrete(name="Category")
```
を追加で指定することで凡例タイトルを自由に設定できます。

#あとがき
それでは皆さん素敵なggplot2ライフを。

ちなみに本記事でサンプルとして紹介したニコニコ動画の動画長分布ですが、もしご興味ある方は
[ニコニコ動画における新配信と動画長さ - ニコナレ](https://niconare.nicovideo.jp/watch/kn3064) 12・13枚目
で紹介しています。