charty 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d70645a4ca621ee142714f3079e85dc843585fa6364c4476d4fdd86761c3b6f
4
- data.tar.gz: b4fa589a9b2c5ba31a6869399c5e90e79767d9e8e4a9a0bf0c5e2d4997725dbf
3
+ metadata.gz: 4cf18b5e31bf29099d3d9386b8b022e38013bba339c129a0292af39983e2bccb
4
+ data.tar.gz: 4eb934400a4fc7c60354bf7f7f31e33d4be8cdbdeafb1d47762264d94c8c5a2a
5
5
  SHA512:
6
- metadata.gz: 6588c1c0105d0994cd024d08f328a6bf10241975abf4ee1b332be0a956f32d7073aed9867b5ddf708ef578e570caf733d422153a479ecae6fedef81daab391c1
7
- data.tar.gz: 47999e4ce59f7cfb4263a5002b3dc070c128971257d7fed81fc23bd7314632cd441bba2ac93a0fdbeb3644d739434dad3d1cad7b465a093af6c53a5766555991
6
+ metadata.gz: 33f5c4ea51ea77a66538e62e43222aaa4f77942b526461ef881cd0ff092eb17a16830937eab032995361a1e7b9e0063e79f682b75fa1c0011644410f02c23b11
7
+ data.tar.gz: cd0c31ae974c4efc6192dc0fa74c93db41cdacac6e5a82cfded9ca1b4285e706c925641df483020d620f22e3aed5fae7263d2364ac0cfb5df35bbf4fc72ad034
data/README.md CHANGED
@@ -69,6 +69,63 @@ require "datasets"
69
69
  penguins = Datasets::Penguins.new
70
70
  ```
71
71
 
72
+ #### A basic workflow
73
+
74
+ The following code shows a basic workflow of the visualization with Charty.
75
+
76
+ First you need to load the Charty library.
77
+
78
+ ```ruby
79
+ require "charty"
80
+ ```
81
+
82
+ Next you msut have a dataset you want to visualize. Here, we use the penguins dataset provided in red-datasets library.
83
+
84
+ ```ruby
85
+ require "datasets"
86
+ penguins = Datasets::Penguins.new
87
+ ```
88
+
89
+ Next you need to create a plotter object by a plotting method. Here, we use `scatter_plot` method to show the relationship
90
+ among `body_mass_g`, `flipper_length_mm`, and `species` columns in the penguins dataset.
91
+
92
+ ```ruby
93
+ plot = Charty.scatter_plot(data: penguins, x: :body_mass_g, y: :flipper_length_mm, color: :species)
94
+ ```
95
+
96
+ If you want to render and save this plotter object into an HTML file by plotly backend, you can do it like below.
97
+
98
+ ```ruby
99
+ Charty::Backends.use(:plotly) # select plotly backend
100
+ plot.save("scatter.html") # save the plot as an HTML file
101
+ ```
102
+
103
+ If you want to save the plotter into a PNG file, you can do it by specifying a output filename with `.png` extension.
104
+
105
+ ```ruby
106
+ plot.save("scatter.png")
107
+ ```
108
+
109
+ #### Jupyter Notebook
110
+
111
+ If you use Charty on Jupyter Notebook with IRuby kerenl (a.k.a. IRuby notebook),
112
+ you can render the plot just evaluate a plotter object. For example, the code below shows a scatter plot figure in
113
+ the output area.
114
+
115
+ ```ruby
116
+ Charty::Backends.use(:plotly)
117
+
118
+ Charty.scatter_plot(data: penguins, x: :body_mass_g, y: :flipper_length_mm, color: :species)
119
+ ```
120
+
121
+ Note that if you want to use the pyplot backend, you need to activate the integration between the pyplot backend and IRuby.
122
+ You can activate the integration by the following two lines.
123
+
124
+ ```ruby
125
+ Charty::Backends.use(:pyplot)
126
+ Charty::Backends::Pyplot.activate_iruby_integration
127
+ ```
128
+
72
129
  #### Bar plot
73
130
 
74
131
  Charty's statistical bar plot shows the relationship between a categorical variable and estimated means of a numeric variable.
@@ -80,8 +137,7 @@ Instead, when we specify the categorical variable as y-axis, the plot draws a ho
80
137
  The following code shows the relationship between species and the mean body masses of penguins in a vertical bar chart.
81
138
 
82
139
  ```ruby
