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

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

2015/02/01

Logicool Trackman Marble (TM-150r)のカップ安定化

LogicoolのMarbleはとても気に入って使っているが、自分のはボールを支えるカップがややガタついていた(個体差か?)。
特に日常作業に支障はないわけだが少し気になりだしたので、分解して固定性を高めることにした。ネジは底板の裏のラベルのところにある隠しネジを含めて5個。これらを外すとスムーズに開いた。開くと、カップは底板とは別にある程度自由に動く構造になっており、これがガタつきの原因と思われた。
瞬間接着剤で固定というのも考えたが、家に瞬間接着剤がなかったのと、やや非可逆的手段になるのが少しためらわれた。他の手段がないかと考えて、詰め物で固定する方法とした。紙で固定するのは、腐ったりカビが生えたりすると嫌だったので、ある程度の厚みがあるプラスチックということで、いらないクリアファイルを切って詰め物として使うことにした。
まず、上下方向のガタつきを抑制するため、底板とカップの間に、底にある穴を邪魔しないような形でクリアファイルを形にあうように切り、3枚重ねにした。
次に、カップと支柱のような構造との間にわずかなすきまがあり、これが前後左右方向のガタつきの原因と考えられたため、幅2mm、長さ8mmくらいに切った長方形のクリアファイルの破片を、これらの間に満遍なく差しこむように留置した。
十分にクリアファイルの破片を差し込み、カップのガタつきがないのを確認し、蓋をしめてネジを戻し、終了。しばらく使ってみたが、ガタつかず、だいぶ使いやすくなったと思った。もっと早くやってればよかった。