Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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.

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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)

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

Next, focus on the code we need to write.

Slide 15

Slide 15 text

This is output images How code we need to write?

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

about Plotting Abstraction Layer

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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)

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

about Data Abstraction Layer

Slide 24

Slide 24 text

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.

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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. こちらが提出した最終報告書

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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.

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

RubyConfTH 〜 つい最近

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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.

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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)

Slide 43

Slide 43 text

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);

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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