83
- Charty::Backends.use(:pyplot)
84
- Charty.bar_plot(data: penguins, x: :species, y: :body_mass_g).render
140
+ Charty.bar_plot(data: penguins, x: :species, y: :body_mass_g)
85
141
  ```
86
142
 
87
143
  ![](images/penguins_species_body_mass_g_bar_plot_v.png)
@@ -89,8 +145,7 @@ Charty.bar_plot(data: penguins, x: :species, y: :body_mass_g).render
89
145
  Exchanging x and y axes alternates the orientation of the resulting chart.
90
146
 
91
147
  ```ruby
92
- Charty::Backends.use(:pyplot)
93
- Charty.bar_plot(data: penguins, x: :body_mass_g, y: :species).render
148
+ Charty.bar_plot(data: penguins, x: :body_mass_g, y: :species)
94
149
  ```
95
150
 
96
151
  ![](images/penguins_species_body_mass_g_bar_plot_h.png)
@@ -98,8 +153,7 @@ Charty.bar_plot(data: penguins, x: :body_mass_g, y: :species).render
98
153
  Adding color axis introduces color grouping in the bar plot.
99
154
 
100
155
  ```ruby
101
- Charty::Backends.use(:pyplot)
102
- Charty.bar_plot(data: penguins, x: :species, y: :body_mass_g, color: :sex).render
156
+ Charty.bar_plot(data: penguins, x: :species, y: :body_mass_g, color: :sex)
103
157
  ```
104
158
 
105
159
  ![](images/penguins_species_body_mass_g_sex_bar_plot_v.png)
@@ -116,8 +170,7 @@ Instead, when we specify the categorical variable as y-axis, the plot draws a ho
116
170
  The following code draws a vertical box plot to show distributions of penguins' body mass per species.
117
171
 
118
172
  ```ruby
119
- Charty::Backends.use(:pyplot)
120
- Charty.box_plot(data: penguins, x: :species, y: :body_mass_g).render
173
+ Charty.box_plot(data: penguins, x: :species, y: :body_mass_g)
121
174
  ```
122
175
 
123
176
  ![](images/penguins_species_body_mass_g_box_plot_v.png)
@@ -125,8 +178,7 @@ Charty.box_plot(data: penguins, x: :species, y: :body_mass_g).render
125
178
  As `bar_plot` above, exchanging x and y axes alternates the orientation of the resulting chart.
126
179
 
127
180
  ```ruby
128
- Charty::Backends.use(:pyplot)
129
- Charty.box_plot(data: penguins, x: :body_mass_g, y: :species).render
181
+ Charty.box_plot(data: penguins, x: :body_mass_g, y: :species)
130
182
  ```
131
183
 
132
184
  ![](images/penguins_species_body_mass_g_box_plot_h.png)
@@ -134,8 +186,7 @@ Charty.box_plot(data: penguins, x: :body_mass_g, y: :species).render
134
186
  Adding color axis introduces color grouping in the box plot.
135
187
 
136
188
  ```ruby
137
- Charty::Backends.use(:pyplot)
138
- Charty.box_plot(data: penguins, x: :species, y: :body_mass_g, color: :sex).render
189
+ Charty.box_plot(data: penguins, x: :species, y: :body_mass_g, color: :sex)
139
190
  ```
140
191
 
141
192
  ![](images/penguins_species_body_mass_g_sex_box_plot_v.png)
@@ -145,7 +196,6 @@ Charty.box_plot(data: penguins, x: :species, y: :body_mass_g, color: :sex).rende
145
196
  Charty's scatter plot shows the relationship between two numeric variables.
146
197
 
147
198
  ```ruby
148
- Charty::Backends.use(:pyplot)
149
199
  Charty.scatter_plot(data: penguins, x: :body_mass_g, y: flipper_length_mm)
150
200
  ```
151
201
 
@@ -156,7 +206,6 @@ The following example specifies `:species` variable in the color axis.
156
206
  It shows the different species by the different colors.
157
207
 
158
208
  ```ruby
