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 +4 -4
- data/README.md +63 -15
- data/charty.gemspec +3 -0
- data/lib/charty.rb +1 -0
- data/lib/charty/backends/bokeh.rb +2 -2
- data/lib/charty/backends/google_charts.rb +1 -1
- data/lib/charty/backends/gruff.rb +1 -1
- data/lib/charty/backends/plotly.rb +149 -13
- data/lib/charty/backends/pyplot.rb +8 -4
- data/lib/charty/backends/rubyplot.rb +1 -1
- data/lib/charty/plotter.rb +2 -2
- data/lib/charty/plotters/abstract_plotter.rb +29 -2
- data/lib/charty/plotters/bar_plotter.rb +1 -16
- data/lib/charty/plotters/box_plotter.rb +1 -16
- data/lib/charty/plotters/scatter_plotter.rb +2 -13
- data/lib/charty/table_adapters/hash_adapter.rb +1 -1
- data/lib/charty/util.rb +20 -0
- data/lib/charty/version.rb +1 -1
- metadata +45 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4cf18b5e31bf29099d3d9386b8b022e38013bba339c129a0292af39983e2bccb
|
4
|
+
data.tar.gz: 4eb934400a4fc7c60354bf7f7f31e33d4be8cdbdeafb1d47762264d94c8c5a2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
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
|
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
|
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
|
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
|
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
@@ -17,13 +17,13 @@ module Charty
|
|
17
17
|
@series = series
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
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
|
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
|
@@ -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
|
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:
|
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
|
482
|
-
|
483
|
-
|
484
|
-
|
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
|
-
|
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:
|
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:
|
549
|
+
id: element_id,
|
500
550
|
data: JSON.dump(@traces),
|
501
551
|
layout: JSON.dump(@layout)
|
502
552
|
}
|
503
|
-
|
504
|
-
|
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
|
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
|
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]
|
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 =
|
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
|
data/lib/charty/plotter.rb
CHANGED
@@ -237,11 +237,11 @@ module Charty
|
|
237
237
|
end
|
238
238
|
|
239
239
|
def render(filename=nil)
|
240
|
-
@backend.
|
240
|
+
@backend.old_style_render(self, filename)
|
241
241
|
end
|
242
242
|
|
243
243
|
def save(filename=nil, **kw)
|
244
|
-
@backend.
|
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
|
-
|
152
|
-
|
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
|
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
|
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
|
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]
|
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 =
|
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
|
data/lib/charty/util.rb
ADDED
@@ -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
|
data/lib/charty/version.rb
CHANGED
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
|
+
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-
|
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
|