D3.js+AngularJSなRadianのチュートリアルを進めながらグラフ書いてみた(データプロットまで)

続編

前回はとりあえず線が引けて便利だね!というところまでだったので、 データをつっこんで線を引かせるところをやっていきます。

ということで今回もチュートリアルをさらう。

plot-data

前回同様、template.htmlを編集していく。

<plot height=300 aspect=2>
  <lines x="[[dat.a]]" y="[[dat.b]]"></lines>
</plot>

<plot-data name="dat" format="csv" cols="a,b">
1,5
2,10
3,14
4,12
5,22
6,6
7,5
</plot-data>

とするとデータを投入できます。 投入したデータは同じangularのスコープ範囲内だったら有効。 フォーマットは現在csv, jsonに対応しています。 colsで各列に名前をa, bと名前をつけているので、逆に言うとcsvデータの部分はヘッダー無しで値のみを記述する必要があるのに注意。

htmlにデータを直接記入する以外にも

<plot-data name="dat" format="csv" cols="day,temp,prec"
           src="/data/vic2012.csv">
</plot-data>

という書き方も可能。

jsonの場合には列名の指定はない。

<plot-data name="dat" format="json">
[{ "a": 1, "b": 5 },
 { "a": 2, "b": 10 },
 { "a": 3, "b": 14 },
 { "a": 4, "b": 12 },
 { "a": 5, "b": 22 },
 { "a": 6, "b": 6 },
 { "a": 7, "b": 5 }]
</plot-data>

ただし線を引かせる場合にはxの配列、yの配列を用意しないといけない。通常はunderscore,jsのpluckとかでやる処理だけど、radianではpluckオペレータとして#が用意されているので

<plot height=300 aspect=2>
  <lines x="[[dat#a]]" y="[[dat#b]]"></lines>
</plot>

と、#つなぎで指定してやれば目的の処理が可能。すごい。

metadata

データにメタデータ(軸名、単位)を仕込むとグラフ描画時にラベルが自動で設定される。 dateフォーマットを指定すると軸を日付ベースにしてくれて更に便利。

<plot height=300 aspect=2 axis-x-label="January 2012">
  <lines x="[[dat.date]]" y="[[dat.temp]]"></lines>
</plot>

<plot-data name="dat" format="csv" cols="date,temp">
  <metadata name="date" format="date"></metadata>
  <metadata name="temp" label="Temperature" units="&deg;C"></metadata>
"2012-01-01",  3.80
"2012-01-02",  5.50
"2012-01-03",  7.90
"2012-01-04",  8.50
"2012-01-05",  4.90
"2012-01-06",  2.70
"2012-01-07",  5.70
"2012-01-08",  6.50
"2012-01-09",  6.80
"2012-01-10",  2.20
"2012-01-11",  1.40
"2012-01-12",  1.60
"2012-01-13", -0.10
"2012-01-14",  1.70
</plot-data>

f:id:matsu_chara:20131101160145j:plain

pointプロット

linesではなくpointsをプロットする際には以下のようにすればOK。 strokeで縁取り、marker-sizeでマーカーのサイズを設定できるなど簡単。

<plot height=300 aspect=1>
  <points x="[[iris.sepal_length]]" y="[[iris.petal_length]]"
          marker-size=25 stroke="none" fill="red"></points>
</plot>

<plot-data name="iris" format="csv" src="/data/iris.csv"
           cols="sepal_length,sepal_width,petal_length,petal_width,species">
  <metadata name="sepal_length" label="Sepal length" units="mm"></metadata>
  <metadata name="sepal_width" label="Sepal width" units="mm"></metadata>
  <metadata name="petal_length" label="Petal length" units="mm"></metadata>
  <metadata name="petal_width" label="Petal width" units="mm"></metadata>
</plot-data>

f:id:matsu_chara:20131109193815j:plain

barプロット

棒グラフもかける。linesやplotの代わりにbarsを使うだけ。 fillやoffsetを使うと、色をつけたり、棒同士を離したり出来る。

<plot height=300 aspect=1 range-y=0 stroke="none" bar-width=0.3>
  <bars x="[[dat.x]]" y="[[dat.y]]" fill="red" bar-offset=0.2></bars>
  <bars x="[[dat.x]]" y="[[dat.z]]" fill="blue" bar-offset=-0.2></bars>
</plot>

