주어진 점에서 선분을 그립니다.

주어진 점에서 선분을 그립니다.

여러 포인트(>= 10000)로 형식화된 목록이 있습니다.

x y

예를 들어

1 2
1.0001 2.003
...

첫 번째와 두 번째, 두 번째와 세 번째, n번째와 (n+1)번째 세그먼트 사이의 세그먼트를 벡터 그래픽으로 그릴 수 있는 Linux 프로그램이 있습니까?

답변1

gnuplotJoseph R.이 언급했듯이 오래된 고전 제품 과 벡터 기반 및 비트맵 기반의 다양한 형식으로 다양한 그래픽을 생성할 수 있는 최신 제품이 많이 있습니다 . 하지만 이러한 프로그램은 다재다능하기 때문에 올바르게 사용하는 방법을 익히는 데 시간이 꽤 걸리고, 간단한 꺾은선형 차트를 빠르게 그리는 경우에는 다소 어려울 수 있습니다.

최근에는 SVG 형식을 독학하고, 작은 SVG 파일을 수동으로 만들고, SVG를 사용하여 다양한 것을 그리는 Python 프로그램을 작성하고 있습니다. 그래서 귀하의 질문을 보고 SVG 프로그래밍 연습을 더 많이 할 수 있는 좋은 기회라고 생각했습니다. . :)

이것은 질문에 주어진 형식의 데이터를 기반으로 간단한 선 차트를 만드는 원시 Python 프로그램입니다. 출력은 stdout으로 인쇄되는 SVG 형식이므로 파일에 저장하려면 리디렉션을 사용해야 합니다. 입력 데이터는 명령줄에 지정된 파일 이름에서 읽히지만, 파일 이름이 지정되지 않으면 프로그램은 stdin에서 데이터를 읽으므로 프로그램을 파이프에서 사용할 수 있습니다.

#입력 데이터에는 빈 줄이나 공백이 아닌 첫 번째 문자가 있는 주석 줄이 포함될 수 있습니다 . 각 줄의 X와 Y 값은 최소한 하나의 공백 문자로 구분되어야 하며(탭도 가능), 줄의 다른 공백은 무시되므로 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()

답변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')

그러면 새 캔버스가 열리고 그 위에 선이 그려지고 결과가 파일에 기록됩니다.

관련 정보