2015/05/24

Rでグラフを描く際のy軸のラベルなどの件

統計解析やグラフ作成が必要な際にはだいたいいつもRを使っている。
tiffで1000dpi、9cmのグラフを作成したい場合、単純に下記のようにすればよいと思ったわけだが、ラベルの記載がいまいちうまく行かなかった。ラベル中に上付き文字を使う場合はexpression(paste())を使用するのが一般的だと思われるが、どうも上付きにした2の上のほうが下の図のように欠けてしまう。また、y軸の目盛には小数点の".0"がついて欲しかったが、最初その方法が良くわからなかった。

xData <- 5:10
yData <- rnorm(length(xData),7.5,1)

l <- lm(yData ~ xData)

tiff("test.tiff",width=90,height=90,units="mm",res=1000,pointsize=7)
xlim <- c(5,10)
ylim <- c(5.0,10.0)

plot(x=xData, xlab="xData (mm)",
     y=yData, ylab=expression(paste("yData (mm"^"2",")")),
     xlim=xlim,ylim=ylim)

abline(l)
dev.off()


まず、上付きの2の上のほうが欠けてしまう問題について。左側の余白が小さすぎるのが問題っぽかった。par("mar")で出てきた余白を見て、左側の4.1(左から2番目の値)を5.1に変更したらうまくいった。
> par("mar")
[1] 5.1 4.1 4.1 2.1
また、目盛の有効数字についてだが、plot()内で書かずにaxis()を使って自分で書く方法でできることが判明。axis()のlabels引数にsprintf("%.1f",lab_vector)したものを渡すことで".0"がついた目盛を作成できた。
最終的には以下のようになった。

xData <- 5:10
yData <- rnorm(length(xData),7.5,1)

l <- lm(yData ~ xData)

tiff("test.tiff",width=90,height=90,units="mm",res=1000,pointsize=7)
par(mar=c(5.1,5.1,4.1,2.1),font=1,family="Helvetica")
xlim <- c(5,10)
ylim <- c(5.0,10.0)

plot(x=xData, xlab="xData (mm)",
     y=yData, ylab=expression(paste("yData (mm"^"2",")")),
     xlim=xlim,ylim=ylim,xaxt="n",yaxt="n")
axis(1,at=pretty(xlim))
axis(2,at=pretty(ylim),labels=sprintf("%.1f",pretty(ylim)))

abline(l)
dev.off()
これで求めていた形になった。かなり解決に時間がかかったが、今後もRでグラフを作成する際には使っていきたい。統計処理のトレンドはSciPyになってきている?みたいな事も聞いたことがあるが、そっちもそのうち試してみようかと思った。



2015/05/17

Linux Trackball:Emulate3Buttons改造


1年くらい前にevdevのEmulate3Buttonsまわりのコードを改造したが、今回それに追加をすることにした。
xorg.confの設定において、Emulate3ButtonsはButton1(左クリック)とButton3(右クリック)を同時押しするとButton2のeventが発行されるというものである。
また、左右同時押し+トラックボールで画面のスクロールをしたい場合、EmulateWheelを"True"にすればよいわけだが、それを行うEmulateWheelButtonはEmulateされたボタンであってはならないという制約がデフォルトでは存在した。これを変更する改造を以前行ったわけだが、問題が完全に解決したわけではなかった。

自分の愛用しているKensingtonのExpert Mouse 7やSlimbladeにおいて、ボタンのフィジカルレイアウトは


2 | 8
-----
1 | 3
となっているわけだが、自分は


8 | 9
-----
1 | 3
のように使いたい。8をブラウザの戻る、9をブラウザの進むに割り当てると非常にブラウジングが快適になるからだ。
この設定はOption "ButtonMapping" "1 8 3 4 5 6 7 9"のようにすれば可能だが、こうするとEmulate3Buttonsで発行されるボタンはフィジカルボタンの2番目、つまり"8"が発行されてしまう。自分としては中クリックの"2"を発行したい。さらに、EmulateWheelButtonは"2"にしたい。

どうしたものかとしばらく悩んだが、解決策を思いついた。
Emulate3Buttonsで発行されるボタンを存在しないフィジカルボタンの9番目にして、そこをButtonMappingで"2"にすればいいのである。
xf86-input-evdev-2.9.2/src/emuMB.cのステートマシンのstateTab[][][0]が発行されるキー番号なので、ここの2を9に変更すればよい。以前変更したEvdevMBEmuFilterEventの変更部分はそのままで大丈夫だ。


diff -ur xf86-input-evdev-2.9.2/src/emuMB.c xf86-input-evdev-2.9.2-myMB/src/emuMB.c
--- xf86-input-evdev-2.9.2/src/emuMB.c 2015-03-11 12:24:39.000000000 +0900
+++ xf86-input-evdev-2.9.2-myMB/src/emuMB.c 2015-05-17 02:23:52.430447770 +0900
@@ -94,7 +94,7 @@
     {  0,  0,  0 },   /* nothing -> ground (no change) */
     {  0,  0,  1 },   /* left -> delayed left */
     {  0,  0,  2 },   /* right -> delayed right */
-    {  2,  0,  3 },   /* left & right (middle press) -> pressed middle */
+    {  9,  0,  3 },   /* left & right (middle press) -> pressed middle */
     {  0,  0, -1 }    /* timeout N/A */
   },
 /* 1 delayed left */
