메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

Perl GD::Graph 모듈 소개

한빛미디어

|

2002-04-09

|

by HANBIT

12,782

저자: 김진중 / 라이센스 : GPSL(http://shovel.dnip.net)

0. 머릿말

필자는 통계학을 전공하고 있으며 이번 학기에 "시뮬레이션 및 연습" 이라는 과목을 들어야 하게 되었다. 이 과목은 실제 현상을 설명하기 위한 통계적 모형에 대해 컴퓨터를 이용한 모의실험(Simulation)을 하는 과목이다. 이 과목의 내용은 대부분 어떠한 현상들에 대한 확률 값을 계산하고 그 계산 결과들을 그래프로 나타내주기만 하면 되는데 이것들을 모두 웹에서 보여줄 수 있도록 하는 것이 이번 과목의 두 번째 목표이다. (설마 그럴 일은 없겠지만 필자 전공이 통계학이라고 통계학에 대해서 물어보는 사람은 없기를 바란다. 필자는 전공 학점을 가히 전무 후무 하다 할 수 있을 정도의 낮은 학점대로 유지하고 있다 -_-;;)

대개 이런 경우 자바 애플릿을 이용하는 경우가 많다. 그렇지만 필자가 컴퓨터를 전공 한 것도 아닌데다가, 자바랑은 영 궁합이 맞지 않아 자바 애플릿 사용하는 것을 별로 탐탁치 않게 여기고 있기 때문에, 역시 잘 하지는 못하지만 필자의 주무기라고 할 수 있는 Perl CGI를 이용해서 시뮬레이션을 해 보기로 하였다.

처음에는 GD 모듈이라는 것을 이용해서 그림 파일을 만들어 낼 수 있다는 사실을 알고는 있었지만 그 모듈을 이용해 그래프 그릴 생각을 하니 굉장히 막막했었다. 그러나 펄이 어떤 언어인가? 그리고 cpan이 어떤 곳인가? search.cpan.org에서 아무 생각 없이 graph라고 검색을 했더니 많은 수의 graph를 생성 할 수 있는 모듈들이 쏟아져 나왔다. 필자는 그 중 GD 패키지의 하나인 GD::Graph 모듈을 이용해 아주 깔끔하고 쉽게 웹상에서 바로 그래프를 그려주는 CGI를 작성할 수 있게 되었다.

1. GD::Graph 모듈 소개

GD 모듈은 GD라는 그래픽 라이브러리를 이용해서 쉽게 펄로 다양한 그림을 그리고 이미지 파일로 만들거나 출력할 수 있게 해주는 모듈이다. 그리고 GD::Graph 모듈은 GD 모듈에서 파생된 모듈로써 여러 모양의 그래프를 쉽게 그리고 이미지 파일로 만들거나 출력해 주는 아주 유용한 모듈이다. Graph 모듈에는 lines, bars, points linespoints, area, mixed, pie 형태의 그래프를 그릴 수 있도록 해주는 클래스들이 포함되어 있으며, 여러 가지 다양한 기능들을 포함하고 있다.

참고로 GD::Graph3d 모듈이라는 것도 있는데 이것은 이름에서 보다시피 3차원 그래프를 그릴 수 있도록 해주는 모듈이며, 이외에도 GD::Graph에서 파생된 Chart, CGI::Graph 등등 다른 유용한 모듈들도 있다. 하지만 이 기사에서는 GD::Graph만 간략하게 다루도록 하겠다.

2. GD::Graph 모듈 얻기

윈도우 계열에서는 PPM을 이용하면 된다. 리눅스등에서는 패키지 관리프로그램등을 이용해서 설치 하면 된다. 끝!

...돌 던질 때 제발 짱돌은 삼가해 달라..그거 되게 아프다...;;

역시 예전 펄 쓰레드 기사에서도 썼듯이 삽질을 좋아하는 성격상, 또한 삽질을 좋아하시는 독자들을 위해서 소스를 컴파일해서 사용하는 법을 알아보기로 하겠다.

일단 펄은 당연히 설치되어 있어야겠고, search.cpan.org에 가서 "Graph"라는 키워드로 검색을 한 후 GD::Graph 라는 모듈을 찾아서 소스를 받아 온다.

컴파일 방법도 역시 아주 쉽다. 소스를 풀어 놓은 후 소스 디렉토리 안에 들어가서 다음과 같이 해주면 된다.
  perl Makefile.PL

  make

  make install(물론 root로)
대부분의 모듈들은 이 순서로만 하면 거의 한큐에 설치가 된다. 제대로 설치가 되었는지를 확인하려면,
  make samples
한 후에 samples 디렉토리로 들어가서 sample*.png 나 sample*.gif 파일을 그래픽 뷰어로 확인해 보면 된다. 이때 GD::Graph 모듈을 컴파일 하기 전에 버전 1.19 이상의 GD 라이브러리가 설치 되어 있어야 하며 GD::Text::Align 모듈도 설치 되어 있어야 한다. 그냥 간단하게 자동 설치 프로그램들을 이용해서 설치하는 것이 속 편할 듯 싶다..-_-;;

* 참고로 필자는 데비안을 쓰는데 데비안에서는
  apt-get install libgd-perl-graph
라는 명령어로 한큐에 설치가 된다. 죄송하지만 레드햇은 써 본지가 5년이 넘어서 잘 모르겠다..;;

3. GD::Graph 모듈의 간단한 사용법

먼저 데이터는 x 값들의 배열의 배열들로 만들어진다. 당연히 x 값들의 모든 배열들은 같은 크기여야 한다. 그렇지 않으면 GD::Graph 모듈은 에러를 낼 것이다. 데이터는 다음과 같은 형식으로 만들어 낸다.
  @data = ( 
     ["1st","2nd","3rd","4th","5th","6th","7th", "8th", "9th"],
     [    1,    2,    5,    6,    3,  1.5,    1,     3,     4],
     [ sort { $a <=> $b } (1, 2, 5, 6, 3, 1.5, 1, 3, 4) ]
  );
또는
  @x_label = { "1st","2nd","3rd","4th","5th","6th","7th", "8th", "9th"};
  @x_value_1 = { 1, 2, 5, 6, 3, 1.5, 1, 3, 4};
  @x_value_2 = { sort { $a <=> $b } (1, 2, 5, 6, 3, 1.5, 1, 3, 4) }
  ...
 
  @data = ( \@x_label, \@x_value_1, \@x_value_2, ... )
이렇게 배열의 배열로 x 축 데이터를 만들어 내는데, 첫번째 인자는 x 축의 눈금들에 붙여질 이름이나 수치들의 배열이고, 두 번째부터는 그래프를 그리는 데 이용하는 x 값들의 배열들을 나열하면 된다. 사실 데이터 타입을 정확히 말하자면 배열의 레퍼런스들을 저장해 놓은 배열인 것이므로, 데이터 배열 안에 배열을 직접 저장하는 일은 없기를 바란다. (필자도 말이 꼬이고 있다..-_-;;)

그 다음 new 메소드를 호출하여 원하는 형태의 GD::Graph 객체를 생성한다. 그래프 종류에는 막대그래프, 선 그래프, 원 그래프, 복합 그래프 등이 있다.
  $graph = GD::Graph::chart->new(400, 300);
위의 chart 라는 키워드 대신 lines, bars, points, linespoints, area, mixed, pie도 쓸 수 있다. 행여나 "chart"라는 단어를 쓰는 독자분은 아무도 없으리라고 생각한다.(사실 필자가 그짓을 했었다..-_-;;)

다음은 그래프의 옵션을 지정하는 방법이다.
  $graph->set(
    x_label => "X Label", # X 축의 라벨 이름을 붙인다.
    y_label => "Y label", # Y 축의 라벨 이름을 붙인다.
    title   => "Simple Graph", # 그래프의 타이틀을 지정해준다.
    y_max_value   => 8, # y 축의 최대 값을 지정한다.
    y_tick_number => 8, # y 축의 눈금을 몇개로 나눌 것인가를 지정한다.
    y_label_skip  => 2  # y 축 눈금에 붙이는 값들을 몇개마다 붙일 것인가를
                          지정해준다.
  );
조금 설명이 애매하지만, 그래프를 그리고 출력해보면 바로 알 수 있을 것이다. 그리고 바로 그래프를 그리면 된다.
  my $gd = $graph->plot(\@data); # 데이터 셋 역시 레퍼런스로 넘겨준다.
생성된 그래프 데이터를 파일로 저장하는 방법은 GD 라이브러리의 버전에 따라서 조금씩 다르다. 1.19 이전의 GD 라이브러리를 쓴다면
  open(IMG, ">file.gif") or die $!;
  binmode IMG;
  print IMG $gd->gif;
  close IMG;
위와 같이 하고, 1.20 이상의 최신 버전을 사용한다면
  open(IMG, ">file.png") or die $!;
  binmode IMG;
  print IMG $gd->png;
  close IMG;
또는 다음과 같이 사용하면 된다.
  open(IMG, ">file.gd2") or die $!;
  binmode IMG;
  print IMG $gd->gd2;
물론 다음과 같은 축약형의 사용 방법도 존재한다.(각각의 경우 GD 라이브러리가 지원하는 함수를 사용한다.)
  print IMG $graph->plot(\@data)->gif;
  print IMG $graph->plot(\@data)->png;
  print IMG $graph->plot(\@data)->gd;
  print IMG $graph->plot(\@data)->gd2;
CGI 스크립트에서 쓰려면 다음과 같이 하면 된다.
  use CGI qw(:standard);
  ...
  print header("image/png");
  binmode STDOUT;
  print $graph->plot(\@data)->png;
4. GD::Graph 모듈의 실제 적용 예

이제 간단하게나마 사용법을 알았으니 실제로 사용을 해보자. 다음은 필자가 했었던 시스템 신뢰도에 대한 시뮬레이션 결과를 웹상에서 그래프로 그려낸 것을 캡쳐한 그림이다.


[그림] 시스템 신뢰도에 대한 시뮬레이션 결과를 웹상에서 그래프로 나타낸 그림

(1-(1-p)^2)*(1-(1-p)^4) 와 1-(1-p*(1-(1-p)^2)^2) 이것이 각각의 시스템의 신뢰도를 계산하는 확률식인데 이것에 대해서는 필자에게 질문하지 말길 바란다. 필자도 어떻게 나온 식인지 잘 모른다 ㅡ,ㅡ;

프로그램의 주요 골격은 계산식에서 ^ 연산자는 펄에서 사용할 수 있는 ** 연산자로 바꿔주고, p를 0부터 1까지 0.1씩 증가시켜가면서 대입시킨 후 그 식을 eval로 계산해 내고 그 결과들을 배열에 저장한 후 그 값들을 이용하여 그래프를 그려주는 아주 단순한 프로그램이다.

단순히 구현만 해 놓은 것이고, 필자의 프로그래밍 실력 또한 좋지 못해서 그다지 깔끔한 소스는 아니지만 주석을 자세하게 달아 놨으니 설명은 주석으로 대신하는 것으로 한다(사실은 필자의 주특기인 "귀찮아!!" 스킬 구사중..;;).
---- graph.html ----

  
  
  Chapter 1
  
     
  
   
   
  

  


---- graphh.html ----

  
  
  
  
  
System Reliability
수식을 바꿔넣고 실행해보세요 =)
---- graph.cgi ---- #!/usr/bin/perl -w use CGI; # CGI 모듈 사용 use GD::Graph::lines; # 문제의 GD::Graph 모듈 사용 # lines 부분을 다음과 같은 키워드로 대체하면 # lines, bars, points, linespoints, area, mixed, pie # 그 모듈 형식의 그래프를 그릴 수 있음 $q = new CGI; # CGI 객체를 생성 $first = $q->param("first"); # 첫번째 신뢰도 확률식을 저장 $second = $q->param("second"); # 두번째 신뢰도 확률식을 저장 @x_label = (); # x 축의 라벨값들을 저장하는 리스트 @f_value = (); # 첫번째 신뢰도 확률식에 확률을 대입한 신뢰도 값들을 # 저장 할 변수를 초기화 @s_value = (); # 두번째 신뢰도 확률식에 확률을 대입한 신뢰도 값들을 # 저장 할 변수를 초기화 $first =~ s/\^/**/g; # 확률식에서 누승 연산자인 ^ 를 펄이 인식할 수 있는 $second =~ s/\^/**/g; # ** 연산자로 바꿔준다 # 아래는 0 부터 1 까지 0.1 씩 증가하는 확률 값들을 확률식에 대입하여 # 신뢰도를 계산 한 후 그 식을 직접 eval 함수로 계산한 후에 # 각각의 신뢰도 배열에 저장한다 for ($i = 0; $i <= 1; $i += 0.1) { push(@x_label, $i); $temp = $first; $temp =~ s/p/$i/g; # p 라고 되어 있는 부분을 확률값으로 치환 $fv = eval($temp); # eval 함수를 이용하여 확률식을 직접 계산 push(@f_value, $fv); $temp = $second; $temp =~ s/p/$i/g; $sv = eval($temp); push(@s_value, $sv); push(@fs_value, $fv - $sv); # 세번째 그래프로 첫번째 확률식의 신뢰도와 # 두번째 시스템 확률식의 신뢰도의 차이를 # 다른 그래프 하나도 표시하기 위함 } # 그래프를 그리기 위한 데이터 리스트 # 이 리스트에는 x 축의 라벨 값들과 # 그 다음 그리고자 하는 그래프 값들을 가진 배열를의 레퍼런스들의 # 리스트를 가진다. 즉 그래프의 갯수는 넘겨주는 인수의 갯수 -1 @data = (\@x_label, \@f_value, \@s_value, \@fs_value); # 그래프를 그릴 영역을 400x300 으로 만든다 $graph = GD::Graph::lines->new(400, 300); $graph->set( y_label => "Reliability", # y 축의 이름 x_label => "Probability", # x 축의 이름 title => "System Reliability", # 그래프의 제목 y_min_value => 0, # y 축의 시작 값 y_max_value => 1, # y 축의 최대값 y_tick_number => 10, # y 축의 눈금을 몇개로 나눌 것인가 y_label_skip => 1, # y 축에 붙이는 라벨을 눈금 몇개마다 하나씩 붙일 것인가 ); my $gd = $graph->plot(\@data); # 그래프를 생성해서 gd 에 저장 print $q->header("image/gif"); # gif 파일을 전송한다고 알려줌 binmode STDOUT; # 출력 모드를 바이너리로 바꾸고 print STDOUT $gd->png; # gd 에 저장되어 있는 그림 파일을 표준출력으로 출력 close STDOUT;
5. 더 해야 할 것...