<plot-data name="dat" format="csv" cols="x,y,z">
  1,34,10
  2,22,20
  3,53,50
  4,27,20
  5,13,30
  6,8,40
  7,5,10
  8,12,5
  9,29,40
  10,44,20
  11,27,10
  12,30,5
</plot-data>

f:id:matsu_chara:20131109193844j:plain

また、生データをつっこめば自動でヒストグラムを生成してくれる機能もある。

<plot height=300 aspect=1 range-y=0 stroke="none"
      hist="[[histogram(dat.x,10)]]">
  <bars x="[[hist.centres]]" y="[[hist.counts]]" fill="red"></bars>
</plot>

<plot-data name="dat" format="csv" cols="x">
  -0.21991614
  -1.21243350
  0.25558776
  -0.13629943
  -2.22833941
  -1.60829920
  -0.55755778
  -0.23925929
  0.40663494
  0.99105558
  -0.95120549
  -1.67478975
  -0.14602045
  -0.01902537
  -0.40205444
  1.44275512
  -1.05451039
  -1.01921213
  1.03799046
  -0.33640740
</plot-data>

f:id:matsu_chara:20131109193920j:plain

ちなみにhistogram()の第二引数は区間の分割数。

雑なまとめ

紹介できてない機能(angularによるデータバインディング、レイアウト機能など)もあるけど、データをjsonで持ってきて、各種グラフが書けるところまでは追えたので個人的な目的は達成できそう。

PHPでの名前付き引数のRFCについて

名前付き引数は、オプションの管理に便利な機能です。

グラフ作成の際に、軸名を指定すれば付くし指定しなければ省略されるだとか、 色を指定してもいいし省略すれば自動で適当につけてくれたりするなど

plot(x, y, linewidth=2.5)
plot(x, y, color="red",  linewidth=2.5, linestyle="-")

のようにできるとすごい便利。

で、PHPでも出来ないかなと思って調べたら出来なかったんですがメモ。

Python

Pythonは下のように引数名を指定して関数を呼び出すことが出来る。

def foo(a, b, c=8, d=9):
    print a, b, c, d

foo(1, 2)      # 1 2 8 9
foo(1, 2, d=4) # 1 2 8 4

便利。

Ruby

Rubyは以前は出来なかったけれど、2.0から出来るようになった。

def foo(a, b, c:8, d:9)
    print a, b, c, d,"\n"
end

foo(1, 2)      # 1289
foo(1, 2, d:4) # 1284

これも便利。*1

PHP

一方、PHPではこのような便利な記法は使えないよう。 ただ、default値の連想配列を用意して、呼ぶときも連想配列に突っ込んでもらって、 array_mergeすれば機能的には同じことが出来る。(昔のrubyのマネだけど・・・。)

<?php
function foo($a, $b, array $args) {
    $defaults = ['c' => 8, 'd' => 9];
    $args = array_merge($defaults, $args);
    
    print $a . $b . $args['c'] . $args['d'] . "\n";
}

foo(1, 2, []);         // 1289
foo(1, 2, ['d' => 4]); // 1284

上記のコードの良くないなーと思うところは、

  • やりたいこと以外の処理が多くなり、コードの見通しがあまり良くない。
  • オプションを指定しない時に、いちいち空のarray渡したくない。
  • 引数$argsはarrayだということは分かるが、中に何を入れれば良いかはコードかドキュメントを読まないといけない。
  • 無効なキーが渡された時(typoなど)に何のエラーもなく、ただ無視される。

のような点だと思う。

そして

今は使えなくてもいつか使えるようになるかなと調べたところ2012年に提案されていたらしい→PHP: rfc:namedparameters。しかし、

Discussion

We don't see the real need for named parameters, as they seem to violate PHP's KISS principle. It also makes for messier code.

でobsoleteだった。

と思ったら、2013年バージョンが再度提案されていました→PHP: rfc:named_params。 これによると

<?php
htmlspecialchars($string, double_encode => false);
// Same as
htmlspecialchars($string, ENT_COMPAT | ENT_HTML401, 'UTF-8', false);

みたいなことが可能になるらしい。 とても便利そうだけど仕様として複雑で、実装が大変な模様。 まだUnder Discussionなので、今後が気になる機能です。応援したいです。

結論

PHPでは出来ないので我慢しよう。

