charty 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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