위의 프로그램으로 그래프를 출력해 보면 조금 딱딱한 꺽은선 그래프가 보일 것이다. 하지만 x값을 100개 정도로 만들어서 넣어보면 곡선 그래프처럼 보일 것이다(사실 필자의 홈페이지에는 이렇게 만들어 놨다..^^;).

언제나 그렇듯이 필자는 머리가 나빠서(골이 비었으니 당연하지 않은가? ;;) 복잡한 응용이나 깊숙한 것 까지는 파헤치지 못했다. 그렇지만 이 정도면 그래프를 그려야 하는 왠만한 작업은 쉽게 해 낼 수 있을 것이라고 생각한다(이 CGI 를 어떤 분에게 보여 드렸더니 왜 진작 이 생각을 못했을까라고 한탄 하는 것을 보았다.).

GD::Graph의 perldoc 문서를 보면 상당히 많은 옵션들과 메소드들이 있는 것을 알 수 있다(그래프의 색깔, 폰트, 다양한 출력 양식, 데이터 지정 법 등). 그만큼 다양한 모양과 기능의 그래프를 만들 수 있다는 얘기이므로 그래프를 좀 더 이쁘게 만들고 싶다면 GD::Graph 문서를 한 번 읽어 보기 바란다(많은 도움이 될 것이라 생각됨).

더 나아가 GD 모듈을 공부한다면 아마 웹상에서 그래픽을 조작해야 하는 왠만한 작업은 쉽게 해 낼 수 있을 것이라고 장담한다. 물론 웹 상이 아닌 경우는 말 할 것도 없고……

6. 참고한 것

이번에도 역시 GD::Graph의 perldoc만 참고했다. 너무 perldoc 문서가 잘되어 있는 탓일까? 외국 사이트에도 GD::Graph에 대한 소개가 나와있는 곳은 없었다. 필자가 생각하기에는 perldoc 문서와 샘플코드만 봐도 GD::Graph 모듈에 대해서는 거의 완벽하게 알 수 있게 되지 않을까 싶다.

Happy Hacking !!

김진중님은 매일매일을 숫자와 컴퓨터 프로그래밍으로 보내고 있는 프로그래머로 그들만의 세계에서는 nuthack으로 통합니다. Perl, Python, Ruby 등의 언어를 다루지만, 가장 이쁘고 아름다운 언어는 Perl이라고 우기는 Perl 예찬론자이며 모든 사람들이 Perl의 아름다움에 매료되었으면 하는 Perl 프로그래머입니다.
TAG :
댓글 입력
자료실

최근 본 책0