OCamlでCSVを読み込んでPDFにプロットしてみた。
まずOPAMで依存パッケージをインストールしておく。
opam install batteries csv camlpdf
以下のソースコードを作成し、ocamlbuild -pkgs camlpdf,csv,batteries main.native
でコンパイルし、./main.native
で実行する。手元のMacBook Air (13 inch, Mid-2011)で時間を測ると、コンパイルは1.3秒程度、実行時間は45個のCSVファイル(合計6.5 MB)の読み込み+PDF作成で2.8秒と、かなり速くて良い感じ。
main.ml
open BatList
type t = {
x: float;
y: float;
}
let write_pdf points path =
let f p =
Pdfops.Op_l (p.x *. 50.,p.y *. 1000.)
in let ps = map f points
in let ops =
concat [[Pdfops.Op_cm (Pdftransform.matrix_of_transform [Pdftransform.Translate (50., 100.)]);
Pdfops.Op_SC [0.5;0.5;0.];
Pdfops.Op_w 1.;
Pdfops.Op_m (0.,0.)
];
ps;
[Pdfops.Op_S]
]
in
let page =
{(Pdfpage.blankpage Pdfpaper.a4) with
Pdfpage.content = [Pdfops.stream_of_ops ops]}
in
let pdf, pageroot = Pdfpage.add_pagetree [page] (Pdf.empty ()) in
let pdf = Pdfpage.add_root pageroot [] pdf in
Pdfwrite.pdf_to_file pdf path
let show_points p =
Printf.sprintf "Point {%f,%f}" p.x p.y
let read_csv path =
let dat = Csv.load path in
let dat = drop 13 dat in
let a = 1 in
let decode [x;y] =
{x = float_of_string x; y = float_of_string y} in
map decode dat
let () =
let f i =
let points = read_csv (Printf.sprintf "testdata/%02d.csv" i) in
write_pdf points (Printf.sprintf "%02d.pdf" i) in
iter f (range 1 `To 45);;
なお、csv, camlpdfともにドキュメントがほぼないに等しいのでソースコードを読む必要がある。
csvはCSV.load
というのがstring -> string list list
という型で、ファイル名を指定するとCSVの二次元リストを返す関数。
PDFの出力については、AdobeのPDF仕様書を読みながらPdfops.Op_l
(PDFの線を描画するl
演算子)などの意味を紐解いていく必要があったが、PDFをいじったことのある人であればなんとかなる感じ。