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
@@ -0,0 +1,55 @@
|
|
1
|
+
module Charty
|
2
|
+
module TableAdapters
|
3
|
+
class ActiveRecordAdapter
|
4
|
+
TableAdapters.register(:active_record, self)
|
5
|
+
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def self.supported?(data)
|
9
|
+
defined?(ActiveRecord::Relation) && data.is_a?(ActiveRecord::Relation)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(data)
|
13
|
+
@data = check_type(ActiveRecord::Relation, data, :data)
|
14
|
+
@column_names = @data.column_names.freeze
|
15
|
+
@columns = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :column_names
|
19
|
+
|
20
|
+
def [](row, column)
|
21
|
+
fetch_records unless @columns
|
22
|
+
if row
|
23
|
+
@columns[resolve_column_index(column)][row]
|
24
|
+
else
|
25
|
+
@columns[resolve_column_index(column)]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private def resolve_column_index(column)
|
30
|
+
case column
|
31
|
+
when String, Symbol
|
32
|
+
index = column_names.index(column.to_s)
|
33
|
+
unless index
|
34
|
+
raise IndexError, "invalid column name: #{column.inspect}"
|
35
|
+
end
|
36
|
+
index
|
37
|
+
when Integer
|
38
|
+
column
|
39
|
+
else
|
40
|
+
message = "column must be String or Integer: #{column.inspect}"
|
41
|
+
raise ArgumentError, message
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private def fetch_records
|
46
|
+
@columns = @data.pluck(*column_names).transpose
|
47
|
+
end
|
48
|
+
|
49
|
+
private def check_type(type, data, name)
|
50
|
+
return data if data.is_a?(type)
|
51
|
+
raise TypeError, "#{name} must be a #{type}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Charty
|
2
|
+
module TableAdapters
|
3
|
+
class DaruAdapter
|
4
|
+
TableAdapters.register(:daru, self)
|
5
|
+
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def self.supported?(data)
|
9
|
+
defined?(Daru::DataFrame) && data.is_a?(Daru::DataFrame)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(data)
|
13
|
+
@data = check_type(Daru::DataFrame, data, :data)
|
14
|
+
end
|
15
|
+
|
16
|
+
def column_names
|
17
|
+
@data.vectors.to_a
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](row, column)
|
21
|
+
if row
|
22
|
+
@data[column][row]
|
23
|
+
else
|
24
|
+
@data[column]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private def check_type(type, data, name)
|
29
|
+
return data if data.is_a?(type)
|
30
|
+
raise TypeError, "#{name} must be a #{type}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Charty
|
2
|
+
module TableAdapters
|
3
|
+
class DatasetsAdapter
|
4
|
+
TableAdapters.register(:datasets, self)
|
5
|
+
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def self.supported?(data)
|
9
|
+
defined?(Datasets::Dataset) &&
|
10
|
+
data.is_a?(Datasets::Dataset)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(dataset)
|
14
|
+
@table = dataset.to_table
|
15
|
+
@records = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def column_names
|
19
|
+
@table.column_names
|
20
|
+
end
|
21
|
+
|
22
|
+
def each(&block)
|
23
|
+
return to_enum(__method__) unless block_given?
|
24
|
+
|
25
|
+
@table.each_record(&block)
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param [Integer] row Row index
|
29
|
+
# @param [Symbol,String,Integer] column Column index
|
30
|
+
def [](row, column)
|
31
|
+
if row
|
32
|
+
record = @table.find_record(row)
|
33
|
+
return nil if record.nil?
|
34
|
+
record[column]
|
35
|
+
else
|
36
|
+
@table[column]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module Charty
|
5
|
+
module TableAdapters
|
6
|
+
class HashAdapter
|
7
|
+
TableAdapters.register(:hash, self)
|
8
|
+
|
9
|
+
extend Forwardable
|
10
|
+
include Enumerable
|
11
|
+
|
12
|
+
def self.supported?(data)
|
13
|
+
case data
|
14
|
+
when []
|
15
|
+
true
|
16
|
+
when Array
|
17
|
+
case data[0]
|
18
|
+
when Numeric, String, Time, Date
|
19
|
+
true
|
20
|
+
when Hash
|
21
|
+
data.all? {|el| el.is_a? Hash }
|
22
|
+
when method(:array?)
|
23
|
+
data.all?(&method(:array?))
|
24
|
+
end
|
25
|
+
when Hash
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.array?(data)
|
31
|
+
case data
|
32
|
+
when Array,
|
33
|
+
->(x) { defined?(Numo::NArray) && x.is_a?(Numo::NArray) },
|
34
|
+
->(x) { defined?(Daru::Vector) && x.is_a?(Daru::Vector) },
|
35
|
+
->(x) { defined?(NMatrix) && x.is_a?(NMatrix) }
|
36
|
+
true
|
37
|
+
else
|
38
|
+
false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize(data, columns: nil)
|
43
|
+
case data
|
44
|
+
when Hash
|
45
|
+
@data = data
|
46
|
+
when Array
|
47
|
+
case data[0]
|
48
|
+
when Numeric, String, Time, Date
|
49
|
+
data = data.map {|x| [x] }
|
50
|
+
@data = make_data_from_records(data, columns)
|
51
|
+
when Hash
|
52
|
+
# TODO
|
53
|
+
when self.class.method(:array?)
|
54
|
+
unsupported_data_format unless data.all?(&self.class.method(:array?))
|
55
|
+
@data = make_data_from_records(data, columns)
|
56
|
+
else
|
57
|
+
unsupported_data_format
|
58
|
+
end
|
59
|
+
else
|
60
|
+
unsupported_data_format
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def_delegator :@data, :keys, :column_names
|
65
|
+
|
66
|
+
def [](row, column)
|
67
|
+
if row
|
68
|
+
@data[column][row]
|
69
|
+
else
|
70
|
+
@data[column]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def each
|
75
|
+
i, n = 0, shape[0]
|
76
|
+
while i < n
|
77
|
+
record = @data.map {|k, v| v[i] }
|
78
|
+
yield record
|
79
|
+
i += 1
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private def make_data_from_records(data, columns)
|
84
|
+
n_rows = data.length
|
85
|
+
n_columns = data.map(&:size).max
|
86
|
+
columns = generate_column_names(n_columns, columns)
|
87
|
+
columns.map.with_index { |key, j|
|
88
|
+
values = n_rows.times.map {|i| data[i][j] }
|
89
|
+
[key, values]
|
90
|
+
}.to_h
|
91
|
+
end
|
92
|
+
|
93
|
+
private def generate_column_names(n_columns, columns)
|
94
|
+
# FIXME: this is the same as NArrayAdapter#generate_column_names
|
95
|
+
columns ||= []
|
96
|
+
if columns.length >= n_columns
|
97
|
+
columns[0, n_columns]
|
98
|
+
else
|
99
|
+
columns + columns.length.upto(n_columns - 1).map {|i| "X#{i}" }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
private def unsupported_data_format
|
104
|
+
raise ArgumentError, "Unsupported data format"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Charty
|
2
|
+
module TableAdapters
|
3
|
+
class NArrayAdapter
|
4
|
+
TableAdapters.register(:narray, self)
|
5
|
+
|
6
|
+
def self.supported?(data)
|
7
|
+
defined?(Numo::NArray) && data.is_a?(Numo::NArray) && data.ndim <= 2
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(data, columns: nil)
|
11
|
+
case data.ndim
|
12
|
+
when 1
|
13
|
+
data = data.reshape(data.length, 1)
|
14
|
+
when 2
|
15
|
+
# do nothing
|
16
|
+
else
|
17
|
+
raise ArgumentError, "Unsupported data format"
|
18
|
+
end
|
19
|
+
@data = data
|
20
|
+
@column_names = generate_column_names(data.shape[1], columns)
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :column_names
|
24
|
+
|
25
|
+
def [](row, column)
|
26
|
+
if row
|
27
|
+
@data[row, resolve_column_index(column)]
|
28
|
+
else
|
29
|
+
@data[true, resolve_column_index(column)]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private def resolve_column_index(column)
|
34
|
+
case column
|
35
|
+
when String, Symbol
|
36
|
+
index = column_names.index(column.to_s)
|
37
|
+
return index if index
|
38
|
+
raise IndexError, "invalid column name: #{column}"
|
39
|
+
when Integer
|
40
|
+
column
|
41
|
+
else
|
42
|
+
message = "column must be String or Integer: #{column.inspect}"
|
43
|
+
raise ArgumentError, message
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private def generate_column_names(n_columns, columns)
|
48
|
+
columns ||= []
|
49
|
+
if columns.length >= n_columns
|
50
|
+
columns[0, n_columns]
|
51
|
+
else
|
52
|
+
columns + columns.length.upto(n_columns - 1).map {|i| "X#{i}" }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Charty
|
2
|
+
module TableAdapters
|
3
|
+
class NMatrixAdapter
|
4
|
+
TableAdapters.register(:nmatrix, self)
|
5
|
+
|
6
|
+
def self.supported?(data)
|
7
|
+
defined?(NMatrix) && data.is_a?(NMatrix) && data.shape.length <= 2
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(data, columns: nil)
|
11
|
+
case data.shape.length
|
12
|
+
when 1
|
13
|
+
data = data.reshape(data.size, 1)
|
14
|
+
when 2
|
15
|
+
# do nothing
|
16
|
+
else
|
17
|
+
raise ArgumentError, "Unsupported data format"
|
18
|
+
end
|
19
|
+
@data = data
|
20
|
+
@column_names = generate_column_names(data.shape[1], columns)
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :column_names
|
24
|
+
|
25
|
+
def [](row, column)
|
26
|
+
if row
|
27
|
+
@data[row, resolve_column_index(column)]
|
28
|
+
else
|
29
|
+
@data[:*, resolve_column_index(column)].reshape([@data.shape[0]])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private def resolve_column_index(column)
|
34
|
+
case column
|
35
|
+
when String, Symbol
|
36
|
+
index = column_names.index(column.to_s)
|
37
|
+
return index if index
|
38
|
+
raise IndexError, "invalid column name: #{column}"
|
39
|
+
when Integer
|
40
|
+
column
|
41
|
+
else
|
42
|
+
message = "column must be String or Integer: #{column.inspect}"
|
43
|
+
raise ArgumentError, message
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private def generate_column_names(n_columns, columns)
|
48
|
+
columns ||= []
|
49
|
+
if columns.length >= n_columns
|
50
|
+
columns[0, n_columns]
|
51
|
+
else
|
52
|
+
columns + columns.length.upto(n_columns - 1).map {|i| "X#{i}" }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
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.
|
4
|
+
version: 0.2.0
|
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: 2019-
|
13
|
+
date: 2019-09-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
@@ -54,6 +54,90 @@ dependencies:
|
|
54
54
|
- - ">="
|
55
55
|
- !ruby/object:Gem::Version
|
56
56
|
version: '0'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: numo-narray
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: nmatrix
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: red-datasets
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: 0.0.9
|
92
|
+
type: :development
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: 0.0.9
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
name: daru
|
101
|
+
requirement: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
type: :development
|
107
|
+
prerelease: false
|
108
|
+
version_requirements: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: activerecord
|
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'
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
name: sqlite3
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
57
141
|
- !ruby/object:Gem::Dependency
|
58
142
|
name: matplotlib
|
59
143
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,23 +178,30 @@ files:
|
|
94
178
|
- examples/iris_dataset.ipynb
|
95
179
|
- examples/nmatrix.ipynb
|
96
180
|
- examples/numo-narray.ipynb
|
181
|
+
- examples/sample_bokeh.ipynb
|
97
182
|
- examples/sample_google_chart.ipynb
|
98
183
|
- examples/sample_gruff.ipynb
|
184
|
+
- examples/sample_images/bar_bokeh.html
|
99
185
|
- examples/sample_images/bar_gruff.png
|
100
186
|
- examples/sample_images/bar_pyplot.png
|
101
187
|
- examples/sample_images/bar_rubyplot.png
|
188
|
+
- examples/sample_images/barh_bokeh.html
|
102
189
|
- examples/sample_images/barh_gruff.png
|
103
190
|
- examples/sample_images/barh_pyplot.png
|
191
|
+
- examples/sample_images/box_plot_bokeh.html
|
104
192
|
- examples/sample_images/box_plot_pyplot.png
|
105
193
|
- examples/sample_images/bubble_pyplot.png
|
106
194
|
- examples/sample_images/bubble_rubyplot.png
|
195
|
+
- examples/sample_images/curve_bokeh.html
|
107
196
|
- examples/sample_images/curve_gruff.png
|
108
197
|
- examples/sample_images/curve_pyplot.png
|
109
198
|
- examples/sample_images/curve_rubyplot.png
|
199
|
+
- examples/sample_images/curve_with_function_bokeh.html
|
110
200
|
- examples/sample_images/curve_with_function_pyplot.png
|
111
201
|
- examples/sample_images/curve_with_function_rubyplot.png
|
112
202
|
- examples/sample_images/error_bar_pyplot.png
|
113
203
|
- examples/sample_images/hist_pyplot.png
|
204
|
+
- examples/sample_images/scatter_bokeh.html
|
114
205
|
- examples/sample_images/scatter_gruff.png
|
115
206
|
- examples/sample_images/scatter_pyplot.png
|
116
207
|
- examples/sample_images/scatter_rubyplot.png
|
@@ -120,16 +211,24 @@ files:
|
|
120
211
|
- examples/sample_rubyplot.ipynb
|
121
212
|
- images/design_concept.png
|
122
213
|
- lib/charty.rb
|
214
|
+
- lib/charty/backends.rb
|
123
215
|
- lib/charty/backends/bokeh.rb
|
124
216
|
- lib/charty/backends/google_chart.rb
|
125
217
|
- lib/charty/backends/gruff.rb
|
218
|
+
- lib/charty/backends/plotly.rb
|
126
219
|
- lib/charty/backends/pyplot.rb
|
127
220
|
- lib/charty/backends/rubyplot.rb
|
128
221
|
- lib/charty/layout.rb
|
129
222
|
- lib/charty/linspace.rb
|
130
223
|
- lib/charty/plotter.rb
|
131
|
-
- lib/charty/plotter_adapter.rb
|
132
224
|
- lib/charty/table.rb
|
225
|
+
- lib/charty/table_adapters.rb
|
226
|
+
- lib/charty/table_adapters/active_record_adapter.rb
|
227
|
+
- lib/charty/table_adapters/daru_adapter.rb
|
228
|
+
- lib/charty/table_adapters/datasets_adapter.rb
|
229
|
+
- lib/charty/table_adapters/hash_adapter.rb
|
230
|
+
- lib/charty/table_adapters/narray_adapter.rb
|
231
|
+
- lib/charty/table_adapters/nmatrix_adapter.rb
|
133
232
|
- lib/charty/version.rb
|
134
233
|
homepage: https://github.com/red-data-tools/charty
|
135
234
|
licenses:
|
@@ -146,9 +245,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
146
245
|
version: '0'
|
147
246
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
148
247
|
requirements:
|
149
|
-
- - "
|
248
|
+
- - ">="
|
150
249
|
- !ruby/object:Gem::Version
|
151
|
-
version:
|
250
|
+
version: '0'
|
152
251
|
requirements: []
|
153
252
|
rubygems_version: 3.0.3
|
154
253
|
signing_key:
|