複数のポイント(> = 10000)にフォーマットされたリストがあります。
x y
例えば
1 2
1.0001 2.003
...
最初と2番目、2番目と3番目、n番目と(n + 1)番目のセグメントの間のセグメントをベクトルグラフィックで描画できるLinuxプログラムはありますか?
答え1
gnuplot
Joseph R.が述べたように、古典的な古典的な製品、ベクトルベースおよびビットマップベースのさまざまな形式でさまざまなグラフィックを生成できる最新の製品がたくさんあります。しかし、これらのプログラムは汎用性があるため、正しく使用する方法を習得するのにかなり時間がかかり、単純な折れ線グラフをすばやく描く場合は少し難しいかもしれません。
最近では、SVG形式を独学し、小さなSVGファイルを手動で作成し、SVGを使用してさまざまなものを描くPythonプログラムを書いています。それで、あなたの質問を見て、SVGプログラミングの練習をもっとするための良い機会だと思いました。 。 :)
これは、質問に与えられた形式のデータに基づいて単純な線グラフを作成するネイティブPythonプログラムです。出力はstdoutとして印刷されるSVG形式なので、ファイルに保存するにはリダイレクトを使用する必要があります。入力データはコマンドラインで指定されたファイル名から読み取られますが、ファイル名が指定されていない場合、プログラムはstdinからデータを読み取るため、プログラムはパイプで使用できます。
#
入力データには、空白行や空白ではなく、最初の文字を含むコメント行を含めることができます。各行のXとYの値は少なくとも1つのスペース文字で区切る必要があり(タブも可能です)、行の他のスペースは無視されるため、X値の前またはY値の後のスペースは無視されます。
プログラムは、すべてのXYデータから最大値と最小値を取得します。この値はSVG viewBoxの計算に使用され、図面のサイズと中心が正しく調整されます。
SVGgraph.py
#! /usr/bin/env python
''' Create a simple line graph as an SVG file
Written by PM 2Ring 2014.11.09
'''
import sys
def bounding_box(points):
xtup, ytup = zip(*points)
xlo = min(xtup)
xhi = max(xtup)
ylo = min(ytup)
yhi = max(ytup)
return xlo, ylo, xhi - xlo, yhi - ylo
def points_to_SVG(points, width, height):
#Get graph bounds & adjust to allow for a margin
xlo, ylo, xsize, ysize = bounding_box(points)
margin = 0.02
xmargin = xsize * margin
ymargin = ysize * margin
xlo -= xmargin
xsize += 2 * xmargin
ylo -= ymargin
ysize += 2 * ymargin
strokewidth = 2.0 * min(xsize, ysize) / float(max(width, height))
head = '''<?xml version="1.0"?>\n<svg xmlns="http://www.w3.org/2000/svg"
width="%d" height="%d" viewBox="%f %f %f %f"
preserveAspectRatio="xMidYMid meet">\n\n''' % (width, height, xlo, ylo, xsize, ysize)
body = ' <polyline points="\n' + '\n'.join(["%f, %f" % t for t in points]) + '\n"\n'
tail = 'style="fill:none; stroke-width:%f; stroke:#006600;"/>\n</svg>' % strokewidth
return head + body + tail
def main():
iname = sys.argv[1] if len(sys.argv) > 1 else None
f = open(iname, 'rt') if iname else sys.stdin
data = f.read().splitlines()
if iname is not None:
f.close()
points = []
for line in data:
#Skip blank lines
if not line: continue
x, y = line.split()
#Skip comments: lines which have '#' as the first non-blank char
if x.startswith('#'): continue
points.append((float(x), float(y)))
width, height = 800, 600
print points_to_SVG(points, width, height)
if __name__ == '__main__':
main()
以下はいくつかのサンプル出力です。
図test.svg
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg"
width="800" height="600" viewBox="-0.240855 -3.881333 12.524483 7.762666"
preserveAspectRatio="xMidYMid meet">
<polyline points="
0.000000, 0.000000
0.523599, 3.732051
1.047198, 2.598076
1.570796, -0.500000
2.094395, -0.866025
2.617994, 0.267949
3.141593, 0.000000
3.665191, -0.267949
4.188790, 0.866025
4.712389, 0.500000
5.235988, -2.598076
5.759587, -3.732051
6.283185, -0.000000
6.806784, 3.732051
7.330383, 2.598076
7.853982, -0.500000
8.377580, -0.866025
8.901179, 0.267949
9.424778, 0.000000
9.948377, -0.267949
10.471976, 0.866025
10.995574, 0.500000
11.519173, -2.598076
12.042772, -3.732051
"
style="fill:none; stroke-width:0.019407; stroke:#006600;"/>
</svg>
FWIW、これはこのSVGテストデータを生成するために使用したプログラムです。
SVGgraph-points.py
#! /usr/bin/env python
''' Create a list of points to test SVGgraph.py with
Written by PM 2Ring 2014.11.09
'''
import sys
from math import pi, sin
def f(x):
return sin(x) + 2.0 * sin(x * 2.0) + 1.5 * sin(x * 3.0)
def make_points(n):
points = n * [None]
for i in xrange(n):
x = 4.0 * pi * i / n
y = f(x)
points[i] = (x, y)
return points
def main():
n = int(sys.argv[1]) if len(sys.argv) > 1 else 24
points = make_points(n)
print '\n'.join(["%f %f" % t for t in points])
if __name__ == '__main__':
main()
使用法
python SVGgraph-points.py 24 > testdata
python SVGgraph.py testdata > graphtest.svg
または
python SVGgraph-points.py | python SVGgraph.py > graphtest.svg
滑らかなグラフを生成するには、SVGgraph-points.pyでパラメータを200以上に指定します。
上記のように、これは単なるおおよそのスクリプトであり、素晴らしいコマンドライン処理を追加したくありません。 :)
PythonスクリプトまたはSVGでパラメータを変更したい場合がありますが、width
SVGインジケータは通常、画像を表示するときにスケールを制御できるため重要ではありません。height
SVGファイルでこれらの値を編集しても、画像は常に中央に配置され、適切にサイズ変更されて切り取られる部分はありません。
margin
図の周りの最小余白を決定する現在0.02に設定されている倍率引数を試すこともできます。strokewidth
現在2.0に設定されている乗数を調整して、描画された線の(公称)厚さを制御できます。
楽しくお過ごしください!
編集する
これは、SVG(および他の多くのコンピュータ描画システム)によって使用される反転システムではなく、既存の座標系を使用するグラフィックススクリプトの新しいバージョンです。これでグラフは逆になりません。 :)
#! /usr/bin/env python
''' Create a simple line graph as an SVG file
Uses a conventional coordinate system,
not the usual inverted SVG system.
Written by PM 2Ring 2014.11.11
'''
import sys
def bounding_box(points):
xtup, ytup = zip(*points)
xlo = min(xtup)
xhi = max(xtup)
ylo = min(ytup)
yhi = max(ytup)
return xlo, ylo, xhi, yhi
def points_to_SVG(points, width, height):
#Get graph bounds & adjust to allow for a margin
xlo, ylo, xhi, yhi = bounding_box(points)
xsize = xhi - xlo
ysize = yhi - ylo
margin = 0.02
xmargin = xsize * margin
ymargin = ysize * margin
xlo -= xmargin
xsize += 2 * xmargin
yhi += ymargin
ysize += 2 * ymargin
strokewidth = 2.0 * min(xsize, ysize) / float(max(width, height))
head = '''<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg"
width="%d" height="%d" viewBox="%f %f %f %f"
preserveAspectRatio="xMidYMid meet">
<polyline style="fill:none; stroke-width:%f; stroke:#006600;"
transform="scale(1, -1)"
points="\n''' % (width, height, xlo, -yhi, xsize, ysize, strokewidth)
body = '\n'.join(["%f, %f" % t for t in points])
tail = '\n"/>\n</svg>'
return head + body + tail
def main():
iname = sys.argv[1] if len(sys.argv) > 1 else None
f = open(iname, 'rt') if iname else sys.stdin
data = f.read().splitlines()
if iname is not None:
f.close()
points = []
for line in data:
#Skip blank lines
if not line: continue
x, y = line.split()
#Skip comments: lines which have '#' as the first non-blank char
if x.startswith('#'): continue
points.append((float(x), float(y)))
width, height = 800, 600
print points_to_SVG(points, width, height)
if __name__ == '__main__':
main()
答え2
小さなスクリプトを書くことができます。このような:
#!/usr/bin/ruby
require 'rvg/rvg'
require 'scanf'
include Magick
RVG::dpi = 72
rvg = RVG.new(2.5.in, 2.5.in).viewbox(0,0,300,300) do |canvas|
canvas.styles(:stroke=>'black', :stroke_width=>4)
oldx=oldy=nil
ARGF.map{|line| line.scanf("%f %f")}.each do | x,y |
canvas.line(oldx,oldy,x,y) if oldx
oldx,oldy=x,y
end
end
rvg.draw.write('output.png')
これにより、新しいキャンバスが開き、その上に線が描かれ、結果がファイルに書き込まれます。