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.
@@ -1,94 +1,102 @@
1
- require 'rubyplot'
1
+ require 'fileutils'
2
2
 
3
3
  module Charty
4
- class Rubyplot < PlotterAdapter
5
- Name = "rubyplot"
4
+ module Backends
5
+ class Rubyplot
6
+ Backends.register(:rubyplot, self)
6
7
 
7
- def initialize
8
- @plot = ::Rubyplot
9
- end
8
+ class << self
9
+ def prepare
10
+ require 'rubyplot'
11
+ end
12
+ end
10
13
 
11
- def label(x, y)
12
- end
14
+ def initialize
15
+ @plot = ::Rubyplot
16
+ end
13
17
 
14
- def series=(series)
15
- @series = series
16
- end
18
+ def label(x, y)
19
+ end
20
+
21
+ def series=(series)
22
+ @series = series
23
+ end
17
24
 
18
- def render_layout(layout)
19
- (fig, axes) = *@plot.subplots(nrows: layout.num_rows, ncols: layout.num_cols)
20
- layout.rows.each_with_index do |row, y|
21
- row.each_with_index do |cel, x|
22
- plot = layout.num_rows > 1 ? axes[y][x] : axes[x]
23
- plot(plot, cel)
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
- def render(context, filename="")
30
- FileUtils.mkdir_p(File.dirname(filename))
31
- plot(@plot, context).write(filename)
32
- end
36
+ def render(context, filename="")
37
+ FileUtils.mkdir_p(File.dirname(filename))
38
+ plot(@plot, context).write(filename)
39
+ end
33
40
 
34
- def plot(plot, context)
35
- # case
36
- # when plot.respond_to?(:xlim)
37
- # plot.xlim(context.range_x.begin, context.range_x.end)
38
- # plot.ylim(context.range_y.begin, context.range_y.end)
39
- # when plot.respond_to?(:set_xlim)
40
- # plot.set_xlim(context.range_x.begin, context.range_x.end)
41
- # plot.set_ylim(context.range_y.begin, context.range_y.end)
42
- # end
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
- figure = ::Rubyplot::Figure.new
45
- axes = figure.add_subplot 0,0
46
- axes.title = context.title if context.title
47
- axes.x_title = context.xlabel if context.xlabel
48
- axes.y_title = context.ylabel if context.ylabel
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
- case context.method
51
- when :bar
52
- context.series.each do |data|
53
- axes.bar! do |p|
54
- p.data(data.xs.to_a)
55
- p.label = data.label
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
- end
58
- figure
59
- when :barh
60
- raise NotImplementedError
61
- when :box_plot
62
- raise NotImplementedError
63
- when :bubble
64
- context.series.each do |data|
65
- axes.bubble! do |p|
66
- p.data(data.xs.to_a, data.ys.to_a, data.zs.to_a)
67
- p.label = data.label if data.label
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
- end
70
- figure
71
- when :curve
72
- context.series.each do |data|
73
- axes.line! do |p|
74
- p.data(data.xs.to_a, data.ys.to_a)
75
- p.label = data.label if data.label
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
- end
78
- figure
79
- when :scatter
80
- context.series.each do |data|
81
- axes.scatter! do |p|
82
- p.data(data.xs.to_a, data.ys.to_a)
83
- p.label = data.label if data.label
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
@@ -1,7 +1,8 @@
1
1
  module Charty
2
2
  class Plotter
3
- def initialize(adapter_name)
4
- @plotter_adapter = PlotterAdapter.create(adapter_name)
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, seriesy = *table.to_a(x, y)
15
+ seriesx = table[x]
16
+ seriesy = table[y]
15
17
  xrange = (seriesx.min)..(seriesx.max)
16
18
  yrange = (seriesy.min)..(seriesy.max)
17
- bar = bar do
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, seriesy = *table.to_a(x, y)
28
+ seriesx = table[x]
29
+ seriesy = table[y]
27
30
  xrange = (seriesx.min)..(seriesx.max)
28
31
  yrange = (seriesy.min)..(seriesy.max)
29
- bar = barh do
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.to_a(x, y)
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 = box_plot do
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, seriesy, seriesz = *table.to_a(x, y, z)
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 = bubble do
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, seriesy = *table.to_a(x, y)
67
+ seriesx = table[x]
68
+ seriesy = table[y]
63
69
  xrange = (seriesx.min)..(seriesx.max)
64
70
  yrange = (seriesy.min)..(seriesy.max)
65
- curve = curve do
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, seriesy = *table.to_a(x, y)
80
+ seriesx = table[x]
81
+ seriesy = table[y]
75
82
  xrange = (seriesx.min)..(seriesx.max)
76
83
  yrange = (seriesy.min)..(seriesy.max)
77
- scatter = scatter do
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, seriesy = *table.to_a(x, y)
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 = error_bar do
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.to_a(x, y)
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 = hist do
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(@plotter_adapter)
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(@plotter_adapter)
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(@plotter_adapter)
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(@plotter_adapter)
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(@plotter_adapter)
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(@plotter_adapter)
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(@plotter_adapter)
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(@plotter_adapter)
155
+ context.apply(@backend)
148
156
  end
149
157
 
150
158
  def layout(definition=:horizontal)
151
- Layout.new(@plotter_adapter, definition)
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 &block
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
- @plotter_adapter.render(self, filename)
240
+ @backend.render(self, filename)
233
241
  end
234
242
 
235
243
  def save(filename=nil)
236
- @plotter_adapter.save(self, filename)
244
+ @backend.save(self, filename)
237
245
  end
238
246
 
239
- def apply(plotter_adapter)
247
+ def apply(backend)
240
248
  case
241
249
  when !@series.empty?
242
- plotter_adapter.series = @series
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
- @plotter_adapter = plotter_adapter
258
+ @backend = backend
251
259
  self
252
260
  end
253
261
  end
@@ -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
- def initialize(table)
5
- @table = table
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 :table
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'