Victor は Ruby で SVG 画像を作るための gem です。pure Ruby なので気軽に使えます。他の gem への依存もありません。
リポジトリの examples ディレクトリ を見ると雰囲気が分かります。
これを使ってためしに簡単な散布図のようなものを描いてみました。
できあがり
ブラウザで表示させてスクリーンショットを撮ったもの。
色付きのグラフも良いものですが、白黒のも渋くて好きです。
コード
感触がなんとなく分かればOK という程度の試みです。DRY でなかったり座標決め打ちだったりしていろいろ適当ですが気にしない。
最低限でいえば直線が描ければよくて、あとは円とかテキストが描ければなお良し! という感じ。
あとは transform を使ってy軸ラベルを回転させたり CSS でフォントを指定したりできるな、といったあたりを試すことができました。
require "victor"
OFFSET_X = 80
OFFSET_Y = 20
FRAME_WIDTH = 400 - 80 - 20
FONT_SIZE = 16
STROKE_STYLE = { stroke: "#000", stroke_width: 1 }
def transform_x(x)
OFFSET_X + x * FRAME_WIDTH
end
def transform_y(y)
OFFSET_Y + (1 - y) * FRAME_WIDTH
end
def draw_line(x1, y1, x2, y2)
$svg.line(
x1: x1, y1: y1,
x2: x2, y2: y2,
style: STROKE_STYLE
)
end
def draw_frame
$svg.rect(
x: 80, y: 20, width: 300, height: 300,
style: STROKE_STYLE, fill: "transparent"
)
end
def draw_tick_x(x)
font_offset_x = -12
font_offset_y = 26
frame_x = transform_x(x)
draw_line frame_x, 320, frame_x, 330
$svg.text(
x, x: frame_x + font_offset_x, y: 320 + font_offset_y,
font_size: FONT_SIZE, class: "text"
)
end
def draw_axis_x
[0.0, 0.2, 0.4, 0.6, 0.8, 1.0].each { |x| draw_tick_x x }
frame_x = transform_x(0.5)
$svg.text(
"x軸ラベル", x: frame_x, y: 320 + 50,
text_anchor: "middle",
font_size: FONT_SIZE, class: "text"
)
end
def draw_tick_y(y)
font_offset_x = -40
font_offset_y = 5
frame_y = transform_y(y)
draw_line 70, frame_y, 80, frame_y
$svg.text(
y, x: 80 + font_offset_x, y: frame_y + font_offset_y,
font_size: FONT_SIZE, class: "text"
)
end
def draw_axis_y
[0.0, 0.2, 0.4, 0.6, 0.8, 1.0].each { |y| draw_tick_y y }
frame_y = transform_y(0.5)
$svg.text(
"y軸ラベル", x: 0, y: 0, font_size: FONT_SIZE, class: "text",
text_anchor: "middle",
transform: "translate(26, #{frame_y}) rotate(270)"
)
end
def plot_points(xs, ys)
xs.zip(ys).each do |x, y|
$svg.circle(
cx: transform_x(x), cy: transform_y(y), r: 5,
style: STROKE_STYLE, fill: "transparent"
)
end
end
def plot_line(x1, y1, x2, y2)
draw_line(
transform_x(x1), transform_y(y1),
transform_x(x2), transform_y(y2)
)
end
# --------------------------------
$svg = Victor::SVG.new(
width: 400, height: 400,
style: { background: "#fff" }
)
$svg.css = <<CSS
.text { font-family: "Noto Sans CJK JP"; }
CSS
draw_frame
draw_axis_x
draw_axis_y
plot_points [0.1, 0.6, 0.61, 0.9], [0.2, 0.3, 0.31, 0.7] # xs, ys
plot_line 0.1, 0.5, 0.9, 0.9 # x1, y1, x2, y2
$svg.save "sample.svg"
関連
SVG を Ruby のコードに変換する機能があるのがちょっとおもしろい。
この記事を読んだ人は(ひょっとしたら)こちらも読んでいます