与えられた点から線分を描画します。

与えられた点から線分を描画します。

複数のポイント(> = 10000)にフォーマットされたリストがあります。

x y

例えば

1 2
1.0001 2.003
...

最初と2番目、2番目と3番目、n番目と(n + 1)番目のセグメントの間のセグメントをベクトルグラフィックで描画できるLinuxプログラムはありますか?

ベストアンサー1

gnuplotJoseph 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でパラメータを変更したい場合がありますが、widthSVGインジケータは通常、画像を表示するときにスケールを制御できるため重要ではありません。heightSVGファイルでこれらの値を編集しても、画像は常に中央に配置され、適切にサイズ変更されて切り取られる部分はありません。

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()

おすすめ記事