参考

  1. http://www.daisaru11.jp/blog/python-%E3%83%A1%E3%83%A2/%E9%96%A2%E6%95%B0%E5%BC%95%E6%95%B0%E3%81%AE%E5%8F%97%E3%81%91%E6%B8%A1%E3%81%97/

  2. Ruby 2.0.0リリース! – キーワード引数を使ってみよう

  3. » Ruby2.0のキーワード引数でオプショナルな引数にまつわる面倒事からさようなら TECHSCORE BLOG

  4. PHP: rfc:namedparameters

  5. PHP: rfc:named_params

*1:Pythonではfoo(1,2,3,4)とできますが、Rubyで同じことをするとArgumentErrorと言われるなど、ちょっと違いがある。

pandocでmarkdownからgithub風シンタックスハイライトされたhtml生成(ついでに数式)

再びpandocとmarkdownネタ。 前回はこちら

markdownからhtml生成できてすごい!となったんですが、 見栄え的にはGithub風になっていると落ち着くということで出来ないかどうか調べたところ出来そうだったので方法をメモ

github.css

github風のCSSを公開してくださっている方がいるので、ダウンロード Github Markdown CSS - for Markdown Editor Preview

テンプレートを作成

  1. C:\Users<ユーザ名>\AppData\Roaming\cabal\pandoc-1.11.1\data\templates
    のdefault.html5をコピーしてgithub.htmlなどの適当な名前にする。

  2. headタグの中の適当なところにgithub.cssの中身をコピー

markdownからhtmlを生成

> pandoc -s --template=github.html test.md -o test.html

結果

通常

f:id:matsu_chara:20131023021308j:plain

Github風

f:id:matsu_chara:20131023021315j:plain

ちなみに

> pandoc -s -t html5 -c github.css test.md -o test.html

でも可能です。 cssファイルが埋め込みにならないんですが、それでもOKならこっちの方が楽です。

ついでに数式

公式のデモPandoc - Demos通りにmath系の好きなオプションを以下から選んでつければOK。 mathjaxの場合は-sをつけても完全なstandaloneにはならないそうです。(サーバとの通信が必要)

> pandoc math.text -s -o mathDefault.html
> pandoc math.text -s --mathml -o mathMathML.html
> pandoc math.text -s --webtex -o mathWebTeX.html
> pandoc math.text -s --mathjax -o mathMathJax.html
> pandoc math.text -s --latexmathml -o mathLaTeXMathML.html

phpでarray_zip()相当のことをしたい

がっつり既出ネタ

array_zip

phpでarray_zip()みたいなことをしたい。

つまり、pythonのzipのように リストを二つ渡すとタプルのリストを生成してくれる関数がほしい。

# -*- coding: utf-8 -*-
a = [1,2,3]
b = ["a", "b", "c"]
zip(a,b)
# [(1, 'a'), (2, 'b'), (3, 'c')]

ついでに

# ...
c = [4,5,6]
zip(a,b,c)
# [(1, 'a', 4), (2, 'b', 5), (3, 'c', 6)]

みたいにn-tupleが生成できると嬉しい。

phpにタプルは無いけれど配列ベースでなら、array_mapのコールバック関数にnullを指定するとできるらしい。

<?php
$a = [1,2,3]
$b = ["a", "b", "c"]

array_map(null, $a, $b);
# [[1, "a"], [2, "b"], [3, "c"]]
?>

とのこと。 関数化すると、こんな感じ

<?php
function array_zip($args) {
  $args = func_get_args();
  array_unshift($args, null);
  return call_user_func_array("array_map", $args);
}
?>

もちろん配列ベースなのでmutableだし要素追加も出来てしまうんだけど、・・・

あれ・・・メリットあるのかな・・・

array_column

array_系の関数といえばphp5.5からのarray_columnが楽しそうです。 いわゆるpluck*1的なことができる関数で、PHP: array_column - Manualから例を持ってくると、

<?php
$records = array(
    array(
        'id' => 2135,
        'first_name' => 'John',
        'last_name' => 'Doe',
    ),
    array(
        'id' => 3245,
        'first_name' => 'Sally',
        'last_name' => 'Smith',
    ),
    array(
        'id' => 5342,
        'first_name' => 'Jane',
        'last_name' => 'Jones',
    ),
    array(
        'id' => 5623,
        'first_name' => 'Peter',
        'last_name' => 'Doe',
    )
);
 