@@ -102,7 +102,7 @@
     {  1, -1,  0 },   /* nothing (left event) -> ground */
     {  0,  0,  1 },   /* left -> delayed left (no change) */
     {  1, -1,  2 },   /* right (left event) -> delayed right */
-    {  2,  0,  3 },   /* left & right (middle press) -> pressed middle */
+    {  9,  0,  3 },   /* left & right (middle press) -> pressed middle */
     {  1,  0,  4 },   /* timeout (left press) -> pressed left */
   },
 /* 2 delayed right */
@@ -110,12 +110,12 @@
     {  3, -3,  0 },   /* nothing (right event) -> ground */
     {  3, -3,  1 },   /* left (right event) -> delayed left (no change) */
     {  0,  0,  2 },   /* right -> delayed right (no change) */
-    {  2,  0,  3 },   /* left & right (middle press) -> pressed middle */
+    {  9,  0,  3 },   /* left & right (middle press) -> pressed middle */
     {  3,  0,  5 },   /* timeout (right press) -> pressed right */
   },
 /* 3 pressed middle */
   {
-    { -2,  0,  0 },   /* nothing (middle release) -> ground */
+    { -9,  0,  0 },   /* nothing (middle release) -> ground */
     {  0,  0,  7 },   /* left -> released right */
     {  0,  0,  6 },   /* right -> released left */
     {  0,  0,  3 },   /* left & right -> pressed middle (no change) */
@@ -139,33 +139,33 @@
   },
 /* 6 released left */
   {
-    { -2,  0,  0 },   /* nothing (middle release) -> ground */
-    { -2,  0,  1 },   /* left (middle release) -> delayed left */
+    { -9,  0,  0 },   /* nothing (middle release) -> ground */
+    { -9,  0,  1 },   /* left (middle release) -> delayed left */
     {  0,  0,  6 },   /* right -> released left (no change) */
     {  1,  0,  8 },   /* left & right (left press) -> repressed left */
     {  0,  0, -1 },   /* timeout N/A */
   },
 /* 7 released right */
   {
-    { -2,  0,  0 },   /* nothing (middle release) -> ground */
+    { -9,  0,  0 },   /* nothing (middle release) -> ground */
     {  0,  0,  7 },   /* left -> released right (no change) */
-    { -2,  0,  2 },   /* right (middle release) -> delayed right */
+    { -9,  0,  2 },   /* right (middle release) -> delayed right */
     {  3,  0,  9 },   /* left & right (right press) -> repressed right */
     {  0,  0, -1 },   /* timeout N/A */
   },
 /* 8 repressed left */
   {
-    { -2, -1,  0 },   /* nothing (middle release, left release) -> ground */
-    { -2,  0,  4 },   /* left (middle release) -> pressed left */
+    { -9, -1,  0 },   /* nothing (middle release, left release) -> ground */
+    { -9,  0,  4 },   /* left (middle release) -> pressed left */
     { -1,  0,  6 },   /* right (left release) -> released left */
     {  0,  0,  8 },   /* left & right -> repressed left (no change) */
     {  0,  0, -1 },   /* timeout N/A */
   },
 /* 9 repressed right */
   {
-    { -2, -3,  0 },   /* nothing (middle release, right release) -> ground */
+    { -9, -3,  0 },   /* nothing (middle release, right release) -> ground */
     { -3,  0,  7 },   /* left (right release) -> released right */
-    { -2,  0,  5 },   /* right (middle release) -> pressed right */
+    { -9,  0,  5 },   /* right (middle release) -> pressed right */
     {  0,  0,  9 },   /* left & right -> repressed right (no change) */
     {  0,  0, -1 },   /* timeout N/A */
   },
@@ -237,12 +237,14 @@

     if ((id = stateTab[pEvdev->emulateMB.state][*btstate][0]) != 0)
     {
-        EvdevQueueButtonEvent(pInfo, abs(id), (id >= 0));
+ if (!EvdevWheelEmuFilterButton(pInfo, abs(id), (id >= 0)))
+    EvdevQueueButtonEvent(pInfo, abs(id), (id >= 0));
         ret = TRUE;
     }
     if ((id = stateTab[pEvdev->emulateMB.state][*btstate][1]) != 0)
     {
-        EvdevQueueButtonEvent(pInfo, abs(id), (id >= 0));
+ if (!EvdevWheelEmuFilterButton(pInfo, abs(id), (id >= 0)))
+    EvdevQueueButtonEvent(pInfo, abs(id), (id >= 0));
         ret = TRUE;
     }

こうした後で、Option "ButtonMapping" "1 8 3 4 5 6 7 9 2"にする。
/etc/X11/xorg.confの該当部分はこんな感じ。


Section "InputDevice"
  Identifier "Kensington Slimblade"
  Driver "evdev"
  Option "Protocol" "auto"
Option "Device"   "/dev/input/by-id/usb-Kensington_Kensington_Slimblade_Trackball-event-mouse"
  Option "Buttons"  "9"
Option "Emulate3Buttons" "true"
Option "Emulate3Timeout" "100"
Option "EmulateWheel"        "true"
Option "EmulateWheelButton" "9" # requires evdev customize
Option "EmulateWheelTimeout" "250"
Option "YAxisMapping" "4 5"
Option "XAxisMapping" "6 7"
  Option "ButtonMapping" "1 8 3 4 5 6 7 9 2"
EndSection

これで、左右ボタン同時押しで中クリックとして使用し、左右ボタン同時押し+トラックボールでスクロールすることができる。ちなみに中ボタンドラッグができないのは仕様である。
非常に快適である。