12/08/2018, 13:33

Vẽ đồ thị trong Rails với thư viện Chartkick

Mỗi ngày chúng ta đều làm việc với các ddnhj dạng dữ liệu khác nhau. Chúng ta có rất nhiều cách hiển thị dữ liệu khác nhau như: dạng bảng, đồ thị v.v.... Theo quan điểm của tôi thì biểu diễn dữ liệu dưới dạng đồ thị là một cách biểu diễn trực quan, giúp người dùng có sự tương tác và nhận thức ...

1.png

Mỗi ngày chúng ta đều làm việc với các ddnhj dạng dữ liệu khác nhau. Chúng ta có rất nhiều cách hiển thị dữ liệu khác nhau như: dạng bảng, đồ thị v.v.... Theo quan điểm của tôi thì biểu diễn dữ liệu dưới dạng đồ thị là một cách biểu diễn trực quan, giúp người dùng có sự tương tác và nhận thức nhanh hơn so với dạng bảng.

Hiện nay, chúng ta có rất nhiều thư viện hỗ trợ việc vẽ đồ thị một cách đơn giản, giao diện đẹp nhưng trong bài viết này tôi xin giới thiệu về thư viện Chartkick (Một thư viện để tạo đồ thị trong Ruby). Chartkick có thể kết hợp với Google Chart, HighChart, Chart.js và nó cũng cung cấp các API để nhà phát triển có thể tùy biến.

Trong bài viết này, tôi sẽ trình bày cách sử dụng Chartkick trong một ứng dụng Rails để vẽ đồ thị.

Tạo ứng dụng rails bằng câu lệnh sau:

$ rails new DemoGrapher -T

Giả sử ứng dụng của chúng ta là theo dõi thông tin về các vận động viên thể thao và các cuộc thi mà họ tham gia. Vì vậy, chúng ta sẽ thiết kế CSDL như sau:

sporters

  • name (string)
  • age (integer)
  • country_id (integer)

countries

  • name (string)

**competitions **

  • title (string)

competition_results

  • sporter_id (integer)
  • competition_id (integer)
  • place (integer)

Khởi tạo các model cần thiết:

$ 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

Chúng ta cũng sẽ tạo StatisticsController để làm trang chủ của ứng dụng:

statistics_controller.rb

class StatisticsController < ApplicationController
  def index
  end
end

views/statistics/index.html.erb

<h1>Statistics</h1>

config/routes.rb

[...]
root 'statistics#index'
[...]

Tiếp theo ta cần phải khởi tạo những dữ liệu mẫu thông qua file seed.rb:

Bổ sung các gem countries và gem facker để tạo dữ liệu mẫu:

Gemfile

[...]
gem 'countries'
gem 'faker'
[...]

và chạy bundle install trong terminal.

Để tạo dữ liệu mẫu ta bổ ung đoạn code sau vào file seed.rb:

# Tạo 50 countries
ISO3166::Country.all.shuffle.first(50).each do |country|
  Country.create({name: country.name})
end

# Tạo 100 sporter sample
100.times { Sporter.create({
                               name: Faker::Name.name,
                               age: rand(18..50),
                               country_id: rand(1..50)
                           }) }

# Tạo dữ liệu cho bảng competition
%w(tennis parachuting badminton archery chess boxing racing golf running skiing walking cycling surfing swimming skeleton).each do |c|
    Competition.create({title: c})
end

# Tạo dữ liệu cho bảng CompetitionResult
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

Để sử dụng được thư viện Chartkick trong ứng dụng rails ta cần khai báo gem chartkick trong Gemfile, sau đó chạy bundle install:

Gemfile

[...]
gem 'chartkick'
[...]

Tiếp theo ta cần khai báo include thư viện trong file javascripts/application.js của ứng dụng:

[...]
//= require highcharts
//= require chartkick
[...]

Tất cả chuẩn bị đã xong. Bây giờ, ta có thể bắt đầu hiển thị biểu đồ . Để bắt đầu, ta sẽ hiển thị biểu đồ phân bố các sporters theo lứa tuổi.

Load data sporter

statistics_controller.rb

