Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rubyアソシエーション開発助成成果報告会

秒速284km
September 20, 2019

 Rubyアソシエーション開発助成成果報告会

Rubyアソシエーション開発助成成果報告会
https://rubyassociation.doorkeeper.jp/events/95710

秒速284km

September 20, 2019
Tweet

More Decks by 秒速284km

Other Decks in Programming

Transcript

  1. Ruby Association Grant 2018 Report
    Charty.new( "Visualizing your data in Ruby" ) |> Grant |> RubyKaigi |> Latest |> render
    @284km (Kazuma Furuhashi)
    Speee Inc.

    View Slide

  2. はじめての pipeline operator
    Charty.new( "Visualizing your data in Ruby" ) |> Grant |> RubyKaigi |> Latest |> render

    View Slide

  3. Revert "Add pipeline operator [Feature #15799]" · ruby/ruby@2ed68d0
    Charty.new( "Visualizing your data in Ruby" ) |> Grant |> RubyKaigi |> Latest |> render
    僕が発表タイトルを提出した頃の trunk では動いてた

    View Slide

  4. Ruby Association Grant 2018 Report
    Charty.new( "Visualizing your data in Ruby" ) |> Grant |> RubyKaigi |> Latest |> render
    Charty.new( "Visualizing your data in Ruby" ).Grant.RubyKaigi.Latest.render
    @284km (Kazuma Furuhashi)
    Speee Inc.

    View Slide

  5. about me / what I did
    @284km
    red-data-tools/charty 成果報告
    ( Red Data Tools, Asakusa.rb, Speee )

    View Slide

  6. Rubyアソシエーション開発助成⾦2018 公募開始
    応募 -> 採択
    応募した時の内容をこちらに公開しています。
    https://gist.github.com/284km/0d451d9f6a491f1d839ab8a9ad8f4fe2

    View Slide

  7. About Charty
    Charty is a open-source Ruby library for visualizing your data in a simple way.
    For example, Charty outputs these graphs.
    We can easily plot using Charty

    View Slide

  8. Why Charty?
    Ruby には可視化ツールの定番と⾔えるものが存在しないと⾔えるだろう。
    様々な理由(後ほど説明するが、存在しない分野のツールを今から⽤意するのは⼤変とい
    う理由)があるので Ruby ⽤の可視化ツールを作るのは難しいのだが、Charty の思想は
    その分野の初⼿として妥当で、やる意味もあると思えていた。
    他⾔語であっても、優れたライブラリがあるのならばそれををまず Ruby から使えるよう
    にして、まず Ruby で使える可視化ツールを⽤意しようという⽅向性です(後ほど説明し
    ます)

    View Slide

  9. なお、この時点での⾃分の状態はこの程度でした
    応募した時点ではまだよくわかっていないことは多かった
    どうやったら完成できるのかも明確には分かっていなかった
    達成するためにどの程度の調査が必要になるのかが読めなかった辺りは⼤きめの不安材料
    だった
    まあ、不明点や、不⾜する前提知識は補いながら進めればよいという考えではじめた

    View Slide

  10. The scope in Grant is as follows
    (1) Create a thin Ruby library that can use the GR framework as an independent
    backend.
    (2) Enable GR framework as backend from Charty (use SciRuby/rubyplot as the
    visualization layer)
    (3) Implements Collection Interface corresponding to Charty's Data Abstraction Layer.
    (4) Implement Daru Interface corresponding to Charty's Data Abstraction Layer.
    そして中間報告の時点で、以下 2 つの実装を余⼒があれば実施すると加えた
    (a) Support rubydown (https://github.com/sciruby-jp/rubydown)
    (b) Support ActiveRecord Interface

    View Slide

  11. Characteristics of Charty
    Charty has 2 abstract layer
    Data Abstraction Layer (abstract data structure)
    Plotting Abstraction Layer (abstract backend plotting libraries)
    (I will explain about it later)

    View Slide

  12. Basic usage
    Charty とはこういうものです。
    (I will show a demo)
    /examples/iris_dataset.ipynb

    View Slide

  13. 開発を進めると、当初の⽬論⾒どおり⾏かないことも発⽣します
    GR フレームワークとそれを利⽤する Ruby 向け可視化ライブラリである rubyplot の開発
    状況が
    予想よりも進んでいなかった
    rubyplot の他に、Python の可視化ライブラリである matplotlib を pycall.rb を介して利
    ⽤し、同時に複数の可視化ライブラリのバックエンドをサポートする事を⽬指すように⽅
    針転換した
    中間報告までに Plotting Abstraction Layer の仕組みを⽤意することを⽬指していたが、
    報告時には matplotlib と rubyplot の他に Gruff をバックエンドとしてサポートすること
    ができた

    View Slide

  14. Next, focus on the code we need to write.

    View Slide

  15. This is output images
    How code we need to write?

    View Slide

  16. e.g. Pyplot backend
    require 'charty'
    charty = Charty::Plotter.new(:pyplot)
    scatter = charty.scatter do
    iris.group_by(:label).groups.each do |label, index|
    records = iris.row[*index]
    series records[:petal_length].to_a, records[:petal_width].to_a, label: label[0]
    end
    xlabel "Petal Length"
    ylabel "Petal Width"
    end
    scatter.render('pyplot.png')

    View Slide

  17. Gruff backend example
    If we want to use another backend, difference is only one line.
    require 'charty'
    charty = Charty::Plotter.new(:gruff)
    scatter = charty.scatter do
    iris.group_by(:label).groups.each do |label, index|
    records = iris.row[*index]
    series records[:petal_length].to_a, records[:petal_width].to_a, label: label[0]
    end
    xlabel "Petal Length"
    ylabel "Petal Width"
    end
    scatter.render('gruff.png')

    View Slide

  18. about Plotting Abstraction Layer

    View Slide

  19. about Plotting Abstraction Layer
    From the previous example, the difference is one line to change backend
    Here is one of the features of Charty
    We can easily switch backend libraries with almost the same code

    View Slide

  20. More about Plotting Abstraction Layer
    Currently supported backends is below
    pyplot
    gruff
    Rubyplot
    --- 最終報告時点 ---
    google-chart (@indigolain)
    bokeh (@kantarow)
    plotly (@kei-s)
    plotly.js
    chart.js
    JFreeChart (for JRuby)

    View Slide

  21. Plotting Abstraction Layer 実装時のポイント
    出⼒可能なグラフの種類が⼀番多い Matplotlib をリファレンス実装として、その後他の
    ライブラリのサポートを増やしつつ Interface を考えるという⼿順で作業を進めた。
    サポートするグラフの種類により描画に必要なデータ構造が異なるため、より多くのグラ
    フ出⼒に対応した Interface を考えるにあたってはこの⼿順が有効であった。
    当初、GR Framework を backend に持つ rubyplot が魅⼒的であり真っ先に実装を始めた
    が、それに続いて Matplotlib のサポートを考えると両ライブラリに対応すること、より
    多くのグラフ(データ構造)に対応することを同時に考えることとなり難易度が⾼かった
    が、村⽥メンターの助⾔により順序を変えることで設計の難易度を下げることが出来た。

    View Slide

  22. 中間報告以降(2019/1 中旬) 〜

    View Slide

  23. about Data Abstraction Layer

    View Slide

  24. about Data Abstraction Layer
    Charty supports these data structures (I will show a demo)
    daru
    numo/narray
    nmatrix
    ActiveRecord
    Array
    Hash
    --- 最終報告時点 ---
    benchmark_driver (Charty Adapter)
    DataSets
    Thus, Charty can respond to various data structures.
    That's because Charty::Table is abstracted.

    View Slide

  25. Data Abstraction Layer 実装時のポイント
    Charty がサポートするデータ構造は複数あるため、各データ構造から⼀度中間データ構
    造に変換し、その中間データ構造と Plotting Abstraction Layer とのマッピング処理を⽤
    意することにより、新たなデータ構造をサポートしたい場合には中間データ構造にさえ対
    応するコードを書けばよいという状態をまず作った。
    その中間データ構造が Charty::Table (この後説明します)
    この点では Charty と思想の近い holoviews の Interface を参考にした。
    機能の拡充と共に Charty::Table の役割は増えるため、ある程度複雑になる時点で対応す
    るデータ構造に応じた Adapter を⽤意することを予定している。(Grant の開発期間後に
    adapter の仕組みを実際に⽤意した)

    View Slide

  26. Charty::Table
    村⽥メンターのメンター報告書 の説明が⾮常にわかりやすい
    可視化をする対象となるデータは tidy data 形式 (または、整然データ形式) と呼ばれる表
    形式にまとめられることが多い。
    Charty は、論理的に表として解釈可能な様々なデータ構造を Charty::Table クラスで包む
    ことで、データ構造の実装の詳細を可視化レイヤから隠すことを⽬指している。
    本プロジェクトでは、このデータ構造の詳細を隠すためのデータ抽象化レイヤを開発する
    ために、holoviews を参考にし、Daru::DataFrame、Numo::NArray、ActiveRecord の
    関係データを抽象化することに対応した。

    View Slide

  27. Feature summary of Charty
    Charty has two abstraction layers.
    Data Abstraction Layer
    Plotting Abstraction Layer.
    Thus we can use the data structures we need
    We can use output libraries we want to use.
    We can use them in any combination we need with almost no code rewrite.
    こちらが提出した最終報告書

    View Slide

  28. Grant 期間の開発 〜 RubyKaigi へと続くことができた
    Charty は特に、他⾔語の可視化ツールの調査や、インターフェイスを決めるために学習
    が必要なことが多かったと感じている。
    たとえば Grant に採択されず、中間報告、最終報告といった期限も無いまま Charty の開
    発を進めていたら、作業はしただろうけれど、いつ形になっていたかというのが今考えて
    もわからない。ずっと事前準備をしていた恐れすらあると思う。
    採択して頂き、その課程を経たことにより、RubyKaigi で話せるところまで、この期間で
    開発を進めることができたという事実がある。
    そして RubyKaigi で RubyData Workshop セッションを企画し、発表機会を提供してく
    れた村⽥メンターに感謝している。

    View Slide

  29. RubyKaigi での発表
    Charty の紹介はもちろんだが、⼀緒に開発する仲間を増やすという⽬的にフォーカスし
    た。
    現時点での知識不⾜は開発をしながら補うことができる点を伝えたかった。これは⾃分の
    経験は事実なので伝えることができた。
    Charty のできることをなるべくわかりやすく伝えることを意識した。
    結果的に、RubyKaigi 期間中に 5 ⼈の⽅から合計 5 つの PR が作られマージされた。これ
    はうれしい。
    発表後声をかけてくれた⽅々とすぐに Hack space に移動して作業開始できたり、コード
    懇親会で Charty テーブルを作って頂くことができた点などにとても助けられた。このよ
    うなサポートのお陰で開発が進んだ事実も広くしられてほしいとも思う。

    View Slide

  30. 名古屋Ruby会議02 〜 RubyConf Taiwan 〜 RubyConfTH
    Grant 期間の成果として Charty が動く形で⾒せられるようになったため、
    名古屋Ruby会議02, RubyConf Taiwan, RubyConfTH と海外の Ruby カンファレンスも含め登
    壇する機会が得られた。
    Charty をより多くの⽅に知ってもらう機会
    海外のカンファレンスで登壇するという経験
    台湾のコード懇親会でも Charty の開発に参加してくれる⼈が現れ、その PR はマージさ
    れた

    View Slide

  31. Now Charty with JRuby is working
    This impression became my motivation.
    So, I implemented JFreeChart backend.
    Thanks to Charles, development progressed.

    View Slide

  32. Charty が JRuby に対応したのは RubyConf Taiwan での発表後に頂いた Charles からのこの
    メッセージがキッカケであるように、海外カンファレンスでも変わらず、発表と開発の良いル
    ープを回すことが出来たのは⾮常に良い経験となった。この経験は今後にも活かしたい

    View Slide

  33. Charty with JRuby
    red-data-tools/charty-backends-jfreechart
    Please use JRubyist.
    This is not yet complete.
    If you have important use cases, I can write code.
    I'm grad to hear everyone's thoughts.

    View Slide

  34. Other cases
    For example, google-charts, bokeh, plotly
    These were implemented by a pull request that "I'd like to use Charty if this library is
    supported by the backend"
    If there is a real User and Real-world use case exists, it depends on the priority with
    other work, but consider support for a new backend

    View Slide

  35. RubyConfTH 〜 つい最近

    View Slide

  36. benchmark_driver との連携
    benchmark_driver は Grant 2017 のプロジェクトで、Ruby のスゴイベンチマークライブ
    ラリ
    実は、この benchmark_driver の最終報告 には、benchmark_driver の活⽤例として、僕
    が 2018年3⽉に沖縄Ruby会議で発表した時の資料が参照されている
    という程度に benchmark_driver ユーザとしてお世話になっているツール
    そこで、benchmark_driver の出⼒⽤の Charty プラグインというものを作りました
    実質 Grant 2 年分の成果とも⾔えるのではないでしょうか!?

    View Slide

  37. This combination is also possible. Because Charty has Data Abstraction Layer to support
    various data structures.
    benchmark_driver plugin to render with Charty
    benchmark-driver/benchmark_driver-output-charty
    This combination is also possible. Because Charty has Data Abstraction Layer to support
    various data structures.

    View Slide

  38. RubyConfTH での発表から、k0kubun さんが box plot に対応したらよさそうと PR を送って
    くれて、ベンチマーク結果を箱ひげ図で出⼒する機能が最近加わりました。
    https://github.com/benchmark-driver/benchmark_driver-output-charty/pull/3
    Grant での開発を経て発表機会が⽣まれ、発表をきっかけに開発がまた進むという良いループ
    が⽣まれていて、こういう感じにまた次に続くようにしたいなということを最近は考えるよう
    になりました。

    View Slide

  39. benchmark-driver outputs as below by default.
    $ gem install
    $ benchmark-driver examples/parse.yaml
    Calculating -------------------------------------
    csv 3.1.1 csv 3.0.1
    unquoted 61.332 38.149 i/s - 100.000 times in 1.630461s 2.621311s
    quoted 30.558 17.023 i/s - 100.000 times in 3.272469s 5.874313s
    mixed 40.932 23.047 i/s - 100.000 times in 2.443082s 4.339030s
    include_col_sep 11.167 10.657 i/s - 100.000 times in 8.955275s 9.383878s
    include_row_sep 11.180 4.339 i/s - 100.000 times in 8.944608s 23.044523s
    encode_utf-8 39.129 31.525 i/s - 100.000 times in 2.555671s 3.172112s
    encode_sjis 49.982 31.289 i/s - 100.000 times in 2.000736s 3.196026s
    Comparison:
    unquoted
    csv 3.1.1: 61.3 i/s
    csv 3.0.1: 38.1 i/s - 1.61x slower
    quoted
    csv 3.1.1: 30.6 i/s
    csv 3.0.1: 17.0 i/s - 1.80x slower
    mixed
    csv 3.1.1: 40.9 i/s
    csv 3.0.1: 23.0 i/s - 1.78x slower
    include_col_sep
    csv 3.1.1: 11.2 i/s
    csv 3.0.1: 10.7 i/s - 1.05x slower
    include_row_sep
    csv 3.1.1: 11.2 i/s
    csv 3.0.1: 4.3 i/s - 2.58x slower
    encode_utf-8
    csv 3.1.1: 39.1 i/s
    csv 3.0.1: 31.5 i/s - 1.24x slower
    encode_sjis
    csv 3.1.1: 50.0 i/s
    csv 3.0.1: 31.3 i/s - 1.60x slower

    View Slide

  40. benchmark_driver-output-charty outputs as below.
    $ benchmark-driver examples/parse.yaml -o charty

    View Slide

  41. おかげさまでこのように、Charty は開発者が少しずつ増えながら、開発と発表を良い感じに
    繋げつつ開発する流れができつつあります。

    View Slide

  42. Speee という会社で働いているのですが、あるサービスの production 環境でも
    Charty が動いています。(production で使われるというのもまた嬉しい成果です)
    Recently, we introduced Charty in our production environment of Web Application,
    which is our job.
    This Web Application is a common Rails Application.
    At that time, we were asking for Charty to output json, not image file.
    Here is an example using plotly.js (I will show a demo)

    View Slide

  43. Code
    # controller
    plotlyjs = Charty::Plotter.new(:plotlyjs)
    plotlyjs.table = DataModel.where(foo: bar)
    json_data = plotlyjs.to_json
    layout_data = plotlyjs.layout
    # view

    # javascript
    import * as Plotly from 'plotly.js-dist';
    Plotly.newPlot("sample", json_data, layout_data);

    View Slide

  44. Future plan (we aim for these)
    Improvement interface (Continued)
    Support red-arrow for Data Abstraction Layer
    because Apache Arrow is great.
    Release stable version
    Add supported dataset (red-datasets) (e.g. titanic)
    発表を聞いた⼈が、より興味を持ちやすくなるようなデータで説明できるように
    開発者を増やしたいから
    Support Unicode Plot
    Sixel support

    View Slide

  45. 興味を持った⽅はぜひ使ってみてください
    開発に興味を持った⽅は⼀緒に開発しましょう!

    View Slide

  46. Acknowledgement
    Ruby Association Grant
    Various opportunities
    My motivation
    @mrkn
    Great mentor
    Drawing a Charty concept
    @kou
    Various implementation advice
    Red Data Tools org and all members
    All your support
    Speee, Inc
    Gave me a lot of time and support

    View Slide