Juliaでcsvを読み込んでヒートマップを描くのはまだちょっとめんどかったという話

## やりたいこと
Pythonでcsvから読み込んできたDataFrameを使ってseabornでヒートマップを描く場合、余計なことを何もしなければ以下のような感じでいけますよね。

```python
import pandas as pd
import seaborn as sns

df = pd.read_csv("data.csv")    # x,y,zというカラムがあるcsvを想定
pivot = df.pivot("y", "x", "z") # DataFrameをピボットテーブルに変換
sns.heatmap(pivot)              # 突っ込んで終わり
```
importを除けば実質たった3行。非常にスッキリしています。
自分はこれと同じことをJulia(Plots+PyPlot)でも楽にできないかとずっと思っていたのですが、何度か調べていてどうもJuliaにはまだPandas+Seabornほど洗練されたAPIは備わっていないようだったので、ヒートマップだけは渋々Pythonで描いていました。
今回は何とかしてこの作業をPlots+PyPlotでやってみたというお話です。

## やり方
まずは読み込むcsvの用意から。

```julia
using PyPlot, Plots, DataFrames, CSV

# PlotsのバックエンドにはPyPlotを使用
pyplot()

# csvに書き出す元データを作る
df = DataFrame(Location = ["NY", "SF", "NY", "NY", "SF", "SF", "TX", "TX", "TX", "DC", "DC", "DC"],
               Class = ["M","M","H","L","L","H", "H","L","M","M","H","L"],
               Score = rand(12))
df |> CSV.write("data.csv")

# csvを読み込んでdataframeに格納する
data = CSV.read("data.csv")
```
![df.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227776/97bd2e24-2d7d-d6f5-3a24-11455888c700.png)

次、ピボットテーブルに変換。

```julia
# 縦軸にLocation, 横軸にClassを持つピボットテーブルに変形する
pivot = DataFrames.unstack(data, :Location, :Class, :Score)
```
![pivot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227776/a8dce7e9-c6e4-5ef0-69dc-e102d6206221.png)

なぜか文字化けしてるけど気にしない。
最初に見せたようにPythonならこれをsns.heatmapに突っ込むだけで終わりですがJuliaの場合は残念ながらそうはいきません。
先に答えを見せるとこうやる必要がありました。

```julia
x = String.(names(pivot)[2:end])
y = pivot.Location
z = Matrix(pivot)[:,2:end]
heatmap(x, y, z)
```

まず1行目で何をやっているかですが、やりたいのはpivotの横軸の値(= [H,L,M])をString型の要素が入ったArrayとして取得することです。`names(pivot)`だけでできればいいのですが、この関数の返り値はそのままだと`Array{Symbol,1}`なので、`String.`でString型に変換しないとheatmap関数が受付けてくれません。
![names_pivot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227776/08001ae6-2d10-264c-de10-a0ffc19f5f13.png)
また面倒なことに`names(pivot)`すると最初の要素に縦軸の列名である`:Location`が紛れ込んでしまうため、これを取り除くために`[2:end]`を付けています。んー、ピボットテーブルの横軸の値だけ取得する関数くらい用意されてて欲しいですね...^^;

続いて2行目はいいとして3行目ですが、こちらもまたちょっと面倒ながらheatmap関数は引数でDataFrame型を受け付けてくれないので`Matrix`関数でpivotを行列形式に変換する必要があります。
![matrix.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227776/a949cf1f-8ea3-70ec-a141-afa8cb78fa9b.png)
更にご覧の通りこれでは1列目に不要な縦軸の値が紛れ込んでいるので,これを取り除くために`[:,2:end]`を付けて2列目以降だけをzに渡しています。ここも何とかならんかな...^^;

とまあこういう細かいことをすればちゃんとヒートマップを描いてくれます。
![julia_heatmap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227776/1c466616-ee99-dbc2-5884-9d7f7363dd2d.png)

とは言えPandas+Seabornの組み合わせに慣れきっていた自分にはPlots+PyPlotでのヒートマップ作成はだいぶ面倒くささを感じてしまいました。[PyPlot公式](https://docs.juliaplots.org/latest/examples/pyplot/#heatmap-categorical-axes-and-aspect_ratio)などに何かいい例は載っていないかと何度も探したのですが、あるのはどれもheatmap関数がそのまま読み込めるように最初からピボットテーブル化して行列形式になっている都合のいいデータでヒートマップを描く例ばかり...
**「そんなん実際の仕事でやるわけないでしょ! CSVから読み込んだデータをヒートマップにする方法が知りたいんだよ!!」**
と心の中で何度も突っ込んでいました（泣）

また今回紹介したようなPlots+PyPlotの組み合わせでヒートマップを描く方法以外にも[Vega.jl](https://johnmyleswhite.github.io/Vega.jl/heatmap.html)や[Makie.jl](http://makie.juliaplots.org/stable/functions-overview.html#heatmap-1)などを使ってももちろんヒートマップ自体は描けるのですが、どれもDataFrameとかピボットテーブルを直接読み込んで描画することはできず、行列形式のデータになるまで手作業で整形してから描画関数に突っ込まないといけないやつばかりだったので、Juliaのヒートマップ描画周りのAPIはどのパッケージももう少し改良が必要そうだなと感じました。もしJuliaでのヒートマップ作成にお詳しい方がいらっしゃればマサカリ大歓迎ですのでぜひコメントください。