159
- Charty::Backends.use(:pyplot)
160
209
  Charty.scatter_plot(data: penguins, x: :body_mass_g, y: flipper_length_mm, color: :species)
161
210
  ```
162
211
 
@@ -166,7 +215,6 @@ Moreover, size and style axes can be specified.
166
215
  The following example specifies `:sex` variable in the style axis.
167
216
 
168
217
  ```ruby
169
- Charty::Backends.use(:pyplot)
170
218
  Charty.scatter_plot(data: penguins, x: :body_mass_g, y: flipper_length_mm, color: :species, style: :sex)
171
219
  ```
172
220
 
data/charty.gemspec CHANGED
@@ -34,6 +34,9 @@ Gem::Specification.new do |spec|
34
34
  spec.add_development_dependency "test-unit"
35
35
  spec.add_development_dependency "red-datasets", ">= 0.0.9"
36
36
  spec.add_development_dependency "daru"
37
+ spec.add_development_dependency "matrix" # need for daru on Ruby > 3.0
37
38
  spec.add_development_dependency "activerecord"
38
39
  spec.add_development_dependency "sqlite3"
40
+ spec.add_development_dependency "playwright-ruby-client"
41
+ spec.add_development_dependency "iruby"
39
42
  end
data/lib/charty.rb CHANGED
@@ -3,6 +3,7 @@ require_relative "charty/version"
3
3
  require "colors"
4
4
  require "palette"
5
5
 
6
+ require_relative "charty/util"
6
7
  require_relative "charty/backends"
7
8
  require_relative "charty/backend_methods"
8
9
  require_relative "charty/plotter"
@@ -17,13 +17,13 @@ module Charty
17
17
  @series = series
18
18
  end
19
19
 
20
- def render(context, filename)
20
+ def old_style_render(context, filename)
21
21
  plot = plot(context)
22
22
  save(plot, context, filename)
23
23
  PyCall.import_module('bokeh.io').show(plot)
24
24
  end
25
25
 
26
- def save(plot, context, filename)
26
+ def old_style_save(plot, context, filename)
27
27
  if filename
28
28
  PyCall.import_module('bokeh.io').save(plot, filename)
29
29
  end
@@ -33,7 +33,7 @@ module Charty
33
33
  @series = series
34
34
  end
35
35
 
36
- def render(context, filename)
36
+ def old_style_render(context, filename)
37
37
  plot(nil, context)
38
38
  end
39
39
 
@@ -26,7 +26,7 @@ module Charty
26
26
  raise NotImplementedError
27
27
  end
28
28
 
29
- def render(context, filename="")
29
+ def old_style_render(context, filename="")
30
30
  FileUtils.mkdir_p(File.dirname(filename))
31
31
  plot(@plot, context).write(filename)
32
32
  end
@@ -1,5 +1,6 @@
1
1
  require "json"
2
2
  require "securerandom"
3
+ require "tmpdir"
3
4
 
4
5
  module Charty
5
6
  module Backends
@@ -36,7 +37,7 @@ module Charty
36
37
  @series = series
37
38
  end
38
39
 
39
- def render(context, filename)
40
+ def old_style_render(context, filename)
40
41
  plot(nil, context)
41
42
  end
42
43
 
@@ -447,7 +448,34 @@ module Charty
447
448
  # TODO: Handle loc
448
449
  end
449
450
 
450
- def save(filename, title: nil)
451
+ def save(filename, format: nil, title: nil, width: 700, height: 500, **kwargs)
452
+ format = detect_format(filename) if format.nil?
453
+
454
+ case format
455
+ when nil, :html, "text/html"
456
+ save_html(filename, title: title, **kwargs)
457
+ when :png, "png", "image/png",
458
+ :jpeg, "jpeg", "image/jpeg"
459
+ render_image(format, filename: filename, notebook: false, title: title, width: width, height: height, **kwargs)
460
+ end
461
+ nil
462
+ end
463
+
464
+ private def detect_format(filename)
465
+ case File.extname(filename).downcase
466
+ when ".htm", ".html"
467
+ :html
468
+ when ".png"
469
+ :png
470
+ when ".jpg", ".jpeg"
471
+ :jpeg
472
+ else
473
+ raise ArgumentError,
474
+ "Unable to infer file type from filename: %p" % filename
475
+ end
476
+ end
477
+
478
+ private def save_html(filename, title:, element_id: nil)
451
479
  html = <<~HTML
452
480
  <!DOCTYPE html>
453
481
  <html>
@@ -464,30 +492,50 @@ module Charty
464
492
  </body>
465
493
  </html>
466
494
  HTML
495
+
496
+ element_id = SecureRandom.uuid if element_id.nil?
497
+
467
498
  html %= {
468
499
  title: title || default_html_title,
469
- id: SecureRandom.uuid,
500
+ id: element_id,
470
501
  data: JSON.dump(@traces),
471
502
  layout: JSON.dump(@layout)
472
503
  }
473
504
  File.write(filename, html)
474
- nil
475
505
  end
476
506
 
477
507
  private def default_html_title
478
508
  "Charty plot"
479
509
  end
480
510
 
481
- def show
482
- unless defined?(IRuby)
483
- raise NotImplementedError,
484
- "Plotly backend outside of IRuby is not supported"
511
+ def render(element_id: nil, format: nil, notebook: false)
512
+ case format
513
+ when :html, "html"
514
+ format = "text/html"
515
+ when :png, "png"
516
+ format = "image/png"
517
+ when :jpeg, "jpeg"
518
+ format = "image/jpeg"
485
519
  end
486
520
 
487
- IRubyOutput.prepare
521
+ case format
522
+ when "text/html", nil
523
+ # render html after this case cause
524
+ when "image/png", "image/jpeg"
525
+ image_data = render_image(format, element_id: element_id, notebook: false)
526
+ if notebook
527
+ return [format, image_data]
528
+ else
529
+ return image_data
530
+ end
531
+ else
532
+ raise ArgumentError,
533
+ "Unsupported mime type to render: %p" % format
534
+ end
488
535
 
536
+ # TODO: size should be customizable
489
537
  html = <<~HTML
490
- <div id="%{id}" style="width: 100%%; height:100%%;"></div>
538
+ <div id="%{id}" style="width: 100%%; height:525px;"></div>
491
539
  <script type="text/javascript">
492
540
  requirejs(["plotly"], function (Plotly) {
493
541
  Plotly.newPlot("%{id}", %{data}, %{layout});
@@ -495,13 +543,46 @@ module Charty
495
543
  </script>
496
544
  HTML
497
545
 
546
+ element_id = SecureRandom.uuid if element_id.nil?
547
+
498
548
  html %= {
499
- id: SecureRandom.uuid,
549
+ id: element_id,
500
550
  data: JSON.dump(@traces),
501
551
  layout: JSON.dump(@layout)
502
552
  }
503
- IRuby.display(html, mime: "text/html")
504
- nil
553
+
554
+ if notebook
555
+ IRubyOutput.prepare
556
+ ["text/html", html]
557
+ else
558
+ html
559
+ end
560
+ end
561
+
562
+ private def render_image(format=nil, filename: nil, element_id: nil, notebook: false,
563
+ title: nil, width: nil, height: nil)
564
+ format = "image/png" if format.nil?
565
+ case format
566
+ when :png, "png", :jpeg, "jpeg"
567
+ image_type = format.to_s
568
+ when "image/png", "image/jpeg"
569
+ image_type = format.split("/").last
570
+ else
571
+ raise ArgumentError,
572
+ "Unsupported mime type to render image: %p" % format
573
+ end
574
+
575
+ height = 525 if height.nil?
576
+ width = (height * Math.sqrt(2)).to_i if width.nil?
577
+ title = "Charty plot" if title.nil?
578
+
579
+ element_id = SecureRandom.uuid if element_id.nil?
580
+ element_id = "charty-plotly-#{element_id}"
581
+ Dir.mktmpdir do |tmpdir|
582
+ html_filename = File.join(tmpdir, "%s.html" % element_id)
583
+ save_html(html_filename, title: title, element_id: element_id)
584
+ return self.class.render_image(html_filename, filename, image_type, element_id, width, height)
585
+ end
505
586
  end
506
587
 
507
588
  module IRubyOutput
@@ -544,6 +625,61 @@ module Charty
544
625
  END
545
626
  end
546
627
  end
628
+
629
+ @playwright_fiber = nil
630
+
631
+ def self.ensure_playwright
632
+ if @playwright_fiber.nil?
633
+ begin
634
+ require "playwright"
635
+ rescue LoadError
636
+ $stderr.puts "ERROR: You need to install playwright and playwright-ruby-client before using Plotly renderer"
637
+ raise
638
+ end
639
+
640
+ @playwright_fiber = Fiber.new do
641
+ playwright_cli_executable_path = ENV.fetch("PLAYWRIGHT_CLI_EXECUTABLE_PATH", "npx playwright")
642
+ Playwright.create(playwright_cli_executable_path: playwright_cli_executable_path) do |playwright|
643
+ playwright.chromium.launch(headless: true) do |browser|
644
+ request = Fiber.yield
645
+ loop do
646
+ result = nil
647
+ case request.shift
648
+ when :finish
649
+ break
650
+ when :render
651
+ input, output, format, element_id, width, height = request
652
+
653
+ page = browser.new_page
654
+ page.set_viewport_size(width: width, height: height)
655
+ page.goto("file://#{input}")
656
+ element = page.query_selector("\##{element_id}")
657
+
658
+ kwargs = {type: format}
659
+ kwargs[:path] = output unless output.nil?
660
+ result = element.screenshot(**kwargs)
661
+ end
662
+ request = Fiber.yield(result)
663
+ end
664
+ end
665
+ end
666
+ end
667
+ @playwright_fiber.resume
668
+ end
669
+ end
670
+
671
+ def self.terminate_playwright
672
+ return if @playwright_fiber.nil?
673
+
674
+ @playwright_fiber.resume([:finish])
675
+ end
676
+
677
+ at_exit { terminate_playwright }
678
+
679
+ def self.render_image(input, output, format, element_id, width, height)
680
+ ensure_playwright if @playwright_fiber.nil?
681
+ @playwright_fiber.resume([:render, input, output, format.to_s, element_id, width, height])
682
+ end
547
683
  end
548
684
  end
549
685
  end
@@ -41,7 +41,7 @@ module Charty
41
41
  @pyplot.show
42
42
  end
43
43
 
44
- def render(context, filename)
44
+ def old_style_render(context, filename)
45
45
  plot(@pyplot, context)
46
46
  if filename
47
47
  FileUtils.mkdir_p(File.dirname(filename))
@@ -50,7 +50,7 @@ module Charty
50
50
  @pyplot.show
51
51
  end
52
52
 
53
- def save(context, filename, finish: true)
53
+ def old_style_save(context, filename, finish: true)
54
54
  plot(context)
55
55
  if filename
56
56
  FileUtils.mkdir_p(File.dirname(filename))
@@ -374,7 +374,7 @@ module Charty
374
374
  brief_ticks = RELATIONAL_PLOT_LEGEND_BRIEF_TICKS
375
375
  verbosity = :auto if verbosity == true
376
376
 
377
- legend_titles = [:color, :size, :style].filter_map {|v| variables[v] }
377
+ legend_titles = Util.filter_map([:color, :size, :style]) {|v| variables[v] }
378
378
  legend_title = legend_titles.pop if legend_titles.length == 1
379
379
 
380
380
  legend_kwargs = {}
@@ -484,7 +484,7 @@ module Charty
484
484
  legend_kwargs.each do |key, kw|
485
485
  _, label = key
486
486
  kw[:color] ||= ".2"
487
- use_kw = legend_attributes.filter_map {|attr|
487
+ use_kw = Util.filter_map(legend_attributes) {|attr|
488
488
  [attr, kw[attr]] if kw.key?(attr)
489
489
  }.to_h
490
490
  use_kw[:visible] = kw[:visible] if kw.key?(:visible)
@@ -592,6 +592,10 @@ module Charty
592
592
  @pyplot.gca.legend(loc: loc, title: title)
593
593
  end
594
594
 
595
+ def render(notebook: false)
596
+ show
597
+ end
598
+
595
599
  def show
596
600
  @pyplot.show
597
601
  end
@@ -33,7 +33,7 @@ module Charty
33
33
  @plot.show
34
34
  end
35
35
 
36
- def render(context, filename="")
36
+ def old_style_render(context, filename="")
37
37
  FileUtils.mkdir_p(File.dirname(filename))
38
38
  plot(@plot, context).write(filename)
39
39
  end
@@ -237,11 +237,11 @@ module Charty
237
237
  end
238
238
 
239
239
  def render(filename=nil)
240
- @backend.render(self, filename)
240
+ @backend.old_style_render(self, filename)
241
241
  end
242
242
 
243
243
  def save(filename=nil, **kw)
244
- @backend.save(self, filename, **kw)
244
+ @backend.old_style_save(self, filename, **kw)
245
245
  end
246
246
 
247
247
  def apply(backend)
@@ -14,6 +14,10 @@ module Charty
14
14
  attr_reader :data, :x, :y, :color
15
15
  attr_reader :color_order, :key_color, :palette
16
16
 
17
+ def inspect
18
+ "#<#{self.class}:0x%016x>" % self.object_id
19
+ end
20
+
17
21
  def data=(data)
18
22
  @data = case data
19
23
  when nil, Charty::Table
@@ -147,9 +151,32 @@ module Charty
147
151
  ary
148
152
  end
149
153
 
154
+ def save(filename, **kwargs)
155
+ backend = Backends.current
156
+ backend.begin_figure
157
+ render_plot(backend, **kwargs)
158
+ backend.save(filename, **kwargs)
159
+ end
160
+
161
+ def render(notebook: false, **kwargs)
162
+ backend = Backends.current
163
+ backend.begin_figure
164
+ render_plot(backend, notebook: notebook, **kwargs)
165
+ backend.render(notebook: notebook, **kwargs)
166
+ end
167
+
168
+ private def render_plot(*, **)
169
+ raise NotImplementedError,
170
+ "subclass must implement #{__method__}"
171
+ end
172
+
150
173
  def to_iruby
151
- result = render
152
- ["text/html", result] if result
174
+ render(notebook: iruby_notebook?)
175
+ end
176
+
177
+ private def iruby_notebook?
178
+ return false unless defined?(IRuby)
179
+ true # TODO: Check the server is notebook or not
153
180
  end
154
181
  end
155
182
  end
@@ -42,25 +42,10 @@ module Charty
42
42
  @cap_size = check_number(cap_size, :cap_size, allow_nil: true)
43
43
  end
44
44
 
45
- def render
46
- backend = Backends.current
47
- backend.begin_figure
45
+ private def render_plot(backend, **)
48
46
  draw_bars(backend)
49
47
  annotate_axes(backend)
50
48
  backend.invert_yaxis if orient == :h
51
- backend.show
52
- end
53
-
54
- # TODO:
55
- # - Should infer mime type from file's extname
56
- # - Should check backend's supported mime type before begin_figure
57
- def save(filename, **opts)
58
- backend = Backends.current
59
- backend.begin_figure
60
- draw_bars(backend)
61
- annotate_axes(backend)
62
- backend.invert_yaxis if orient == :h
63
- backend.save(filename, **opts)
64
49
  end
65
50
 
66
51
  private def draw_bars(backend)
@@ -27,25 +27,10 @@ module Charty
27
27
  @whisker = check_number(val, :whisker, allow_nil: true)
28
28
  end
29
29
 
30
- def render
31
- backend = Backends.current
32
- backend.begin_figure
30
+ private def render_plot(backend, **)
33
31
  draw_box_plot(backend)
34
32
  annotate_axes(backend)
35
33
  backend.invert_yaxis if orient == :h
36
- backend.show
37
- end
38
-
39
- # TODO:
40
- # - Should infer mime type from file's extname
41
- # - Should check backend's supported mime type before begin_figure
42
- def save(filename, **opts)
43
- backend = Backends.current
44
- backend.begin_figure
45
- draw_box_plot(backend)
46
- annotate_axes(backend)
47
- backend.invert_yaxis if orient == :h
48
- backend.save(filename, **opts)
49
34
  end
50
35
 
51
36
  private def draw_box_plot(backend)
@@ -47,20 +47,9 @@ module Charty
47
47
  @line_width = check_color(val, :edge_color, allow_nil: true)
48
48
  end
49
49
 
50
- def render
51
- backend = Backends.current
52
- backend.begin_figure
50
+ private def render_plot(backend, **)
53
51
  draw_points(backend)
54
52
  annotate_axes(backend)
55
- backend.show
56
- end
57
-
58
- def save(filename, **opts)
59
- backend = Backends.current
60
- backend.begin_figure
61
- draw_points(backend)
62
- annotate_axes(backend)
63
- backend.save(filename, **opts)
64
53
  end
65
54
 
66
55
  private def draw_points(backend)
@@ -105,7 +94,7 @@ module Charty
105
94
  verbosity = legend
106
95
  verbosity = :auto if verbosity == true
107
96
 
108
- titles = [:color, :size, :style].filter_map do |v|
97
+ titles = Util.filter_map([:color, :size, :style]) do |v|
109
98
  variables[v] if variables.key?(v)
110
99
  end
111
100
  legend_title = titles.length == 1 ? titles[0] : ""
@@ -88,7 +88,7 @@ module Charty
88
88
 
89
89
  private def check_data(arrays, columns, index)
90
90
  # NOTE: After Ruby 2.7, we can write the following code by filter_map:
91
- # indexes = arrays.filter_map {|ary| ary.index if ary.is_a?(Charty::Vector) }
91
+ # indexes = Util.filter_map(arrays) {|ary| ary.index if ary.is_a?(Charty::Vector) }
92
92
  indexes = []
93
93
  arrays.each do |array|
94
94
  index = case array
@@ -0,0 +1,20 @@
1
+ module Charty
2
+ module Util
3
+ if [].respond_to?(:filter_map)
4
+ module_function def filter_map(enum, &block)
5
+ enum.filter_map(&block)
6
+ end
7
+ else
8
+ module_function def filter_map(enum, &block)
9
+ enum.inject([]) do |acc, x|
10
+ y = block.call(x)
11
+ if y
12
+ acc.push(y)
13
+ else
14
+ acc
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,5 +1,5 @@
1
1
  module Charty
2
- VERSION = "0.2.4"
2
+ VERSION = "0.2.5"
3
3
 
4
4
  module Version
5
5
  numbers, TAG = VERSION.split("-")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: charty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - youchan
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2021-05-19 00:00:00.000000000 Z
13
+ date: 2021-05-28 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: red-colors
@@ -110,6 +110,20 @@ dependencies:
110
110
  - - ">="
111
111
  - !ruby/object:Gem::Version
112
112
  version: '0'
113
+ - !ruby/object:Gem::Dependency
114
+ name: matrix
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ type: :development
121
+ prerelease: false
122
+ version_requirements: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
113
127
  - !ruby/object:Gem::Dependency
114
128
  name: activerecord
115
129
  requirement: !ruby/object:Gem::Requirement
@@ -138,6 +152,34 @@ dependencies:
138
152
  - - ">="
139
153
  - !ruby/object:Gem::Version
140
154
  version: '0'
155
+ - !ruby/object:Gem::Dependency
156
+ name: playwright-ruby-client
157
+ requirement: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ type: :development
163
+ prerelease: false
164
+ version_requirements: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ - !ruby/object:Gem::Dependency
170
+ name: iruby
171
+ requirement: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - ">="
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ type: :development
177
+ prerelease: false
178
+ version_requirements: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
141
183
  description: Visualizing your data in a simple way.
142
184
  email:
143
185
  - youchan01@gmail.com
@@ -248,6 +290,7 @@ files:
248
290
  - lib/charty/table_adapters/narray_adapter.rb
249
291
  - lib/charty/table_adapters/nmatrix_adapter.rb
250
292
  - lib/charty/table_adapters/pandas_adapter.rb
293
+ - lib/charty/util.rb
251
294
  - lib/charty/vector.rb
252
295
  - lib/charty/vector_adapters.rb
253
296
  - lib/charty/vector_adapters/array_adapter.rb