charty 0.1.5.dev → 0.2.0
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/.travis.yml +4 -5
- data/README.md +1 -1
- data/charty.gemspec +6 -0
- data/examples/sample_bokeh.ipynb +156 -0
- data/examples/sample_google_chart.ipynb +229 -68
- data/examples/sample_images/bar_bokeh.html +85 -0
- data/examples/sample_images/barh_bokeh.html +85 -0
- data/examples/sample_images/box_plot_bokeh.html +85 -0
- data/examples/sample_images/curve_bokeh.html +85 -0
- data/examples/sample_images/curve_with_function_bokeh.html +85 -0
- data/examples/sample_images/scatter_bokeh.html +85 -0
- data/lib/charty.rb +2 -1
- data/lib/charty/backends.rb +55 -0
- data/lib/charty/backends/bokeh.rb +61 -55
- data/lib/charty/backends/google_chart.rb +187 -129
- data/lib/charty/backends/gruff.rb +91 -83
- data/lib/charty/backends/plotly.rb +109 -0
- data/lib/charty/backends/pyplot.rb +96 -88
- data/lib/charty/backends/rubyplot.rb +82 -74
- data/lib/charty/plotter.rb +41 -33
- data/lib/charty/table.rb +44 -3
- data/lib/charty/table_adapters.rb +23 -0
- data/lib/charty/table_adapters/active_record_adapter.rb +55 -0
- data/lib/charty/table_adapters/daru_adapter.rb +34 -0
- data/lib/charty/table_adapters/datasets_adapter.rb +41 -0
- data/lib/charty/table_adapters/hash_adapter.rb +108 -0
- data/lib/charty/table_adapters/narray_adapter.rb +57 -0
- data/lib/charty/table_adapters/nmatrix_adapter.rb +57 -0
- data/lib/charty/version.rb +1 -1
- metadata +104 -5
- data/lib/charty/plotter_adapter.rb +0 -17
@@ -1,94 +1,102 @@
|
|
1
|
-
require '
|
1
|
+
require 'fileutils'
|
2
2
|
|
3
3
|
module Charty
|
4
|
-
|
5
|
-
|
4
|
+
module Backends
|
5
|
+
class Rubyplot
|
6
|
+
Backends.register(:rubyplot, self)
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
class << self
|
9
|
+
def prepare
|
10
|
+
require 'rubyplot'
|
11
|
+
end
|
12
|
+
end
|
10
13
|
|
11
|
-
|
12
|
-
|
14
|
+
def initialize
|
15
|
+
@plot = ::Rubyplot
|
16
|
+
end
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
18
|
+
def label(x, y)
|
19
|
+
end
|
20
|
+
|
21
|
+
def series=(series)
|
22
|
+
@series = series
|
23
|
+
end
|
17
24
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
25
|
+
def render_layout(layout)
|
26
|
+
(fig, axes) = *@plot.subplots(nrows: layout.num_rows, ncols: layout.num_cols)
|
27
|
+
layout.rows.each_with_index do |row, y|
|
28
|
+
row.each_with_index do |cel, x|
|
29
|
+
plot = layout.num_rows > 1 ? axes[y][x] : axes[x]
|
30
|
+
plot(plot, cel)
|
31
|
+
end
|
24
32
|
end
|
33
|
+
@plot.show
|
25
34
|
end
|
26
|
-
@plot.show
|
27
|
-
end
|
28
35
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
36
|
+
def render(context, filename="")
|
37
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
38
|
+
plot(@plot, context).write(filename)
|
39
|
+
end
|
33
40
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
41
|
+
def plot(plot, context)
|
42
|
+
# case
|
43
|
+
# when plot.respond_to?(:xlim)
|
44
|
+
# plot.xlim(context.range_x.begin, context.range_x.end)
|
45
|
+
# plot.ylim(context.range_y.begin, context.range_y.end)
|
46
|
+
# when plot.respond_to?(:set_xlim)
|
47
|
+
# plot.set_xlim(context.range_x.begin, context.range_x.end)
|
48
|
+
# plot.set_ylim(context.range_y.begin, context.range_y.end)
|
49
|
+
# end
|
43
50
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
51
|
+
figure = ::Rubyplot::Figure.new
|
52
|
+
axes = figure.add_subplot 0,0
|
53
|
+
axes.title = context.title if context.title
|
54
|
+
axes.x_title = context.xlabel if context.xlabel
|
55
|
+
axes.y_title = context.ylabel if context.ylabel
|
49
56
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
57
|
+
case context.method
|
58
|
+
when :bar
|
59
|
+
context.series.each do |data|
|
60
|
+
axes.bar! do |p|
|
61
|
+
p.data(data.xs.to_a)
|
62
|
+
p.label = data.label
|
63
|
+
end
|
56
64
|
end
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
figure
|
66
|
+
when :barh
|
67
|
+
raise NotImplementedError
|
68
|
+
when :box_plot
|
69
|
+
raise NotImplementedError
|
70
|
+
when :bubble
|
71
|
+
context.series.each do |data|
|
72
|
+
axes.bubble! do |p|
|
73
|
+
p.data(data.xs.to_a, data.ys.to_a, data.zs.to_a)
|
74
|
+
p.label = data.label if data.label
|
75
|
+
end
|
68
76
|
end
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
77
|
+
figure
|
78
|
+
when :curve
|
79
|
+
context.series.each do |data|
|
80
|
+
axes.line! do |p|
|
81
|
+
p.data(data.xs.to_a, data.ys.to_a)
|
82
|
+
p.label = data.label if data.label
|
83
|
+
end
|
76
84
|
end
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
85
|
+
figure
|
86
|
+
when :scatter
|
87
|
+
context.series.each do |data|
|
88
|
+
axes.scatter! do |p|
|
89
|
+
p.data(data.xs.to_a, data.ys.to_a)
|
90
|
+
p.label = data.label if data.label
|
91
|
+
end
|
84
92
|
end
|
93
|
+
figure
|
94
|
+
when :error_bar
|
95
|
+
# refs. https://github.com/SciRuby/rubyplot/issues/26
|
96
|
+
raise NotImplementedError
|
97
|
+
when :hist
|
98
|
+
raise NotImplementedError
|
85
99
|
end
|
86
|
-
figure
|
87
|
-
when :error_bar
|
88
|
-
# refs. https://github.com/SciRuby/rubyplot/issues/26
|
89
|
-
raise NotImplementedError
|
90
|
-
when :hist
|
91
|
-
raise NotImplementedError
|
92
100
|
end
|
93
101
|
end
|
94
102
|
end
|
data/lib/charty/plotter.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
module Charty
|
2
2
|
class Plotter
|
3
|
-
def initialize(
|
4
|
-
|
3
|
+
def initialize(backend_name)
|
4
|
+
backend_class = Backends.find_backend_class(backend_name)
|
5
|
+
@backend = backend_class.new
|
5
6
|
end
|
6
7
|
|
7
8
|
def table=(data, **kwargs)
|
@@ -11,10 +12,11 @@ module Charty
|
|
11
12
|
attr_reader :table
|
12
13
|
|
13
14
|
def to_bar(x, y, **args, &block)
|
14
|
-
seriesx
|
15
|
+
seriesx = table[x]
|
16
|
+
seriesy = table[y]
|
15
17
|
xrange = (seriesx.min)..(seriesx.max)
|
16
18
|
yrange = (seriesy.min)..(seriesy.max)
|
17
|
-
bar
|
19
|
+
bar do
|
18
20
|
series seriesx, seriesy
|
19
21
|
range x: xrange, y: yrange
|
20
22
|
xlabel x
|
@@ -23,10 +25,11 @@ module Charty
|
|
23
25
|
end
|
24
26
|
|
25
27
|
def to_barh(x, y, **args, &block)
|
26
|
-
seriesx
|
28
|
+
seriesx = table[x]
|
29
|
+
seriesy = table[y]
|
27
30
|
xrange = (seriesx.min)..(seriesx.max)
|
28
31
|
yrange = (seriesy.min)..(seriesy.max)
|
29
|
-
|
32
|
+
barh do
|
30
33
|
series seriesx, seriesy
|
31
34
|
range x: xrange, y: yrange
|
32
35
|
xlabel x
|
@@ -35,10 +38,10 @@ module Charty
|
|
35
38
|
end
|
36
39
|
|
37
40
|
def to_box_plot(x, y, **args, &block)
|
38
|
-
serieses = table
|
41
|
+
serieses = [table[x], table[y]]
|
39
42
|
xrange = 0..serieses.size
|
40
43
|
yrange = (serieses.flatten.min - 1)..(serieses.flatten.max + 1)
|
41
|
-
box_plot
|
44
|
+
box_plot do
|
42
45
|
data serieses
|
43
46
|
range x: xrange, y: yrange
|
44
47
|
xlabel x
|
@@ -47,10 +50,12 @@ module Charty
|
|
47
50
|
end
|
48
51
|
|
49
52
|
def to_bubble(x, y, z, **args, &block)
|
50
|
-
seriesx
|
53
|
+
seriesx = table[x]
|
54
|
+
seriesy = table[y]
|
55
|
+
seriesz = table[z]
|
51
56
|
xrange = (seriesx.min)..(seriesx.max)
|
52
57
|
yrange = (seriesy.min)..(seriesy.max)
|
53
|
-
bubble
|
58
|
+
bubble do
|
54
59
|
series seriesx, seriesy, seriesz
|
55
60
|
range x: xrange, y: yrange
|
56
61
|
xlabel x
|
@@ -59,10 +64,11 @@ module Charty
|
|
59
64
|
end
|
60
65
|
|
61
66
|
def to_curve(x, y, **args, &block)
|
62
|
-
seriesx
|
67
|
+
seriesx = table[x]
|
68
|
+
seriesy = table[y]
|
63
69
|
xrange = (seriesx.min)..(seriesx.max)
|
64
70
|
yrange = (seriesy.min)..(seriesy.max)
|
65
|
-
curve
|
71
|
+
curve do
|
66
72
|
series seriesx, seriesy
|
67
73
|
range x: xrange, y: yrange
|
68
74
|
xlabel x
|
@@ -71,10 +77,11 @@ module Charty
|
|
71
77
|
end
|
72
78
|
|
73
79
|
def to_scatter(x, y, **args, &block)
|
74
|
-
seriesx
|
80
|
+
seriesx = table[x]
|
81
|
+
seriesy = table[y]
|
75
82
|
xrange = (seriesx.min)..(seriesx.max)
|
76
83
|
yrange = (seriesy.min)..(seriesy.max)
|
77
|
-
scatter
|
84
|
+
scatter do
|
78
85
|
series seriesx, seriesy
|
79
86
|
range x: xrange, y: yrange
|
80
87
|
xlabel x
|
@@ -84,10 +91,11 @@ module Charty
|
|
84
91
|
|
85
92
|
def to_error_bar(x, y, **args, &block)
|
86
93
|
# TODO: It is not yet decided how to include data including xerror and yerror.
|
87
|
-
seriesx
|
94
|
+
seriesx = table[x]
|
95
|
+
seriesy = table[y]
|
88
96
|
xrange = (seriesx.min)..(seriesx.max)
|
89
97
|
yrange = (seriesy.min)..(seriesy.max)
|
90
|
-
error_bar
|
98
|
+
error_bar do
|
91
99
|
series seriesx, seriesy
|
92
100
|
range x: xrange, y: yrange
|
93
101
|
xlabel x
|
@@ -96,10 +104,10 @@ module Charty
|
|
96
104
|
end
|
97
105
|
|
98
106
|
def to_hst(x, y, **args, &block)
|
99
|
-
serieses = table
|
107
|
+
serieses = [table[x], table[y]]
|
100
108
|
xrange = (serieses.flatten.min - 1)..(serieses.flatten.max + 1)
|
101
109
|
yrange = 0..serieses[0].size
|
102
|
-
hist
|
110
|
+
hist do
|
103
111
|
data serieses
|
104
112
|
range x: xrange, y: yrange
|
105
113
|
xlabel x
|
@@ -109,46 +117,46 @@ module Charty
|
|
109
117
|
|
110
118
|
def bar(**args, &block)
|
111
119
|
context = RenderContext.new :bar, **args, &block
|
112
|
-
context.apply(@
|
120
|
+
context.apply(@backend)
|
113
121
|
end
|
114
122
|
|
115
123
|
def barh(**args, &block)
|
116
124
|
context = RenderContext.new :barh, **args, &block
|
117
|
-
context.apply(@
|
125
|
+
context.apply(@backend)
|
118
126
|
end
|
119
127
|
|
120
128
|
def box_plot(**args, &block)
|
121
129
|
context = RenderContext.new :box_plot, **args, &block
|
122
|
-
context.apply(@
|
130
|
+
context.apply(@backend)
|
123
131
|
end
|
124
132
|
|
125
133
|
def bubble(**args, &block)
|
126
134
|
context = RenderContext.new :bubble, **args, &block
|
127
|
-
context.apply(@
|
135
|
+
context.apply(@backend)
|
128
136
|
end
|
129
137
|
|
130
138
|
def curve(**args, &block)
|
131
139
|
context = RenderContext.new :curve, **args, &block
|
132
|
-
context.apply(@
|
140
|
+
context.apply(@backend)
|
133
141
|
end
|
134
142
|
|
135
143
|
def scatter(**args, &block)
|
136
144
|
context = RenderContext.new :scatter, **args, &block
|
137
|
-
context.apply(@
|
145
|
+
context.apply(@backend)
|
138
146
|
end
|
139
147
|
|
140
148
|
def error_bar(**args, &block)
|
141
149
|
context = RenderContext.new :error_bar, **args, &block
|
142
|
-
context.apply(@
|
150
|
+
context.apply(@backend)
|
143
151
|
end
|
144
152
|
|
145
153
|
def hist(**args, &block)
|
146
154
|
context = RenderContext.new :hist, **args, &block
|
147
|
-
context.apply(@
|
155
|
+
context.apply(@backend)
|
148
156
|
end
|
149
157
|
|
150
158
|
def layout(definition=:horizontal)
|
151
|
-
Layout.new(@
|
159
|
+
Layout.new(@backend, definition)
|
152
160
|
end
|
153
161
|
end
|
154
162
|
|
@@ -160,7 +168,7 @@ module Charty
|
|
160
168
|
def initialize(method, **args, &block)
|
161
169
|
@method = method
|
162
170
|
configurator = Configurator.new(**args)
|
163
|
-
configurator.instance_eval
|
171
|
+
configurator.instance_eval(&block)
|
164
172
|
# TODO: label も外から付けられた方がよさそう
|
165
173
|
(@range, @series, @function, @data, @title, @xlabel, @ylabel, @labels) = configurator.to_a
|
166
174
|
end
|
@@ -229,17 +237,17 @@ module Charty
|
|
229
237
|
end
|
230
238
|
|
231
239
|
def render(filename=nil)
|
232
|
-
@
|
240
|
+
@backend.render(self, filename)
|
233
241
|
end
|
234
242
|
|
235
243
|
def save(filename=nil)
|
236
|
-
@
|
244
|
+
@backend.save(self, filename)
|
237
245
|
end
|
238
246
|
|
239
|
-
def apply(
|
247
|
+
def apply(backend)
|
240
248
|
case
|
241
249
|
when !@series.empty?
|
242
|
-
|
250
|
+
backend.series = @series
|
243
251
|
when @function
|
244
252
|
linspace = Linspace.new(@range[:x], 100)
|
245
253
|
# TODO: set label with function
|
@@ -247,7 +255,7 @@ module Charty
|
|
247
255
|
@series << Series.new(linspace.to_a, linspace.map{|x| @function.call(x) }, label: "function" )
|
248
256
|
end
|
249
257
|
|
250
|
-
@
|
258
|
+
@backend = backend
|
251
259
|
self
|
252
260
|
end
|
253
261
|
end
|
data/lib/charty/table.rb
CHANGED
@@ -1,11 +1,52 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
|
2
3
|
module Charty
|
4
|
+
class ColumnAccessor
|
5
|
+
def initialize(adapter)
|
6
|
+
@adapter = adapter
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](column_name)
|
10
|
+
@adapter[nil, column_name]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
3
14
|
class Table
|
4
|
-
|
5
|
-
|
15
|
+
extend Forwardable
|
16
|
+
|
17
|
+
def initialize(data, **kwargs)
|
18
|
+
adapter_class = TableAdapters.find_adapter_class(data)
|
19
|
+
if kwargs.empty?
|
20
|
+
@adapter = adapter_class.new(data)
|
21
|
+
else
|
22
|
+
@adapter = adapter_class.new(data, **kwargs)
|
23
|
+
end
|
6
24
|
end
|
7
25
|
|
8
|
-
attr_reader :
|
26
|
+
attr_reader :adapter
|
27
|
+
|
28
|
+
def_delegator :@adapter, :column_names
|
29
|
+
|
30
|
+
def columns
|
31
|
+
@column_accessor ||= ColumnAccessor.new(@adapter)
|
32
|
+
end
|
33
|
+
|
34
|
+
def [](*args)
|
35
|
+
n_args = args.length
|
36
|
+
case n_args
|
37
|
+
when 1
|
38
|
+
row = nil
|
39
|
+
column = args[0]
|
40
|
+
@adapter[row, column]
|
41
|
+
when 2
|
42
|
+
row = args[0]
|
43
|
+
column = args[1]
|
44
|
+
@adapter[row, column]
|
45
|
+
else
|
46
|
+
message = "wrong number of arguments (given #{n_args}, expected 1..2)"
|
47
|
+
raise ArgumentError, message
|
48
|
+
end
|
49
|
+
end
|
9
50
|
|
10
51
|
def to_a(x=nil, y=nil, z=nil)
|
11
52
|
case
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Charty
|
2
|
+
module TableAdapters
|
3
|
+
@adapters = {}
|
4
|
+
|
5
|
+
def self.register(name, adapter_class)
|
6
|
+
@adapters[name] = adapter_class
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.find_adapter_class(data)
|
10
|
+
@adapters.each_value do |adapter_class|
|
11
|
+
return adapter_class if adapter_class.supported?(data)
|
12
|
+
end
|
13
|
+
raise ArgumentError, "Unsupported data class: #{data.class}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
require_relative 'table_adapters/hash_adapter'
|
19
|
+
require_relative 'table_adapters/narray_adapter'
|
20
|
+
require_relative 'table_adapters/datasets_adapter'
|
21
|
+
require_relative 'table_adapters/daru_adapter'
|
22
|
+
require_relative 'table_adapters/active_record_adapter'
|
23
|
+
require_relative 'table_adapters/nmatrix_adapter'
|