[TODO] R 4.0.0 以降の色についてはそのうち書きます。とりあえず palette() のヘルプをご覧ください。palette("Okabe-Ito") とするとsafe colorsになります。→ A New palette() for R,Color Universal Design,Essentials of color in R。あと Colorspace 2.0 とその JSS paper。
統計グラフに色を付けることは広く行われています。しかし,色は万人に共通のものではありません。日本人男性の5%,白人男性の8%は,RGB(赤緑青)のうち赤と緑の区別がうまくできません。その内訳は1:3で赤の感受性がないP型(1型,protanopia)と緑の感受性がないD型(2型,deuteranopia)に分かれます。青を感じない人や,RGBのうち2色以上を感じない人もいます。少数ですが女性にもあります。RGBをすべて区別できることを前提とした統計グラフは避けなければなりません。形やパターンを併用するなどの工夫が必要です。その上で,できるだけ多くの人に見分けやすく快い色遣いをしましょう。
Rの多くの描画関数では col="red" のようなオプションで色が指定できます。"red" のように名前が付いたものは数百色あり,Rのコンソールに colors() と打ち込めば列挙されます。より便利な指定法はHTMLと同じ16進6桁または8桁の "#rrggbb" または "#rrggbbaa" という書き方です(aa は不透明度を表すアルファ値)。あるいは0〜1の実数値を使って
rgb(r,g,b)
あるいは
rgb(r,g,b,a)
と書くこともできます。例えば "red" は "#FF0000" や "#FF0000FF" や rgb(1,0,0) や rgb(1,0,0,1) と同じです。
rgb()
以外に
hsv()
や
hcl()
でも指定できます。色の変換には
col2rgb(),convertColor(),adjustcolor()
といった関数が用意されています。詳しくはヘルプをご覧ください(コンソールに例えば
?hcl
と打ち込みます)。例えば adjustcolor("blue", 0.5) で半透明の青ができます。
モノクロ印刷物の場合は gray(0)(黒)から gray(1)(白)までの実数値による指定が便利でしょう。カラー印刷物に使われるCMYKについては下で説明します。
色を名前やRGB値で指定するより,色の集合すなわちパレットを用意しておき,そこから選んで使うほうが便利です。
Rでデフォルトのパレット palette()
は black, red, green3, blue, cyan, magenta, yellow, gray の8色です:
# png("rgbcolors.png", 400, 200)
# par(mar=c(0,0,0,0))
barplot(rep(1,8), col=palette(), axes=FALSE)
# dev.off()
上のような原色は,目が痛くなるので,なるべく使わないようにしましょう。
rainbow() を使えば任意の個数の色が作れますが,やはり原色に近く,明暗の差があるのでカテゴリーデータに向かないという説もあります。colorspace パッケージの rainbow_hcl() を使えば,できるだけ同じ明度・彩度の色になります。
library(colorspace)
# png("colors.png", 400, 200)
# par(mar=c(0,0,0,0))
plot(NULL, xlim=c(0,7), ylim=c(0,2),
axes=FALSE, xlab="", ylab="")
rect(0:6, 1.1, 1:7, 2, col=rainbow(7))
rect(0:6, 0, 1:7, 0.9, col=rainbow_hcl(7, c=100))
# dev.off()
この rainbow_hcl()
はHCL色空間で一定のC(chroma,彩度),L(luminance,明度)を保ちながらH(hue,色相)だけを変えて色を作ります。デフォルトでは彩度 c = 50,明度 l = 70 ですが,上の例では彩度を少し上げています。
印刷にはRGBベースではなくCMYKベースの色を使います。有名な W. S. Cleveland の The Elements of Graphing Data という本ではCMYKをベースに次の5色をカテゴリーデータ用に薦めています。
| (c,m,y,k) | #rrggbb (R) | #rrggbb (Photoshop) | 色名 |
|---|---|---|---|
| (1,0,0,0) | #00ffff | #00a0e9 | cyan |
| (0,1,0,0) | #ff00ff | #e4007f | magenta |
| (1,0,1,0) | #00ff00 | #009944 | green |
| (0,0.5,1,0) | #ff8000 | #f39800 | orange |
| (1,0.5,0,0) | #0080ff | #0068b7 | royal blue |
最後の色をClevelandはlight blueと書いていますが,ここではより適切と思われるroyal blueを使いました。
上の表でPhotoshopのRGB値はPhotoshop CS5でJapan Color 2001 CoatedからsRGBに変換したものです。一方,RではRGB→CMYKを便宜上次のような簡単なアルゴリズムで変換しています:
c = 1.0 - r
m = 1.0 - g
y = 1.0 - b
k = min(c, m, y)
if (k == 1.0) {
c = m = y = 0.0
} else {
c = (c-k)/(1-k)
m = (m-k)/(1-k)
y = (y-k)/(1-k)
}
CMYKのPDFを出力するには,
pdf("hoge.pdf", width=7, height=4, colormodel="cmyk") # グレースケールなら "gray"
...
dev.off()
のようにします。"cyan","magenta","yellow","black" のようにしてCMYKを指定します。あるいは,上のアルゴリズムを逆に計算したRGB値を使って色を指定します。例えばオレンジ (c,m,y,k) = (0,0.5,1,0) を使いたいなら rgb(1,0.5,0),紺 (c,m,y,k) = (1,0.5,0,0) を使いたいなら rgb(0,0.5,1) を指定します。
ちなみにClevelandは連続量をcyanとmagentaの濃淡で表す右図のような方法も提案しています。
私がよく使うのは紺(#0068b7)からオレンジ(#f39800)にかけての色です。オレンジはRGBのうち赤と緑を含み,紺は青を多く含むので,赤または緑の感受性を持たない人にも見分けやすいというわけです。
より現代的な色の選択を提案するサイトとして,Colorbrewer: Color Advice for Maps があります。RのパッケージRColorBrewerも開発されています。右図はRColorBrewerパッケージのサンプル
display.brewer.all()
の出力です。3段に分かれています。上のグループは順次的(sequential)と呼ばれるもので,小さい量から大きい量までの段階を表すのに使われます。真ん中のグループは定性的(qualitative)と呼ばれるもので,大小関係のないカテゴリー(名義尺度)を表すのに使われます。下のグループは発散的(diverging)と呼ばれるもので,正負の両側に延びる量を表すのに使われます。
例えばこの中のDark2というものに興味があれば,
display.brewer.pal(8, "Dark2")
でこの8色だけサンプル出力します。実際の色を取り出すには,例えば
cols = brewer.pal(8, "Dark2")
とすれば cols[1] から cols[8] までに色が入ります。
自前でこのようなパレットを作るには colorRampPalette()
関数を使います。
# png("110905d.png", 450, 80)
# par(mar=c(0,0,0,0))
cols = colorRampPalette(c("#0068b7","white","#f39800"))
plot(NULL, xlim=c(0,10), ylim=c(0,1),
axes=FALSE, xlab="", ylab="")
rect(0:9, 0, 1:10, 1, col=cols(10))
# dev.off()
0から1までの実数に色を対応させる関数を作るには,例えば次のようにします。
cols = colorRamp(c("#0080ff","white","#ff8000"))
これで cols(0) が #0080ff,cols(1)
が #ff8000 に対応するような0〜255の三つ組を返す関数 cols()
が生成されます。これを使って何か描いてみましょう。
# png("110905b.png", 450, 80)
# par(mar=c(0,0,0,0))
plot(NULL, xlim=c(0,100), ylim=c(0,1), axes=FALSE, xlab="", ylab="")
rect(0:99, 0, 1:100, 1, col=rgb(cols(0:99/99)/255), border=NA)
# dev.off()
colorRamp() にいろいろな色を与えてやってみてください。例:
cols = colorRamp(c("#004080","#0080ff","white","#ff8000","#804000"))
(追記)corrplot パッケージのデフォルト色がオレンジ(負)〜紺(正)であることに気づきました:
colorRampPalette(c("#67001F", "#B2182B", "#D6604D", "#F4A582", "#FDDBC7",
"#FFFFFF", "#D1E5F0", "#92C5DE", "#4393C3", "#2166AC", "#053061"))
scales パッケージにも色を作る関数がいろいろあります。help(package="scales") で出てくる 何々_pal という関数がそれです。例:
cols = dichromat_pal("BluetoOrange.10")(10)
show_col(gradient_n_pal(cols)(seq(0, 1, length.out = 30)))
色覚バリアフリーまたはカラーユニバーサルデザインの考え方について少し補足しておきます。
まず必要なことは,自分以外の色覚の人がどのように見えるかを把握することです。CS4以降のAdobe PhotoshopやAdobe IllustratorにはP型・D型の見え方に変換する機能があります。Adobe Photoshop CS5の場合,「表示」→「校正設定」→「P型(1型)色覚」または「D型(2型)色覚」を選びます(CS4では「表示」が「ビュー」になります)。
同様なことをするMac用の無料ソフト Sim Daltonism を教えていただきました。
GIMP(Mac,Windows,Linux)でも,[表示]→[ディスプレイフィルター]で「色覚障害の視覚」フィルターをアクティブにして選択すれば,1型〜3型の色覚がシミュレートできます。
例えば福島県放射能測定マップの色分けは次のようになっています:
これをPhotoshop CS5で「D型(2型)色覚」にしてみます:
緑とオレンジが同じような色になってしまうことがわかります。そうでなくてもこの色分けは明るい色(黄)を中心に両側に暗い色があるので,これでマップを作ると明るい色の輪に見えてしまうことが,下に挙げた“Escaping RGBland”論文でも指摘されています。正の値が大きいか小さいかを表すにはsequentialな色分けが適当ですが,その前に一つ予備知識。
Rでカラーユニバーサルデザインの考え方に基づいて作られたパッケージに dichromat
があります。
library(dichromat)
# png("dichromat.png", 400, 200)
# par(mar=c(0,0,0,0))
plot(NULL, xlim=c(0,12), ylim=c(0,2),
axes=FALSE, xlab="", ylab="")
rect(0:11, 1.1, 1:12, 2, col=colorschemes$Categorical.12)
rect(0:11, 0, 1:12, 0.9, col=dichromat(colorschemes$Categorical.12))
# dev.off()
colorschemes$Categorical.12 は12色のカテゴリカル用の色です。このパッケージに含まれる色に限らず,どんな色でも dichromat() 関数を通せば色覚を変化させることができます(オプション type="deutan",type="protan" が指定できます。デフォルトは前者)。
そこで,先ほどの福島県放射能測定マップの色分けですが,色そのものはRColorBrewerの適当なsequentialな色分けを使うのでよいと思います。dichromat() 関数でD型色覚の見え方も調べてみましょう。
# library(RColorBrewer)
# library(dichromat)
# png("110922c.png", 400, 200)
# par(mar=c(0,0,0,0))
cols = brewer.pal(8, "YlOrBr")
plot(NULL, xlim=c(0,8), ylim=c(0,2),
axes=FALSE, xlab="", ylab="")
rect(0:7, 1.1, 1:8, 2, col=cols)
rect(0:7, 0, 1:8, 0.9, col=dichromat(cols))
# dev.off()
もっとも,これはグレースケールだけで判別できるので,調べるまでもなかったのですが。
RGBをグレースケールに変換する一番簡単な式は 0.3r + 0.59g + 0.11b です。これとdichromatパッケージを使ってD型・P型・グレイスケールへの変換結果を表示するには次のようにすればいいでしょう。
library(dichromat)
rgb2gray = function(col) {
m = matrix(c(rep(0.3,3),rep(0.59,3),rep(0.11,3)), nrow=3)
rgb(t((m/255) %*% col2rgb(col)))
}
rects = function(col) {
n = length(col)
oldpar = par(mar=c(0,0,0,0))
plot(NULL, xlim=c(0,n), ylim=c(0,4.6), axes=FALSE, xlab="", ylab="")
rect(0:(n-1), 3.6, 1:n, 4.6, col=col)
rect(0:(n-1), 2.4, 1:n, 3.4, col=dichromat(col,type="deutan"))
rect(0:(n-1), 1.2, 1:n, 2.2, col=dichromat(col,type="protan"))
rect(0:(n-1), 0.0, 1:n, 1.0, col=rgb2gray(col))
par(oldpar)
}
最後に,カラーユニバーサルデザイン推奨配色セット ver. 4 にあるアクセントカラー・ベースカラー・無彩色の #rrggbb 値を載せておきます(例えば as.hexmode(c(255,75,0)) などとして16進変換できます)。
|
|
|
Rの pdf(colormodel="cmyk") でPDFにする際の指定は次の通りです:
|
|
(注) これでCMYK値は (0%,78%,100%,55%) になり,推奨値 (55%,90%,100%,0%) と違ってしまいますが,仕様上しかたないようです。
Webで見ている分にはどうでもいいことでも,印刷が関係すると,いろいろ厄介な問題が生じます。このあたりに詳しくない人は,ぜひ「4色」って言っただけで印刷会社の社員がうなだれた……でも、なんで? 『今日も下版はできません!』第21話という漫画をお読みください。
印刷用途にスクリーンショットなどを使う際には,もちろんJPEGでなくPNGを使うことになりますが,RGBのPNGをグレイスケールに変換する必要が生じます。この話は[改訂第7版]LaTeX2e 美文書作成入門のpp.138--139にも書きましたが,ImageMagickのconvert(最近のバージョンではmagick)コマンドを使って
for x in *.png
do
convert $x -colorspace Gray ${x%.png}-gray.png
done
のようにして一括変換できます。
Rで生成したPDFをインクルードして印刷に回す際にも,pdf() 関数なら,上に書いたように colormodel="cmyk" または colormodel="gray" のオプションが使えますが,Macで任意のシステムフォントを埋め込むために quartz(type="pdf") を使う場合には,どうしてもRGBになってしまいますので,後でグレイスケールに変換する必要が生じます。これは,Ghostscriptを使って
gs \ -sDEVICE=pdfwrite \ -sProcessColorModel=DeviceGray \ -sColorConversionStrategy=Gray \ -sColorConversionStrategyForImages=Gray \ -dAutoRotatePages=/None \ -o hoge-gray.pdf \ hoge.pdf
のようにできます。Gray の部分は必要に応じて CMYK にします。Ghostscript 8 では -dUseCIEColor のようなオプションが必要かもしれません。逆に Ghostscript 9 では -dOverrideICC が必要かもしれません。うまく変換されたか Acrobat の印刷工程の出力プレビューでチェックしましょう。R で col=gray(0.9) と指定したら K 10% になるのが正しいのですが,RGB経由の変換では例えば K 13% のようになるかもしれません。
vignette("hcl-colors", package="colorspace")
と打ち込むと見られる。