[...]
def index
  @sporters = Sporter.all
end
[...]

Và trong views ta sẽ hiển thị biểu đồ dạng thanh như sau:

views/statistics/index.html.erb

<%= bar_chart @sporters.group(:age).count %>

Tuy nhiên, ta cần định dạng biểu đồ như tên hiển thị, màu sắc, v.v..., để làm được việc này thì có cách đơn giản nhất là sử dụng hepler với method sporters_by_age để sử dụng phương thức bar_chart như sau:

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, # Chỉ hiển thị số nguyên trên trục y
         title: {
             text: 'Ages count'
         }
      },
      xAxis: {
         title: {
             text: 'Age'
         }
      }
    }
  end
end

Trong ví dụ này, trục X là thể hiện số sporter, còn trục Y là các tuổi thống kê

:library cung cấp rất nhiều tùy chọn. Ở đây, trên trục Y sẽ chỉ hiển thị số nguyên (vì chúng ta không thể có 2.5 sporters ở độ tuổi 20 được) và đặt cho nó một cái tên. Ngoài ra, ta cũng có rất nhiều option khác. Hãy tham khảo tài liệu tại đây

Cuối cùng trong views ta chỉ cần gọi phương thức sporters_by_age :

views/statistics/index.html.erb

<%= sporters_by_age %>

Sử dụng Hightop

Nếu bạn chỉ muốn hiển thị biểu đồ với 10 tuổi phổ biến nhất đối với sporter thì có gem hightop để ta có thể thực hiện điều này một cách đơn giản

  • Khai báo Gemfile và chạy bundle install:
[...]
gem 'hightop'
[...]
  • Sử dụng:

views/statistics/index.html.erb

<%= bar_chart @sporters.top(:age, 10) %>

Selection_005.png

Khi dữ liệu quá nhiều, nếu render biểu đồ trong một trang thì việc tải trang sẽ rất chậm. Chính vì vậy mà Chartkick đã hỗ trợ việc hiển thị biểu đồ bất đồng bộ.

Bắt đầu, ta bổ sung một routes mới trong file config/routes.rb :

[...]
resources :charts, only: [] do
  collection do
    get 'sporters_by_age'
  end
end
[...]

Tiếp theo tạo một controller mới là ChartsController:

class ChartsController < ApplicationController
  def sporters_by_age
    result = Sporter.group(:age).count
    render json: [{name: 'Count', data: result}]
  end
end

Cuối cùng ta cần định nghĩa lại sporters_by_age trong heleper như sau:

def sporters_by_age
    bar_chart sporters_by_age_charts_path, height: '500px', library: {
      title: {text: 'Sporters by age', x: -20},
      yAxis: {
         allowDecimals: false, # Chỉ hiển thị số nguyên trên trục y
         title: {
             text: 'Ages count'
         }
      },
      xAxis: {
         title: {
             text: 'Age'
         }
      }
    }
  end

Để demo cho kiểu biểu đồ này, ta sẽ biểu diễn phân bố của các sporter theo countries. Tương tự những bước như khi sử dụng bar_chart, ta cần thêm phương thức sporters_by_country vào trong file helper để sử dụng phương thức column_chart cho việc hiển thị biểu đồ cột như sau:

[...]
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
[...]

Và trong views cần sử dụng phương thức này để hiển thị biểu đồ :

views/statistics/index.html.erb

<%= sporters_by_country %>

Trong file routes, ta cần khai báo path sporter_by_country:

[...]
resources :charts, only: [] do
  collection do
    get 'sporters_by_age'
    get 'sporters_by_country'
  end
end
[...]

Cuối cùng, ta cần thêm action sporters_by_country vào trong 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
[...]

Selection_006.png

Trên đây là một bài giới thiệu về cách sử dụng cơ bản của gem Chartkick để vẽ hai loại biểu đồ hình cột trong ứng dụng Rails. Hy vọng sẽ giúp được các bạn có thêm một tùy chọn để sử dụng khi cần vẽ biểu đồ trong dự án của mình

Xin cảm ơn các bạn đã theo dõi!!

Tài liệu thao khảo: http://chartkick.com/

0