charty 0.2.6 → 0.2.7
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 +4 -4
- data/charty.gemspec +1 -1
- data/lib/charty.rb +2 -0
- data/lib/charty/backends/plotly.rb +92 -20
- data/lib/charty/backends/plotly_helpers/html_renderer.rb +203 -0
- data/lib/charty/backends/plotly_helpers/notebook_renderer.rb +86 -0
- data/lib/charty/backends/plotly_helpers/plotly_renderer.rb +121 -0
- data/lib/charty/backends/pyplot.rb +1 -0
- data/lib/charty/cache_dir.rb +27 -0
- data/lib/charty/iruby_helper.rb +18 -0
- data/lib/charty/plot_methods.rb +40 -0
- data/lib/charty/plotters.rb +3 -0
- data/lib/charty/plotters/abstract_plotter.rb +16 -8
- data/lib/charty/plotters/distribution_plotter.rb +143 -0
- data/lib/charty/plotters/histogram_plotter.rb +182 -0
- data/lib/charty/statistics.rb +9 -0
- data/lib/charty/version.rb +1 -1
- metadata +23 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e39148cc6e6fd7916cdfbe5dacda3bab8f95068cbe3ceb4dff673d9688487d0
|
4
|
+
data.tar.gz: 5743d17f30055707fe39004f99bb30fb2cb10b164dbf9b222f000068cc800708
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 562b312fb4ca59995d19930f404d6162f432f7731752e5a9016132b6b2696a507f6d7523d5eb6e5bc0141273726d2608b1351b497f2c200cec0fda5204e4fc19
|
7
|
+
data.tar.gz: 213f83930bc1bd809ae98af41d0608793c356b234064e9f2ec79b96e76b1c301a331fc44c9c04fc0f3f188f65b780b59af449dca206f68ec310cb121b6bd0e41
|
data/charty.gemspec
CHANGED
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.require_paths = ["lib"]
|
28
28
|
|
29
29
|
spec.add_dependency "red-colors", ">= 0.3.0"
|
30
|
+
spec.add_dependency "red-datasets", ">= 0.1.2"
|
30
31
|
spec.add_dependency "red-palette", ">= 0.5.0"
|
31
32
|
|
32
33
|
spec.add_dependency "matplotlib", ">= 1.2.0"
|
@@ -36,7 +37,6 @@ Gem::Specification.new do |spec|
|
|
36
37
|
spec.add_development_dependency "bundler", ">= 1.16"
|
37
38
|
spec.add_development_dependency "rake"
|
38
39
|
spec.add_development_dependency "test-unit"
|
39
|
-
spec.add_development_dependency "red-datasets", ">= 0.1.2"
|
40
40
|
spec.add_development_dependency "daru"
|
41
41
|
spec.add_development_dependency "matrix" # need for daru on Ruby > 3.0
|
42
42
|
spec.add_development_dependency "activerecord"
|
data/lib/charty.rb
CHANGED
@@ -3,7 +3,9 @@ require_relative "charty/version"
|
|
3
3
|
require "colors"
|
4
4
|
require "palette"
|
5
5
|
|
6
|
+
require_relative "charty/cache_dir"
|
6
7
|
require_relative "charty/util"
|
8
|
+
require_relative "charty/iruby_helper"
|
7
9
|
require_relative "charty/dash_pattern_generator"
|
8
10
|
require_relative "charty/backends"
|
9
11
|
require_relative "charty/backend_methods"
|
@@ -2,6 +2,10 @@ require "json"
|
|
2
2
|
require "securerandom"
|
3
3
|
require "tmpdir"
|
4
4
|
|
5
|
+
require_relative "plotly_helpers/html_renderer"
|
6
|
+
require_relative "plotly_helpers/notebook_renderer"
|
7
|
+
require_relative "plotly_helpers/plotly_renderer"
|
8
|
+
|
5
9
|
module Charty
|
6
10
|
module Backends
|
7
11
|
class Plotly
|
@@ -558,6 +562,52 @@ module Charty
|
|
558
562
|
end
|
559
563
|
end
|
560
564
|
|
565
|
+
PLOTLY_HISTNORM = {
|
566
|
+
count: "".freeze,
|
567
|
+
frequency: "density".freeze,
|
568
|
+
density: "probability density".freeze,
|
569
|
+
probability: "probability".freeze
|
570
|
+
}.freeze
|
571
|
+
|
572
|
+
def univariate_histogram(data, name, variable_name, stat,
|
573
|
+
bin_start, bin_end, bin_size, alpha,
|
574
|
+
color, color_mapper)
|
575
|
+
orientation = case variable_name
|
576
|
+
when :x
|
577
|
+
:v
|
578
|
+
else
|
579
|
+
:h
|
580
|
+
end
|
581
|
+
trace = {
|
582
|
+
type: "histogram",
|
583
|
+
name: name.to_s,
|
584
|
+
variable_name => data.to_a,
|
585
|
+
orientation: orientation,
|
586
|
+
histnorm: PLOTLY_HISTNORM[stat],
|
587
|
+
"#{variable_name}bins": {
|
588
|
+
start: bin_start,
|
589
|
+
end: bin_end,
|
590
|
+
size: bin_size
|
591
|
+
},
|
592
|
+
opacity: alpha
|
593
|
+
}
|
594
|
+
|
595
|
+
if color
|
596
|
+
trace[:marker] = {
|
597
|
+
color: color_mapper[color].to_rgb.to_hex_string
|
598
|
+
}
|
599
|
+
end
|
600
|
+
|
601
|
+
@traces << trace
|
602
|
+
|
603
|
+
@layout[:bargap] = 0.05
|
604
|
+
|
605
|
+
if @traces.length > 1
|
606
|
+
@layout[:barmode] = "overlay"
|
607
|
+
@layout[:showlegend] = true
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
561
611
|
def set_xlabel(label)
|
562
612
|
@layout[:xaxis] ||= {}
|
563
613
|
@layout[:xaxis][:title] = label
|
@@ -699,7 +749,7 @@ module Charty
|
|
699
749
|
|
700
750
|
def render(element_id: nil, format: nil, notebook: false)
|
701
751
|
case format
|
702
|
-
when :html, "html"
|
752
|
+
when :html, "html", nil
|
703
753
|
format = "text/html"
|
704
754
|
when :png, "png"
|
705
755
|
format = "image/png"
|
@@ -708,7 +758,7 @@ module Charty
|
|
708
758
|
end
|
709
759
|
|
710
760
|
case format
|
711
|
-
when "text/html"
|
761
|
+
when "text/html"
|
712
762
|
# render html after this case cause
|
713
763
|
when "image/png", "image/jpeg"
|
714
764
|
image_data = render_image(format, element_id: element_id, notebook: false)
|
@@ -722,32 +772,54 @@ module Charty
|
|
722
772
|
"Unsupported mime type to render: %p" % format
|
723
773
|
end
|
724
774
|
|
725
|
-
# TODO: size should be customizable
|
726
|
-
html = <<~HTML
|
727
|
-
<div id="%{id}" style="width: 100%%; height:525px;"></div>
|
728
|
-
<script type="text/javascript">
|
729
|
-
requirejs(["plotly"], function (Plotly) {
|
730
|
-
Plotly.newPlot("%{id}", %{data}, %{layout});
|
731
|
-
});
|
732
|
-
</script>
|
733
|
-
HTML
|
734
|
-
|
735
775
|
element_id = SecureRandom.uuid if element_id.nil?
|
736
776
|
|
737
|
-
|
738
|
-
|
739
|
-
data: JSON.dump(@traces),
|
740
|
-
layout: JSON.dump(@layout)
|
741
|
-
}
|
742
|
-
|
777
|
+
renderer = PlotlyHelpers::HtmlRenderer.new(full_html: !notebook)
|
778
|
+
html = renderer.render({data: @traces, layout: @layout}, element_id: element_id)
|
743
779
|
if notebook
|
744
|
-
|
745
|
-
["text/html", html]
|
780
|
+
[format, html]
|
746
781
|
else
|
747
782
|
html
|
748
783
|
end
|
749
784
|
end
|
750
785
|
|
786
|
+
def render_mimebundle(include: [], exclude: [])
|
787
|
+
types = case
|
788
|
+
when IRubyHelper.vscode?,
|
789
|
+
IRubyHelper.nteract?
|
790
|
+
[:plotly_mimetype]
|
791
|
+
else
|
792
|
+
[:plotly_mimetype, :notebook]
|
793
|
+
end
|
794
|
+
bundle = Util.filter_map(types) { |type|
|
795
|
+
case type
|
796
|
+
when :plotly_mimetype
|
797
|
+
render_plotly_mimetype_bundle
|
798
|
+
when :notebook
|
799
|
+
render_notebook_bundle
|
800
|
+
end
|
801
|
+
}.to_h
|
802
|
+
bundle
|
803
|
+
end
|
804
|
+
|
805
|
+
private def render_plotly_mimetype_bundle
|
806
|
+
renderer = PlotlyHelpers::PlotlyRenderer.new
|
807
|
+
obj = renderer.render({data: @traces, layout: @layout})
|
808
|
+
[ "application/vnd.plotly.v1+json", obj ]
|
809
|
+
end
|
810
|
+
|
811
|
+
private def render_notebook_bundle
|
812
|
+
renderer = self.class.notebook_renderer
|
813
|
+
renderer.activate
|
814
|
+
html = renderer.render({data: @traces, layout: @layout})
|
815
|
+
[ "text/html", html ]
|
816
|
+
end
|
817
|
+
|
818
|
+
# for new APIs
|
819
|
+
def self.notebook_renderer
|
820
|
+
@notebook_renderer ||= PlotlyHelpers::NotebookRenderer.new
|
821
|
+
end
|
822
|
+
|
751
823
|
private def render_image(format=nil, filename: nil, element_id: nil, notebook: false,
|
752
824
|
title: nil, width: nil, height: nil)
|
753
825
|
format = "image/png" if format.nil?
|
@@ -0,0 +1,203 @@
|
|
1
|
+
require "datasets/downloader"
|
2
|
+
require "json"
|
3
|
+
require "securerandom"
|
4
|
+
|
5
|
+
module Charty
|
6
|
+
module Backends
|
7
|
+
module PlotlyHelpers
|
8
|
+
class HtmlRenderer
|
9
|
+
def initialize(use_cdn: true,
|
10
|
+
full_html: false,
|
11
|
+
requirejs: true)
|
12
|
+
@use_cdn = use_cdn
|
13
|
+
@full_html = full_html
|
14
|
+
@requirejs = requirejs
|
15
|
+
end
|
16
|
+
|
17
|
+
PLOTLY_URL = "https://plot.ly".freeze
|
18
|
+
PLOTLY_LATEST_CDN_URL = "https://cdn.plot.ly/plotly-latest.min.js".freeze
|
19
|
+
MATHJAX_CDN_URL = ("https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js").freeze
|
20
|
+
|
21
|
+
DEFAULT_WIDTH = "100%".freeze
|
22
|
+
DEFAULT_HEIGHT = 525
|
23
|
+
|
24
|
+
def render(figure, element_id: nil, post_script: nil)
|
25
|
+
element_id = SecureRandom.uuid if element_id.nil?
|
26
|
+
plotly_html_div = build_plotly_html_div(figure, element_id, post_script)
|
27
|
+
|
28
|
+
if @full_html
|
29
|
+
<<~END_HTML % {div: plotly_html_div}
|
30
|
+
<!DOCTYPE html>
|
31
|
+
<html>
|
32
|
+
<head><meta charset="utf-8" /></head>
|
33
|
+
<body>
|
34
|
+
%{div}
|
35
|
+
</body>
|
36
|
+
</html>
|
37
|
+
END_HTML
|
38
|
+
else
|
39
|
+
plotly_html_div
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private def build_plotly_html_div(figure, element_id, post_script)
|
44
|
+
layout = figure.fetch(:layout, {})
|
45
|
+
|
46
|
+
json_data = JSON.dump(figure.fetch(:data, []))
|
47
|
+
json_layout = JSON.dump(layout)
|
48
|
+
json_frames = JSON.dump(figure[:frames]) if figure.key?(:frames)
|
49
|
+
|
50
|
+
# TODO: config and responsive support
|
51
|
+
|
52
|
+
template = layout.fetch(:template, {}).fetch(:layout, {})
|
53
|
+
div_width = layout.fetch(:width, template.fetch(:width, DEFAULT_WIDTH))
|
54
|
+
div_height = layout.fetch(:height, template.fetch(:height, DEFAULT_HEIGHT))
|
55
|
+
|
56
|
+
div_width = "#{div_width}px" if Float(div_width, exception: false)
|
57
|
+
div_height = "#{div_height}px" if Float(div_height, exception: false)
|
58
|
+
|
59
|
+
# TODO: showLink and showSendToCloud support
|
60
|
+
base_url_line = "window.PLOTLYENV.BASE_URL = '%{url}';" % {url: PLOTLY_URL}
|
61
|
+
|
62
|
+
## build script body
|
63
|
+
|
64
|
+
# TODO: post_script support
|
65
|
+
then_post_script = ""
|
66
|
+
if post_script
|
67
|
+
ary = Array.try_convert(post_script)
|
68
|
+
post_script = ary || [post_script]
|
69
|
+
post_script.each do |ps|
|
70
|
+
next if ps.nil?
|
71
|
+
then_post_script << '.then(function(){ %{post_script} })' % {
|
72
|
+
post_script: ps % {plot_id: element_id}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
then_addframes = ""
|
78
|
+
then_animate = ""
|
79
|
+
if json_frames
|
80
|
+
then_addframes = <<~END_ADDFRAMES % {id: element_id, frames: json_frames}
|
81
|
+
.then(function(){
|
82
|
+
Plotly.addFrames('%{id}', {frames});
|
83
|
+
})
|
84
|
+
END_ADDFRAMES
|
85
|
+
|
86
|
+
# TODO: auto_play support
|
87
|
+
end
|
88
|
+
|
89
|
+
json_config = JSON.dump({}) # TODO: config support
|
90
|
+
|
91
|
+
script = <<~END_SCRIPT
|
92
|
+
if (document.getElementById("%{id}")) {
|
93
|
+
Plotly.newPlot("%{id}", %{data}, %{layout}, %{config})%{then_addframes}%{then_animate}%{then_post_script};
|
94
|
+
}
|
95
|
+
END_SCRIPT
|
96
|
+
script = script % {
|
97
|
+
id: element_id,
|
98
|
+
data: json_data,
|
99
|
+
layout: json_layout,
|
100
|
+
config: json_config,
|
101
|
+
then_addframes: then_addframes,
|
102
|
+
then_animate: then_animate,
|
103
|
+
then_post_script: then_post_script
|
104
|
+
}
|
105
|
+
|
106
|
+
## Handle loading/initializing plotlyjs
|
107
|
+
|
108
|
+
case
|
109
|
+
when @requirejs
|
110
|
+
include_plotlyjs = :require
|
111
|
+
include_mathjax = false
|
112
|
+
when @use_cdn
|
113
|
+
include_plotlyjs = :cdn
|
114
|
+
include_mathjax = :cdn
|
115
|
+
else
|
116
|
+
include_plotlyjs = true
|
117
|
+
include_mathjax = :cdn
|
118
|
+
end
|
119
|
+
|
120
|
+
case include_plotlyjs
|
121
|
+
when :require
|
122
|
+
require_start = 'require(["plotly"], function (Plotly) {'
|
123
|
+
require_end = '});'
|
124
|
+
when :cdn
|
125
|
+
load_plotlyjs = <<~END_LOAD_PLOTLYJS % {win_config: window_plotly_config, url: PLOTLY_LATEST_CDN_URL}
|
126
|
+
%{win_config}
|
127
|
+
<script src="%{url}"></script>
|
128
|
+
END_LOAD_PLOTLYJS
|
129
|
+
when true
|
130
|
+
load_plotlyjs = <<~END_LOAD_PLOTLYJS % {win_config: window_plotly_config, script: get_plotlyjs}
|
131
|
+
%{win_config}
|
132
|
+
<script type="text/javascript">%{script}</script>
|
133
|
+
END_LOAD_PLOTLYJS
|
134
|
+
end
|
135
|
+
|
136
|
+
## Handle loading/initializing MathJax
|
137
|
+
|
138
|
+
mathjax_tmplate = %Q[<script src="%{url}?config=TeX-AMS-MML_SVG"></script>]
|
139
|
+
case include_mathjax
|
140
|
+
when :cdn
|
141
|
+
mathjax_script = mathjax_tmplate % {url: MATHJAX_CDN_URL}
|
142
|
+
mathjax_script << <<~END_SCRIPT % {mathjax_config: mathjax_config}
|
143
|
+
<script type="text/javascript">%{mathjax_config}</script>
|
144
|
+
END_SCRIPT
|
145
|
+
else
|
146
|
+
mathjax_script = ""
|
147
|
+
end
|
148
|
+
|
149
|
+
div_template = <<~END_DIV
|
150
|
+
<div>
|
151
|
+
%{mathjax_script}
|
152
|
+
%{load_plotlyjs}
|
153
|
+
<div id="%{id}" class="plotly-graph-div" style="height: %{height}; width: %{width};"></div>
|
154
|
+
<script type="text/javascript">
|
155
|
+
%{require_start}
|
156
|
+
window.PLOTLYENV = window.PLOTLYENV || {};
|
157
|
+
%{base_url_line}
|
158
|
+
%{script}
|
159
|
+
%{require_end}
|
160
|
+
</script>
|
161
|
+
</div>
|
162
|
+
END_DIV
|
163
|
+
|
164
|
+
plotly_html_div = div_template % {
|
165
|
+
mathjax_script: mathjax_script,
|
166
|
+
load_plotlyjs: load_plotlyjs,
|
167
|
+
id: element_id,
|
168
|
+
height: div_height,
|
169
|
+
width: div_width,
|
170
|
+
require_start: require_start,
|
171
|
+
base_url_line: base_url_line,
|
172
|
+
script: script,
|
173
|
+
require_end: require_end
|
174
|
+
}
|
175
|
+
plotly_html_div.strip!
|
176
|
+
|
177
|
+
plotly_html_div
|
178
|
+
end
|
179
|
+
|
180
|
+
private def window_plotly_config
|
181
|
+
%Q(window.PlotlyConfig = {MathJaxConfig: 'local'};)
|
182
|
+
end
|
183
|
+
|
184
|
+
private def mathjax_config
|
185
|
+
%Q(if (window.MathJax) { MathJax.Hub.Config({SVG: {font: "STIX-Web"}}); })
|
186
|
+
end
|
187
|
+
|
188
|
+
private def get_plotlyjs
|
189
|
+
cache_path = CacheDir.path("plotly.min.js")
|
190
|
+
unless cache_path.exist?
|
191
|
+
download_plotlyjs(cache_path)
|
192
|
+
end
|
193
|
+
cache_path.read
|
194
|
+
end
|
195
|
+
|
196
|
+
private def download_plotlyjs(output_path)
|
197
|
+
downloader = Datasets::Downloader.new(PLOTLY_LATEST_CDN_URL)
|
198
|
+
downloader.download(output_path)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Charty
|
2
|
+
module Backends
|
3
|
+
module PlotlyHelpers
|
4
|
+
class NotebookRenderer < HtmlRenderer
|
5
|
+
def initialize(use_cdn: false)
|
6
|
+
super(use_cdn: use_cdn, full_html: false, requirejs: true)
|
7
|
+
@initialized = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def activate()
|
11
|
+
return if @initialized
|
12
|
+
|
13
|
+
unless IRubyHelper.iruby_notebook?
|
14
|
+
raise "IRuby is unavailable"
|
15
|
+
end
|
16
|
+
|
17
|
+
if @use_cdn
|
18
|
+
script = <<~END_SCRIPT % {win_config: window_plotly_config, mathjax_config: mathjax_config}
|
19
|
+
<script type="text/javascript">
|
20
|
+
%{win_config}
|
21
|
+
%{mathjax_config}
|
22
|
+
if (typeof require !== 'undefined') {
|
23
|
+
require.undef("plotly");
|
24
|
+
requirejs.config({
|
25
|
+
paths: {
|
26
|
+
'plotly': ['https://cdn.plot.ly/plotly-latest.min']
|
27
|
+
}
|
28
|
+
});
|
29
|
+
require(['plotly'], function (Plotly) {
|
30
|
+
window._Plotly = Plotly;
|
31
|
+
});
|
32
|
+
}
|
33
|
+
</script>
|
34
|
+
END_SCRIPT
|
35
|
+
else
|
36
|
+
script = <<~END_SCRIPT % {script: get_plotlyjs, win_config: window_plotly_config, mathjax_config: mathjax_config}
|
37
|
+
<script type="text/javascript">
|
38
|
+
%{win_config}
|
39
|
+
%{mathjax_config}
|
40
|
+
if (typeof require !== 'undefined') {
|
41
|
+
require.undef("plotly");
|
42
|
+
define('plotly', function (require, exports, module) {
|
43
|
+
%{script}
|
44
|
+
});
|
45
|
+
require(['plotly'], function (Plotly) {
|
46
|
+
window._Plotly = Plotly;
|
47
|
+
});
|
48
|
+
}
|
49
|
+
</script>
|
50
|
+
END_SCRIPT
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def render(figure, element_id: nil, post_script: nil)
|
55
|
+
ary = Array.try_convert(post_script)
|
56
|
+
post_script = ary || [post_script]
|
57
|
+
post_script.unshift(<<~END_POST_SCRIPT)
|
58
|
+
var gd = document.getElementById('%{plot_id}');
|
59
|
+
var x = new MutationObserver(function (mutations, observer) {
|
60
|
+
var display = window.getComputedStyle(gd).display;
|
61
|
+
if (!display || display === 'none') {
|
62
|
+
console.log([gd, 'removed']);
|
63
|
+
Plotly.purge(gd);
|
64
|
+
observer.disconnect();
|
65
|
+
}
|
66
|
+
});
|
67
|
+
|
68
|
+
// Listen for the removal of the full notebook cell
|
69
|
+
var notebookContainer = gd.closest('#notebook-container');
|
70
|
+
if (notebookContainer) {
|
71
|
+
x.observe(notebookContainer, {childList: true});
|
72
|
+
}
|
73
|
+
|
74
|
+
// Listen for the clearing of the current output cell
|
75
|
+
var outputEl = gd.closest('.output');
|
76
|
+
if (outputEl) {
|
77
|
+
x.observe(outputEl, {childList: true});
|
78
|
+
}
|
79
|
+
END_POST_SCRIPT
|
80
|
+
|
81
|
+
super(figure, element_id: element_id, post_script: post_script)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require "date"
|
2
|
+
require "json"
|
3
|
+
require "time"
|
4
|
+
|
5
|
+
module Charty
|
6
|
+
module Backends
|
7
|
+
module PlotlyHelpers
|
8
|
+
class PlotlyRenderer
|
9
|
+
def render(figure)
|
10
|
+
json = JSON.generate(figure, allow_nan: true)
|
11
|
+
case json
|
12
|
+
when /\b(?:Infinity|NaN)\b/
|
13
|
+
visit(figure)
|
14
|
+
else
|
15
|
+
JSON.load(json)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private def visit(obj)
|
20
|
+
case obj
|
21
|
+
when Integer, String, Symbol, true, false, nil
|
22
|
+
obj
|
23
|
+
|
24
|
+
when Numeric
|
25
|
+
visit_float(obj)
|
26
|
+
|
27
|
+
when Time
|
28
|
+
visit_time(obj)
|
29
|
+
|
30
|
+
when Date
|
31
|
+
visit_date(obj)
|
32
|
+
|
33
|
+
when DateTime
|
34
|
+
visit_datetime(obj)
|
35
|
+
|
36
|
+
when Array
|
37
|
+
visit_array(obj)
|
38
|
+
|
39
|
+
when Hash
|
40
|
+
visit_hash(obj)
|
41
|
+
|
42
|
+
when ->(x) { defined?(Numo::NArray) && obj.is_a?(Numo::NArray) }
|
43
|
+
visit_array(obj.to_a)
|
44
|
+
|
45
|
+
when ->(x) { defined?(NMatrix) && obj.is_a?(NMatrix) }
|
46
|
+
visit_array(obj.to_a)
|
47
|
+
|
48
|
+
when ->(x) { defined?(Numpy::NDArray) && obj.is_a?(Numpy::NDArray) }
|
49
|
+
visit_array(obj.to_a)
|
50
|
+
|
51
|
+
when ->(x) { defined?(PyCall::List) && obj.is_a?(PyCall::List) }
|
52
|
+
visit_array(obj.to_a)
|
53
|
+
|
54
|
+
when ->(x) { defined?(PyCall::Tuple) && obj.is_a?(PyCall::Tuple) }
|
55
|
+
visit_array(obj.to_a)
|
56
|
+
|
57
|
+
when ->(x) { defined?(PyCall::Dict) && obj.is_a?(PyCall::Dict) }
|
58
|
+
visit_hash(obj.to_h)
|
59
|
+
|
60
|
+
when ->(x) { defined?(Pandas::Series) && obj.is_a?(Pandas::Series) }
|
61
|
+
visit_array(obj.to_a)
|
62
|
+
|
63
|
+
else
|
64
|
+
str = String.try_convert(obj)
|
65
|
+
return str unless str.nil?
|
66
|
+
|
67
|
+
ary = Array.try_convert(obj)
|
68
|
+
return visit_array(ary) unless ary.nil?
|
69
|
+
|
70
|
+
hsh = Hash.try_convert(obj)
|
71
|
+
return visit_hash(hsh) unless hsh.nil?
|
72
|
+
|
73
|
+
type_error(obj)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private def visit_float(obj)
|
78
|
+
obj = obj.to_f
|
79
|
+
rescue RangeError
|
80
|
+
type_error(obj)
|
81
|
+
else
|
82
|
+
case
|
83
|
+
when obj.finite?
|
84
|
+
obj
|
85
|
+
else
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
private def visit_time(obj)
|
91
|
+
obj.iso8601(6)
|
92
|
+
end
|
93
|
+
|
94
|
+
private def visit_date(obj)
|
95
|
+
obj.iso8601(6)
|
96
|
+
end
|
97
|
+
|
98
|
+
private def visit_datetime(obj)
|
99
|
+
obj.iso8601(6)
|
100
|
+
end
|
101
|
+
|
102
|
+
private def visit_array(obj)
|
103
|
+
obj.map {|x| visit(x) }
|
104
|
+
end
|
105
|
+
|
106
|
+
private def visit_hash(obj)
|
107
|
+
obj.map { |key, value|
|
108
|
+
[
|
109
|
+
key,
|
110
|
+
visit(value)
|
111
|
+
]
|
112
|
+
}.to_h
|
113
|
+
end
|
114
|
+
|
115
|
+
private def type_error(obj)
|
116
|
+
raise TypeError, "Unable to convert to JSON: %p" % obj
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
module Charty
|
4
|
+
module CacheDir
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def cache_dir_path
|
8
|
+
platform_cache_dir_path + "charty"
|
9
|
+
end
|
10
|
+
|
11
|
+
def platform_cache_dir_path
|
12
|
+
base_dir = case RUBY_PLATFORM
|
13
|
+
when /mswin/, /mingw/
|
14
|
+
ENV.fetch("LOCALAPPDATA", "~/AppData/Local")
|
15
|
+
when /darwin/
|
16
|
+
"~/Library/Caches"
|
17
|
+
else
|
18
|
+
ENV.fetch("XDG_CACHE_HOME", "~/.cache")
|
19
|
+
end
|
20
|
+
Pathname(base_dir).expand_path
|
21
|
+
end
|
22
|
+
|
23
|
+
def path(*path_components)
|
24
|
+
cache_dir_path.join(*path_components)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Charty
|
2
|
+
module IRubyHelper
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def iruby_notebook?
|
6
|
+
# TODO: This cannot distinguish notebook and console.
|
7
|
+
defined?(IRuby)
|
8
|
+
end
|
9
|
+
|
10
|
+
def vscode?
|
11
|
+
ENV.key?("VSCODE_PID")
|
12
|
+
end
|
13
|
+
|
14
|
+
def nteract?
|
15
|
+
ENV.key?("NTERACT_EXE")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/charty/plot_methods.rb
CHANGED
@@ -248,6 +248,46 @@ module Charty
|
|
248
248
|
&block
|
249
249
|
)
|
250
250
|
end
|
251
|
+
|
252
|
+
def hist_plot(data: nil, x: nil, y: nil, color: nil,
|
253
|
+
stat: :count, bins: :auto,
|
254
|
+
key_color: nil, palette: nil, color_order: nil, color_norm: nil,
|
255
|
+
legend: true, **options, &block)
|
256
|
+
# TODO: support following arguments
|
257
|
+
# - wiehgts
|
258
|
+
# - binwidth
|
259
|
+
# - binrange
|
260
|
+
# - discrete
|
261
|
+
# - cumulative
|
262
|
+
# - common_bins
|
263
|
+
# - common_norm
|
264
|
+
# - multiple
|
265
|
+
# - element
|
266
|
+
# - fill
|
267
|
+
# - shrink
|
268
|
+
# - kde
|
269
|
+
# - kde_params
|
270
|
+
# - line_params
|
271
|
+
# - thresh
|
272
|
+
# - pthresh
|
273
|
+
# - pmax
|
274
|
+
# - cbar
|
275
|
+
# - cbar_params
|
276
|
+
# - x_log_scale
|
277
|
+
# - y_log_scale
|
278
|
+
Plotters::HistogramPlotter.new(
|
279
|
+
data: data,
|
280
|
+
variables: { x: x, y: y, color: color },
|
281
|
+
stat: stat,
|
282
|
+
bins: bins,
|
283
|
+
key_color: key_color,
|
284
|
+
palette: palette,
|
285
|
+
color_order: color_order,
|
286
|
+
color_norm: color_norm,
|
287
|
+
legend: legend,
|
288
|
+
**options,
|
289
|
+
&block)
|
290
|
+
end
|
251
291
|
end
|
252
292
|
|
253
293
|
extend PlotMethods
|
data/lib/charty/plotters.rb
CHANGED
@@ -10,3 +10,6 @@ require_relative "plotters/vector_plotter"
|
|
10
10
|
require_relative "plotters/relational_plotter"
|
11
11
|
require_relative "plotters/scatter_plotter"
|
12
12
|
require_relative "plotters/line_plotter"
|
13
|
+
|
14
|
+
require_relative "plotters/distribution_plotter"
|
15
|
+
require_relative "plotters/histogram_plotter"
|
@@ -183,7 +183,7 @@ module Charty
|
|
183
183
|
|
184
184
|
levels = var_levels.dup
|
185
185
|
|
186
|
-
[:x, :y].each do |axis|
|
186
|
+
([:x, :y] & grouping_vars).each do |axis|
|
187
187
|
levels[axis] = plot_data[axis].categorical_order()
|
188
188
|
if processed
|
189
189
|
# TODO: perform inverse conversion of axis scaling here
|
@@ -213,16 +213,19 @@ module Charty
|
|
213
213
|
|
214
214
|
def save(filename, **kwargs)
|
215
215
|
backend = Backends.current
|
216
|
-
backend
|
217
|
-
render_plot(backend, **kwargs)
|
216
|
+
call_render_plot(backend, notebook: false, **kwargs)
|
218
217
|
backend.save(filename, **kwargs)
|
219
218
|
end
|
220
219
|
|
221
220
|
def render(notebook: false, **kwargs)
|
222
221
|
backend = Backends.current
|
222
|
+
call_render_plot(backend, notebook: notebook, **kwargs)
|
223
|
+
backend.render(notebook: notebook, **kwargs)
|
224
|
+
end
|
225
|
+
|
226
|
+
private def call_render_plot(backend, notebook: false, **kwargs)
|
223
227
|
backend.begin_figure
|
224
228
|
render_plot(backend, notebook: notebook, **kwargs)
|
225
|
-
backend.render(notebook: notebook, **kwargs)
|
226
229
|
end
|
227
230
|
|
228
231
|
private def render_plot(*, **)
|
@@ -231,12 +234,17 @@ module Charty
|
|
231
234
|
end
|
232
235
|
|
233
236
|
def to_iruby
|
234
|
-
render(notebook: iruby_notebook?)
|
237
|
+
render(notebook: IRubyHelper.iruby_notebook?)
|
235
238
|
end
|
236
239
|
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
+
def to_iruby_mimebundle(include: [], exclude: [])
|
241
|
+
backend = Backends.current
|
242
|
+
if backend.respond_to?(:render_mimebundle)
|
243
|
+
call_render_plot(backend, notebook: true)
|
244
|
+
backend.render_mimebundle(include: include, exclude: exclude)
|
245
|
+
else
|
246
|
+
{}
|
247
|
+
end
|
240
248
|
end
|
241
249
|
end
|
242
250
|
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module Charty
|
2
|
+
module Plotters
|
3
|
+
class DistributionPlotter < AbstractPlotter
|
4
|
+
def flat_structure
|
5
|
+
{
|
6
|
+
x: :values
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(data:, variables:, **options, &block)
|
11
|
+
x, y, color = variables.values_at(:x, :y, :color)
|
12
|
+
super(x, y, color, data: data, **options, &block)
|
13
|
+
|
14
|
+
setup_variables
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :variables
|
18
|
+
|
19
|
+
attr_reader :color_norm
|
20
|
+
|
21
|
+
def color_norm=(val)
|
22
|
+
unless val.nil?
|
23
|
+
raise NotImplementedError,
|
24
|
+
"Specifying color_norm is not supported yet"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :legend
|
29
|
+
|
30
|
+
def legend=(val)
|
31
|
+
@legend = check_legend(val)
|
32
|
+
end
|
33
|
+
|
34
|
+
private def check_legend(val)
|
35
|
+
check_boolean(val, :legend)
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_reader :input_format, :plot_data, :variables, :var_types
|
39
|
+
|
40
|
+
# This should be the same as one in RelationalPlotter
|
41
|
+
# TODO: move this to AbstractPlotter and refactor with CategoricalPlotter
|
42
|
+
private def setup_variables
|
43
|
+
if x.nil? && y.nil?
|
44
|
+
@input_format = :wide
|
45
|
+
setup_variables_with_wide_form_dataset
|
46
|
+
else
|
47
|
+
@input_format = :long
|
48
|
+
setup_variables_with_long_form_dataset
|
49
|
+
end
|
50
|
+
|
51
|
+
@var_types = @plot_data.columns.map { |k|
|
52
|
+
[k, variable_type(@plot_data[k], :categorical)]
|
53
|
+
}.to_h
|
54
|
+
end
|
55
|
+
|
56
|
+
private def setup_variables_with_wide_form_dataset
|
57
|
+
unless color.nil?
|
58
|
+
raise ArgumentError,
|
59
|
+
"Unable to assign the following variables in wide-form data: color"
|
60
|
+
end
|
61
|
+
|
62
|
+
if data.nil? || data.empty?
|
63
|
+
@plot_data = Charty::Table.new({})
|
64
|
+
@variables = {}
|
65
|
+
return
|
66
|
+
end
|
67
|
+
|
68
|
+
# TODO: detect flat data
|
69
|
+
flat = data.is_a?(Charty::Vector)
|
70
|
+
if flat
|
71
|
+
@plot_data = {}
|
72
|
+
@variables = {}
|
73
|
+
|
74
|
+
[:x, :y].each do |var|
|
75
|
+
case self.flat_structure[var]
|
76
|
+
when :index
|
77
|
+
@plot_data[var] = data.index.to_a
|
78
|
+
@variables[var] = data.index.name
|
79
|
+
when :values
|
80
|
+
@plot_data[var] = data.to_a
|
81
|
+
@variables[var] = data.name
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
@plot_data = Charty::Table.new(@plot_data)
|
86
|
+
else
|
87
|
+
raise NotImplementedError,
|
88
|
+
"wide-form input is not supported"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
private def setup_variables_with_long_form_dataset
|
93
|
+
if data.nil? || data.empty?
|
94
|
+
@plot_data = Charty::Table.new({})
|
95
|
+
@variables = {}
|
96
|
+
return
|
97
|
+
end
|
98
|
+
|
99
|
+
plot_data = {}
|
100
|
+
variables = {}
|
101
|
+
|
102
|
+
{
|
103
|
+
x: self.x,
|
104
|
+
y: self.y,
|
105
|
+
color: self.color,
|
106
|
+
}.each do |key, val|
|
107
|
+
next if val.nil?
|
108
|
+
|
109
|
+
if data.column_names.include?(val)
|
110
|
+
plot_data[key] = data[val]
|
111
|
+
variables[key] = val
|
112
|
+
else
|
113
|
+
case val
|
114
|
+
when Charty::Vector
|
115
|
+
plot_data[key] = val
|
116
|
+
variables[key] = val.name
|
117
|
+
else
|
118
|
+
raise ArgumentError,
|
119
|
+
"Could not interpret value %p for parameter %p" % [val, key]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
@plot_data = Charty::Table.new(plot_data)
|
125
|
+
@variables = variables.select do |var, name|
|
126
|
+
@plot_data[var].notnull.any?
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
private def map_color(palette: nil, order: nil, norm: nil)
|
131
|
+
@color_mapper = ColorMapper.new(self, palette, order, norm)
|
132
|
+
end
|
133
|
+
|
134
|
+
private def map_size(sizes: nil, order: nil, norm: nil)
|
135
|
+
@size_mapper = SizeMapper.new(self, sizes, order, norm)
|
136
|
+
end
|
137
|
+
|
138
|
+
private def map_style(markers: nil, dashes: nil, order: nil)
|
139
|
+
@style_mapper = StyleMapper.new(self, markers, dashes, order)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
module Charty
|
2
|
+
module Plotters
|
3
|
+
class HistogramPlotter < DistributionPlotter
|
4
|
+
def univariate?
|
5
|
+
self.variables.key?(:x) != self.variables.key?(:y)
|
6
|
+
end
|
7
|
+
|
8
|
+
def univariate_variable
|
9
|
+
unless univariate?
|
10
|
+
raise TypeError, "This is not a univariate plot"
|
11
|
+
end
|
12
|
+
([:x, :y] & self.variables.keys)[0]
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :weights
|
16
|
+
|
17
|
+
def weights=(val)
|
18
|
+
@weights = check_weights(val)
|
19
|
+
end
|
20
|
+
|
21
|
+
private def check_weights(val)
|
22
|
+
raise NotImplementedError, "weights is not supported yet"
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :stat
|
26
|
+
|
27
|
+
def stat=(val)
|
28
|
+
@stat = check_stat(val)
|
29
|
+
end
|
30
|
+
|
31
|
+
private def check_stat(val)
|
32
|
+
case val
|
33
|
+
when :count, "count"
|
34
|
+
val.to_sym
|
35
|
+
when :frequency, "frequency",
|
36
|
+
:density, "density",
|
37
|
+
:probability, "probability"
|
38
|
+
raise ArgumentError,
|
39
|
+
"%p for `stat` is not supported yet" % val,
|
40
|
+
caller
|
41
|
+
else
|
42
|
+
raise ArgumentError,
|
43
|
+
"Invalid value for `stat` (%p)" % val,
|
44
|
+
caller
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
attr_reader :bins
|
49
|
+
|
50
|
+
def bins=(val)
|
51
|
+
@bins = check_bins(val)
|
52
|
+
end
|
53
|
+
|
54
|
+
private def check_bins(val)
|
55
|
+
case val
|
56
|
+
when :auto, "auto"
|
57
|
+
val.to_sym
|
58
|
+
when Integer
|
59
|
+
val
|
60
|
+
else
|
61
|
+
raise ArgumentError,
|
62
|
+
"Invalid value for `bins` (%p)" % val,
|
63
|
+
caller
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# TODO: bin_width
|
68
|
+
# TODO: bin_range
|
69
|
+
# TODO: discrete
|
70
|
+
# TODO: cumulative
|
71
|
+
# TODO: common_bins
|
72
|
+
# TODO: common_norm
|
73
|
+
|
74
|
+
attr_reader :multiple
|
75
|
+
|
76
|
+
def multiple=(val)
|
77
|
+
@multiple = check_multiple(val)
|
78
|
+
end
|
79
|
+
|
80
|
+
private def check_multiple(val)
|
81
|
+
case val
|
82
|
+
when :layer, "layer"
|
83
|
+
val.to_sym
|
84
|
+
when :dodge, "dodge",
|
85
|
+
:stack, "stack",
|
86
|
+
:fill, "fill"
|
87
|
+
val = val.to_sym
|
88
|
+
raise NotImplementedError,
|
89
|
+
"%p for `multiple` is not supported yet" % val,
|
90
|
+
caller
|
91
|
+
else
|
92
|
+
raise ArgumentError,
|
93
|
+
"Invalid value for `multiple` (%p)" % val,
|
94
|
+
caller
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# TODO: element
|
99
|
+
# TODO: fill
|
100
|
+
# TODO: shrink
|
101
|
+
|
102
|
+
attr_reader :kde
|
103
|
+
|
104
|
+
def kde=(val)
|
105
|
+
raise NotImplementedError, "kde is not supported yet"
|
106
|
+
end
|
107
|
+
|
108
|
+
attr_reader :kde_params
|
109
|
+
|
110
|
+
def kde_params=(val)
|
111
|
+
raise NotImplementedError, "kde_params is not supported yet"
|
112
|
+
end
|
113
|
+
|
114
|
+
# TODO: thresh
|
115
|
+
# TODO: pthresh
|
116
|
+
# TODO: pmax
|
117
|
+
# TODO: cbar
|
118
|
+
# TODO: cbar_params
|
119
|
+
# TODO: x_log_scale
|
120
|
+
# TODO: y_log_scale
|
121
|
+
|
122
|
+
private def render_plot(backend, **)
|
123
|
+
draw_univariate_histogram(backend)
|
124
|
+
annotate_axes(backend)
|
125
|
+
end
|
126
|
+
|
127
|
+
private def draw_univariate_histogram(backend)
|
128
|
+
map_color(palette: palette, order: color_order, norm: color_norm)
|
129
|
+
|
130
|
+
# TODO: calculate histogram here and use bar plot to visualize
|
131
|
+
data_variable = self.univariate_variable
|
132
|
+
|
133
|
+
histograms = {}
|
134
|
+
each_subset([:color], processed: true) do |sub_vars, sub_data|
|
135
|
+
key = sub_vars.to_a
|
136
|
+
observations = sub_data[data_variable].drop_na.to_a
|
137
|
+
hist = Statistics.histogram(observations)
|
138
|
+
histograms[key] = hist
|
139
|
+
end
|
140
|
+
|
141
|
+
bin_start, bin_end, bin_size = nil
|
142
|
+
histograms.each do |_, hist|
|
143
|
+
s, e = hist.edge.minmax
|
144
|
+
z = (e - s).to_f / (hist.edge.length - 1)
|
145
|
+
bin_start = [bin_start, s].compact.min
|
146
|
+
bin_end = [bin_end, e].compact.max
|
147
|
+
bin_size = [bin_size, z].compact.min
|
148
|
+
end
|
149
|
+
|
150
|
+
if self.variables.key?(:color)
|
151
|
+
alpha = 0.5
|
152
|
+
else
|
153
|
+
alpha = 0.75
|
154
|
+
end
|
155
|
+
|
156
|
+
each_subset([:color], processed: true) do |sub_vars, sub_data|
|
157
|
+
name = sub_vars[:color]
|
158
|
+
observations = sub_data[data_variable].drop_na.to_a
|
159
|
+
|
160
|
+
backend.univariate_histogram(observations, name, data_variable, stat,
|
161
|
+
bin_start, bin_end, bin_size, alpha,
|
162
|
+
name, @color_mapper)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
private def annotate_axes(backend)
|
167
|
+
if univariate?
|
168
|
+
xlabel = self.variables[:x]
|
169
|
+
ylabel = self.variables[:y]
|
170
|
+
case self.univariate_variable
|
171
|
+
when :x
|
172
|
+
ylabel = self.stat.to_s.capitalize
|
173
|
+
else
|
174
|
+
xlabel = self.stat.to_s.capitalize
|
175
|
+
end
|
176
|
+
backend.set_ylabel(ylabel) if ylabel
|
177
|
+
backend.set_xlabel(xlabel) if xlabel
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
data/lib/charty/statistics.rb
CHANGED
@@ -10,6 +10,10 @@ module Charty
|
|
10
10
|
def self.stdev(enum, population: false)
|
11
11
|
enum.stdev(population: population)
|
12
12
|
end
|
13
|
+
|
14
|
+
def self.histogram(ary, *args, **kwargs)
|
15
|
+
ary.histogram(*args, **kwargs)
|
16
|
+
end
|
13
17
|
rescue LoadError
|
14
18
|
def self.mean(enum)
|
15
19
|
xs = enum.to_a
|
@@ -24,6 +28,11 @@ module Charty
|
|
24
28
|
var = xs.map {|x| (x - mean)**2 }.sum / (n - ddof)
|
25
29
|
Math.sqrt(var)
|
26
30
|
end
|
31
|
+
|
32
|
+
def self.histogram(ary, *args, **kwargs)
|
33
|
+
raise NotImplementedError,
|
34
|
+
"histogram is currently supported only with enumerable-statistics"
|
35
|
+
end
|
27
36
|
end
|
28
37
|
|
29
38
|
def self.bootstrap(vector, n_boot: 2000, func: :mean, units: nil, random: nil)
|
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.7
|
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-06-
|
13
|
+
date: 2021-06-21 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: red-colors
|
@@ -26,6 +26,20 @@ dependencies:
|
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: 0.3.0
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: red-datasets
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 0.1.2
|
36
|
+
type: :runtime
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 0.1.2
|
29
43
|
- !ruby/object:Gem::Dependency
|
30
44
|
name: red-palette
|
31
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -124,20 +138,6 @@ dependencies:
|
|
124
138
|
- - ">="
|
125
139
|
- !ruby/object:Gem::Version
|
126
140
|
version: '0'
|
127
|
-
- !ruby/object:Gem::Dependency
|
128
|
-
name: red-datasets
|
129
|
-
requirement: !ruby/object:Gem::Requirement
|
130
|
-
requirements:
|
131
|
-
- - ">="
|
132
|
-
- !ruby/object:Gem::Version
|
133
|
-
version: 0.1.2
|
134
|
-
type: :development
|
135
|
-
prerelease: false
|
136
|
-
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
requirements:
|
138
|
-
- - ">="
|
139
|
-
- !ruby/object:Gem::Version
|
140
|
-
version: 0.1.2
|
141
141
|
- !ruby/object:Gem::Dependency
|
142
142
|
name: daru
|
143
143
|
requirement: !ruby/object:Gem::Requirement
|
@@ -287,11 +287,16 @@ files:
|
|
287
287
|
- lib/charty/backends/google_charts.rb
|
288
288
|
- lib/charty/backends/gruff.rb
|
289
289
|
- lib/charty/backends/plotly.rb
|
290
|
+
- lib/charty/backends/plotly_helpers/html_renderer.rb
|
291
|
+
- lib/charty/backends/plotly_helpers/notebook_renderer.rb
|
292
|
+
- lib/charty/backends/plotly_helpers/plotly_renderer.rb
|
290
293
|
- lib/charty/backends/pyplot.rb
|
291
294
|
- lib/charty/backends/rubyplot.rb
|
292
295
|
- lib/charty/backends/unicode_plot.rb
|
296
|
+
- lib/charty/cache_dir.rb
|
293
297
|
- lib/charty/dash_pattern_generator.rb
|
294
298
|
- lib/charty/index.rb
|
299
|
+
- lib/charty/iruby_helper.rb
|
295
300
|
- lib/charty/layout.rb
|
296
301
|
- lib/charty/linspace.rb
|
297
302
|
- lib/charty/plot_methods.rb
|
@@ -302,7 +307,9 @@ files:
|
|
302
307
|
- lib/charty/plotters/box_plotter.rb
|
303
308
|
- lib/charty/plotters/categorical_plotter.rb
|
304
309
|
- lib/charty/plotters/count_plotter.rb
|
310
|
+
- lib/charty/plotters/distribution_plotter.rb
|
305
311
|
- lib/charty/plotters/estimation_support.rb
|
312
|
+
- lib/charty/plotters/histogram_plotter.rb
|
306
313
|
- lib/charty/plotters/line_plotter.rb
|
307
314
|
- lib/charty/plotters/random_support.rb
|
308
315
|
- lib/charty/plotters/relational_plotter.rb
|