$first_names = array_column($records, 'first_name');
# ["John", "Sally", "Jane", "Peter"]
?>

のような感じ。

*1:そういえばpythonにpluckは無いのかと思ったらfuncyなるモジュールがあるらしい

sedを使いつつvisual studioを無理やりゴリゴリ回す方法

研究室向けシリーズその4

このシリーズ書くのに疲れていますが最後なので頑張ります。
前回batで処理を自動化したと思うのですが、研究室内のプログラムは割とパラメータが#defineされているケースがあってプログラムの実行時引数に指定するのは面倒だったりします。ちょっとプログラム改変すればいいんですが、それは面倒だなあということも結構あるのではないでしょうか。
ということで今回は

#define N 1

のようにdefineされたパラメータNを1~20まで変化させながらプログラムを順に回すのを目標にします。

流れとしては
sedを使って#define N ◯を見つけて#define N ◯'のように置換→
visual studioのコマンドでビルド→
実行→
ファイル移動→...
終了
とします。

一回一回ビルドして回すのは結構乱暴な感じがしますが、とりあえず問題なさそうな範囲でやりたいと思います。

sedとは

色々機能ありますが、今回使う範囲で言えば置換とか行の削除、追加が出来る便利なやつくらいの認識でOKだと思います。Linuxとかのテキスト処理系としてはawkと併せて抑えておくべき存在です。(多分)

sedのインストール

http://sourceforge.jp/projects/sfnet_gnuwin32/releases/
からsed-4.2.1-setup.exeをダウンロード
C:\Program Files (x86)\GnuWin32\binにパスを通す。
パスとはというかたはawkのときの記事を参照。

sedの使い方

あるファイルのある行を置換したいときは

sed –e “s/(置換前)/(置換後)/” (ファイル名)

のように使います。

例: test.c の fooを10から20に変更

sed –e “s/#define foo 10/#define foo 20/ test.c

注意が一点
"/"は他の命令や区切りと区別できないので"\/"としましょう。(エスケープするといいます)
例: test.c の fooFlagをコメントアウトしてオフにする
sed –e “s/#define fooFlag//*#define fooFlag*// test.c  →できない
sed –e “s/#define fooFlag/\/*#define fooFlag*\// test.c →できる

通常はsedの実行結果は標準出力に出力されますが、

  • iオプションをつけることで元のファイルを上書きすることができます。

例:test.c の fooを10から20に変更され、test.cが上書きされる。

sed -i –e “s/#define foo 10/#define foo 20/ test.c

その他の機能については割愛します。

ループごとに変化する値を変更する。

#define N 5とかを置換前に指定していると#define N 6のときには当然引っかからないので
正規表現を使って#define N 数字みたいな緩いマッチングを行います。
正規表現については割愛するので興味があったら勉強してみてください。
今回は使う分だけ紹介します。

test.c の fooを任意の値から20に変更

sed –e “s/#define foo [0-9]\+/#define foo 20/ test.c

[0-9]+ は 0~9までの文字(=数字)が一回以上繰り返される という意味
(+はエスケープして\+とする。)

[0-9]\+という正規表現を使うことで任意の桁数の数字が指定できます。

CUIVisual studioを使ったビルド

Devenv.exeというVisual studioについてくるプログラムを使えばビルド可能です。
visual studio2010をインストールした状態ではDevenv.exeは
C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\にあります。

パスを通してもいいですし、そのまま
C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe
と指定しても動きます。(,exeは省略可能)

使い方は
Devenv.exe /build release (.slnファイル名)
です。

結果

ということで今までの知識を総動員すると以下のスクリプトが出来上がります。

for /l %%i in (1, 1, 20) do (
  sed -i -e "s/#define N [0-9]\+/#define N %%i" .\SOURCE\Defconst.h

 “C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\Devenv.exe” ^
 .\Test\Test.sln /build release

    .\x64\release\Test.exe input.lst output.lst

    md ..\matome\N=%%i
    xcopy .\Test\answer ..\matome\result_N=%%i /y
)

あとは"Test"の部分などを自分用に適宜変更すれば使えると思います。
各行が何を意味しているか理解しておくと、応用範囲が広がります。

今回はsedやら正規表現やら雑に説明してしまいましたが、(特に正規表現は)割と役に立つ知識なので勉強しておくといいかなーと思います。