[번역] 간단한 그래프와 차트를 레일스에서 만드는 차트킥 소개

1378086969294 Wagurano님이 11달전에 작성함. 3 301 
간단한 그래프와 차트를 레일스에서 만드는 차트킥 소개 --------------------------------------- 원문: https://www.sitepoint.com/make-easy-graphs-and-charts-on-rails-with-chartkick/ 일리야 보드로프-크루코브스키 2016년 6월 13일 씀 ![diagram](//dab1nmslvvntp.cloudfront.net/wp-content/uploads/2016/06/1465561082chart.png) 우리가 매일 다루는 데이타는 포맷이 다양하다. 내가 보기에, 수치 데이타를 보여주는 포맷으로 그래프가 제일 편하다. 사용자들은 밋밋한 표보다는 시시각각 바뀌는 그래프가 보기에 좋고 재미있어서 좋아한다. 웹앱에서 아름답고 시시각각 변하는 그래프를 만드는 방법은 많지만, 특별한 방법을 소개하겠다. 그것은 앤드류 케인이 만든 차트킥이다. 차트킥은 [구글 차트 Google Charts](https://developers.google.com/chart/), [하이차트 Highcharts](http://www.highcharts.com/) 그리고 [차트제이에스 Chart.js](http://www.chartjs.org/)와 동작한다. 옵션을 설정하는 방법은 많고 [그룹데이트 groupdate](https://github.com/ankane/groupdate), [하이탑 hightop](https://github.com/ankane/hightop), [액티브 미디안 active_median](https://github.com/ankane/active_median)과 같은 라이브러리를 쓴다. 여기서는 차트킥을 레일스앱에서 다루는 방법을 소개하고, 여러가지 그래프를 그리고, 설정하고, 천천히 그려본 다음, 그룹데이트와 하이탑 젬을 사용하는 법을 살펴보겠다. 소소코드는 [기트허브](https://github.com/bodrovis/Sitepoint-source/tree/master/Graphs_with_Chartkick)에 있다. 헤로쿠에서 [데모](https://sitepoint-graphs.herokuapp.com/)를 볼 수 있다. # 애플리케이션 준비 레일스 애플리케이션을 아래와 같이 새로 만든다: $ rails new HappyGrapher -T 여기서 레일스5 RC 버전을 썼으나, 위의 코드는 레일스4와 3에서 동작한다. 앱은 "체육인(선수) sporters"(육상선수)와 선수들이 참가하는 대회를 죽 나열하여 보여줍니다. 여기서 필요한 테이블은 선수 sporters * 이름 (글자, 문자열) name (string) * 나이 (숫자, 수치, 정수) age (integer) - 여기서는 18세에서 50세까지 * 국가 (숫자, 수치, 정수) country_id (integer) - 선수 sporters 테이블이 국가 countries 테이블을 참조하는 외부키 foreign key 국가 countries * 국가명 (글자, 문자열) title (string) - 데이터베이스에 국가 50개를 임의로 넣는다. 대회 competitions * 대회명 (글자, 문자열) title (string) - 가짜로 만든 대회 대회 결과 competition_results 선수와 대회 테이블의 다대다 관계를 만들기 위한 테이블 * 선수 아이디 sporter_id (integer) - 외부 참조 키 a foreign key * 대회 아이디 competition_id (integer) - 외부 참조 키 a foreign key * 순위 place (integer) - 선수가 차지한 순위. 여기서는 1부터 6까지. \ 위의 내용으로 데이터베이스를 만든다: $ rails g model Country name:string $ rails g model Sporter name:string age:integer country:references $ rails g model Competition title:string $ rails g model CompetitionResult sporter:references competition:references place:integer $ rake db:migrate 다음으로 콘트롤러와 뷰를 만들고 라우팅을 정한다: statistics_controller.rb class StatisticsController < ApplicationController def index end end views/statistics/index.html.erb <h1>Statistics</h1> config/routes.rb [...] root 'statistics#index' [...] 여기까지 잘 따라왔다. 차트를 그리려면 샘플 데이타가 필요하기 대문에 데이타를 넣어 보자. # 샘플 데이타 불러오기 샘플 데이타를 불러오는 과정을 빨리 넘어가기 위해, 이름과 이메일부터 문단까지 만들어 주는 [페이커 faker](https://github.com/stympy/faker) 젬과 국가 정보를 쉽게 사용하는 [컨트리 countries](https://github.com/hexorx/countries) 젬을 사용하겠다. 젬파일에 페이커 젬과 컨트리 젬을 넣는다: Gemfile [...] gem 'countries' gem 'faker' [...] 그리고 젬 설치한다: $ bundle install seeds.rb 파일을 열어 아래 코드를 붙여 넣어서 국가 50개를 만든다: db/seeds.rb ISO3166::Country.all.shuffle.first(50).each do |country| Country.create({name: country.name}) end 이 코드를 실행하면 어떤 국가가 데이터베이스에 들어갈지 모른다. 남극대륙이나 아프리카 서부 공화국 상투메가 들어가더라도 놀라지 마라. 선수를 넣자: db/seeds.rb 100.times { Sporter.create({ name: Faker::Name.name, age: rand(18..50), country_id: rand(1..50) }) } 여기서 페이커 젬으로 이름을 만든다. 다음으로, 대회. 대회 이름은 미리 준비하지 못하여 직접 대회 이름을 타이핑하겠다. db/seeds.rb %w(tennis parachuting badminton archery chess boxing racing golf running skiing walking cycling surfing swimming skeleton).each {|c| Competition.create({title: c}) } 끝으로 대회 결과를 만든다: db/seeds.rb Competition.all.each do |competition| sporters = Sporter.all.shuffle.first(6) (1..6).each do |place| CompetitionResult.create({ sporter_id: sporters.pop.id, competition_id: competition.id, place: place, created_at: rand(5.years.ago..Time.now) }) end end 여기서 주의할 점은 created_at 컬럼을 몇년전이나 몇개월전에 열린 대회인 것처럼 날짜를 바꾼다. # 간단한 차트를 보여주기 자, 주요 기능인 그래프를 구현하기 위한 준비가 끝났다. 차트킥 젬을 젬 파일에 넣는다: Gemfile [...] gem 'chartkick' [...] 그리고 설치한다: $ bundle install 차트킥은 구글 차트, 하이차트, 그리고 차트제이에스(2.0부터, 기본 어댑터)를 지원한다. 여기서 하이차트를 사용하겠지만 구글 차트를 쓰는 과정도 하이차트를 설치하는 과정과 매우 비슷하다. 우선, 하이차트 최신 버전을 내려받아 자바스크립트 디렉토리에 넣는다.(또는 layouts/application.html.erb 파일에서 CDN 주소를 javascript_include_tag 헬퍼로 넣어도 된다) 다음으로, 아래 두줄을 넣는다. javascripts/application.js [...] //= require highcharts //= require chartkick [...] 이것으로 차트를 그릴 수 있다. 선수 나이를 보여주는 막대 차트를 그려보자. 모든 선수를 가져온다: statistics_controller.rb [...] def index @sporters = Sporter.all end [...] 그리고 뷰를 수정한다: views/statistics/index.html.erb <%= bar_chart @sporters.group(:age).count %> 나이에 따라 선수묶어서 그룹에 속한 선수가 몇명인지 계산한다. 아주 간단하다. 그래프에 제목을 넣고, 가로와 세로 크기를 바꾸고 다른 속성들에 대한 설정을 어떻게 하는지 궁금할 것이다. 아규먼트를 bar_chart와 같은 메소드에 바로 넘겨주거나 :library 옵션에 [설정 사항](https://github.com/ankane/chartkick#options)을 더 넣을 수 있다. StatisticsHelper를 만들고 아래 코드를 붙여 넣는다: statistics_helper.rb module StatisticsHelper def sporters_by_age bar_chart @sporters.group(:age).count, height: '500px', library: { title: {text: 'Sporters by age', x: -20}, yAxis: { allowDecimals: false, title: { text: 'Ages count' } }, xAxis: { title: { text: 'Age' } } } end end :library 뒤에 차트킥에서 사용하는 라이브러리에 맞게 설정한다. 여기서 Y축의 수치를 표기하지 않고(나이가 20살인 선수가 2.5로 표기하는 것 대신) 선수 이름으로 표기한다. X축도 이름을 설정한다. library 옵션 중 제일 첫번째는 전체 그래프의 이름을 사용한다.(보통 제일 아래에 나타난다) 하이차트의 다른 옵션은 [문서](http://api.highcharts.com/highcharts)를 참고하라. 한번 설정하면 [다른 차트에도 적용되므로](https://github.com/ankane/chartkick#global-options) 주의하라. # 하이탑 사용하기 체육인의 가장 "많은" 나이대 위주로 보여주려면, 작고 유용한 하이탑 hightop 젬을 사용하라. 젬파일에 아래와 같이 넣는다: Gemfile [...] gem 'hightop' [...] 그리고 실행한다. $ bundle install 이제부터 가장 많은 나이대 10개를 표시할 수 있다: views/statistics/index.html.erb <%= bar_chart @sporters.top(:age, 10) %> # 그래프를 비동기로 그리기 데이터베이스가 그래프를 그리기에 처리할 데이타가 많다면, 페이지는 느리게 보일 것이다. 따라서, 그래프를 비동기로 그리는 편이 좋다. 차트킥 chartkick 역시 이러한 기능을 [지원한다.](https://github.com/ankane/chartkick#say-goodbye-to-timeouts) 라우트를 분리하고 콘틀로러 액션을 만들고 뷰에 이러한 라우트를 사용해야 한다. 제이쿼리 jQuery 또는 젭토 제이에스 Zepto.js 가 필요하다. 라우트를 새로 만든다: config/routes.rb [...] resources :charts, only: [] do collection do get 'sporters_by_age' end end [...] 그리고 콘트롤러: charts_controller.rb class ChartsController < ApplicationController def sporters_by_age result = Sporter.group(:age).count render json: [{name: 'Count', data: result}] end end 이것이 작동하도록, 헬퍼 안에서 새로 만든 라우트를 호출하도록 코드를 수정한다: statistics_helper.rb [...] def sporters_by_age bar_chart sporters_by_age_charts_path, height: '500px', library: { [...] } end [...] 이제 차트를 비동기로 불러오고 사용자들이 페이지의 다른 내용을 볼 수 있겠다. 선수 @sporters 인스턴스 변수가 필요없으므로 StatisticsController 콘틀로러의 index 메소드에서 인스턴스 변수를 빼도 된다. # 다양한 그래프 유형 ## 막대 차트 막대 차트를 사용한 사례로 국가마다 선수가 몇명인지 보여주겠다. 우선, 위에서 만든 헬퍼와 비슷한 헬퍼를 새로 만든다: statistics_helper.rb [...] def sporters_by_country column_chart sporters_by_country_charts_path, library: { title: {text: 'Sporters by country', x: -20}, yAxis: { title: { text: 'Sporters count' } }, xAxis: { title: { text: 'Country' } } } end [...] 헬퍼를 뷰에서 사용한다: views/statistics/index.html.erb [...] <%= sporters_by_country %> [...] 그리고 라우트에서 사용한다: config/routes.rb [...] resources :charts, only: [] do collection do get 'sporters_by_age' get 'sporters_by_country' end end [...] 콘트롤러 액션의 경우, 결과 result 를 직접 구성해야 하기 때문에 좀 더 복잡해질 것이다: charts_controller.rb [...] def sporters_by_country result = {} Country.all.map do |c| result[c.name] = c.sporters.count end render json: [{name: 'Count', data: result}] end [...] 결과 해시 result hash 는 국가 이름을 키로 하고 각 국가의 선수 총인원을 값으로 구성한다. 페이지를 새로 고침하여 보이는 결과를 확인하라! 보충 class Country < ActiveRecord::Base has_many :sporters end ## 쌓인 막대 차트 각 국가에서 순위(1에서 6까지)를 몇번 차지했는지 보여주겠다. 헬퍼를 새로 정의한다: statistics_helper.rb [...] def results_by_country column_chart results_by_country_charts_path, stacked: true, height: '500px', library: { title: {text: 'Results by country', x: -20}, yAxis: { title: { text: 'Count' } }, xAxis: { title: { text: 'Countries and places' } } } end [...] 쌓인 막대 stacked: true option 다음 결과를 제공한다: ![쌓인 막대](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2016/06/1465561113stacked.png) 헬퍼를 뷰 안에서 사용한다: views/statistics/index.html.erb [...] <%= results_by_country %> [...] 그리고 헬퍼를 라우트에 넣는다: config/routes.rb [...] resources :charts, only: [] do collection do get 'sporters_by_age' get 'sporters_by_country' get 'results_by_country' end end [...] 끝으로, 콘트롤러 액션을 만든다: charts_controller.rb [...] def results_by_country result = Country.all.map do |c| places = {} (1..6).each do |place| places[place] = c.sporters.joins(:competition_results). where("competition_results.place = #{place}").count end { name: c.name, data: places } end render json: result end [...] 모든 국가를 불러와서 맵 메소드를 사용하여 데이타를 배열로 구성한다. 맵 메소드 안에서는 한 국가에서 특정 순위를 차지한 모든 선수를 찾는다. 조인 joins 메소드는 순위 정보를 저장한 대회 결과 copetition_results 테이블과 조인하는데 사용한다. where과 count 메소드로 원하는 값을 찾는다. 그런 다음, 위에서 봤듯이, 국가명을 :name에 넣고 :data에 순위에 대한 해시를 넣는다. 결과 result는 해시로 만든 배열을 만들 것이다. 보충 class Sporter < ActiveRecord::Base belongs_to :country has_many :competition_results end ## 라인 차트와 그룹데이트 마지막으로 다룰 차트는 라인 차트다. 라인 차트를 보여주려고 대회가 매해 몇번 열리는지 보여주겠다. 헬퍼를 새로 만든다. statistics_helper.rb [...] def competitions_by_year line_chart competitions_by_year_charts_path, library: { title: {text: 'Competitions by year', x: -20}, yAxis: { crosshair: true, title: { text: 'Competitions count' } }, xAxis: { crosshair: true, title: { text: 'Year' } } } end [...] 마우스 포인터를 따라서 움직이는 십자선을 표기하기 위해 :crosshair 옵션을 사용한다. ![십자선 crosshair](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2016/06/1465561139crosshair.png) 헬퍼를 뷰안에서 사용한다: views/statistics/index.html.erb [...] <%= competitions_by_year %> [...] 그리고 라우트를 새로 넣는다: config/routes.rb [...] resources :charts, only: [] do collection do get 'sporters_by_age' get 'sporters_by_country' get 'results_by_country' get 'competitions_by_year' end end [...] 콘트롤러 액션을 새로 만들어야 하지만 대회를 개최 연도로 묶고 대회를 세려면 어떻게 해야 할까? 물론, 쿼리를 직접 만들어도 되지만, 차트킥 젬을 만든 사람이 이러한 경우에 쓸 수 있도록 그룹데이트 젬을 직접 만들었다. 젬 이름처럼, 연도, 월, 일자 등으로 그룹으로 묶을 수 있다. 젬은 시간대, 날짜 범위, 시간 포맷, 순서 그리고 여러가지를 지원하여 차트킥과 함께 쓰기에 좋다. 그룹데이트를 젬파일에 넣는다: Gemfile [...] gem 'groupdate' [...] 그룹데이트는 SQLite3을 지원하지 않아서 다른 데이터베이스를 써야 한다. 여기서는 PostgreSQL을 사용한다. 단, MySQL을 사용하려면, [시간대를 지원하는 젬](https://github.com/ankane/groupdate#for-mysql)을 설치해야 한다. 젬파일을 sqlite3 대신 pg 젬으로 바꾼다: Gemfile [...] gem 'pg' [...] 그리고 젬을 설치한다: $ bundle install 그런 다음 database.yml 설정 파일을 수정한다: config/database.yml [...] development: adapter: postgresql encoding: unicode database: your_database pool: 5 username: your_user password: your_password host: localhost port: 5432 [...] 데이터베이스 마이그레이션을 다시 실행하고 테이블에 샘플 데이타를 만들어 넣는다. $ rake db:migrate $ rake db:seed 위 명령어를 실행하기 전에 데이터베이스 생성(rake db:create)해야 한다. 콘틀롤러 액션을 만든다: charts_controller.rb [...] def competitions_by_year result = CompetitionResult.group_by_year(:created_at, format: "%Y").count render json: [{name: 'Count', data: result}] end [...] 좋아 보인다. :format 옵션은 키에 대한 포맷을 정할 수 있다. 연도만 표시하려고 하면, %Y를 쓴다. 다른 지시어는 [루비 공식 문서](http://ruby-doc.org/core-2.2.2/Time.html#method-i-strftime)에서 찾을 수 있다. 페이지를 새로 고침하고 결과를 확인한다. 여기서 보이는 그래프에 만족하지 않고 [하이차트 문서](http://api.highcharts.com/highcharts)에서 설정사항을 살펴보라. # 맺음말 여기서 차트를 간단히 그리는 매우 훌륭한 젬인 차트킥 Chartkick에 대해 살펴보았다. 여러 가지 차트를 그려보고 비동기로 불러왔으며, 그룹데이트와 하이탑 같은 젬 몇개를 더 사용하였다. 물론 여기서 소개한 젬 말고도 더 있으며, 다른 젬 소개 문서를 보고 코드를 더 실습하라. 질문과 느끼거나 바라는 점 등을 적어도 된다. 차트 그리기 안녕! ![글쓴이](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2016/02/1455561538cr_thumb-96x96.jpg) 일리야 보드로프-크루코브스키 Ilya Bodrov-Krukowski [트위터](https://twitter.com/bodrovis) [구글플러스](https://plus.google.com/103641984440210150447) [페이스북](https://facebook.com/isbodrov) [링크드인](https://linkedin.com/in/bodrovis) [기트허브](https://github.com/bodrovis) 일리야 보드로프는 전문 IT 강사이며, 캠페이너 LLC에서 시니어 엔지니어이고, 사이트포인트에서 글을 쓰며 가리치는 일을 돕고, 모스크바 항공 대학 Moscow Aviations Institute 로 강의 나간다. 주로 사용하는 프로그래밍 언어는 루비 (레일스 포함)와 자바스크립트다. 코딩하고, 사람들을 가리치고, 새로운 것을 배우기를 즐긴다. 일리야는 시스코와 마이크로소프트 자격증을 가지고 있고 교육 센터에서 강사로 일했었다. 시간이 남을 때 트위터를 하고, 자신의 [웹사이트](http://www.ilyabodrov.me/)에 글을 올리고, 오픈소스 프로젝트에 참여하고, 스포츠 하러 나가고 음악을 연주한다. 우리말 옮김: 와그라노(wagurano)

Comments (3)

원문에 있는 그림과 사진을 넣었습니다.
1378086969294 Wagurano님이 11달전에 작성함.
수고 많으셨습니다.
Hschoi han Lucius.choi님이 11달전에 작성함.
와 정말 감사합니다. 때마침 그래프 그리는게 필요했는데.. 다음에 그래프 기능 구현할 때 자세히 보겠습니다. 감사합니다 (__)
156f26b8fba6ff872e8a2bd5fe631b3d Leonardo.lee1993님이 10달전에 작성함.