charty 0.1.5.dev → 0.2.5
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/.github/workflows/ci.yml +71 -0
- data/.github/workflows/nmatrix.yml +67 -0
- data/.github/workflows/pycall.yml +86 -0
- data/Dockerfile.dev +9 -1
- data/Gemfile +18 -0
- data/README.md +176 -9
- data/Rakefile +4 -5
- data/charty.gemspec +10 -1
- data/examples/Gemfile +1 -0
- data/examples/active_record.ipynb +1 -1
- data/examples/daru.ipynb +1 -1
- data/examples/iris_dataset.ipynb +1 -1
- data/examples/nmatrix.ipynb +1 -1
- data/examples/{numo-narray.ipynb → numo_narray.ipynb} +1 -1
- data/examples/palette.rb +71 -0
- data/examples/sample.png +0 -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/hist_gruff.png +0 -0
- data/examples/sample_images/scatter_bokeh.html +85 -0
- data/examples/sample_pyplot.ipynb +40 -38
- data/images/penguins_body_mass_g_flipper_length_mm_scatter_plot.png +0 -0
- data/images/penguins_body_mass_g_flipper_length_mm_species_scatter_plot.png +0 -0
- data/images/penguins_body_mass_g_flipper_length_mm_species_sex_scatter_plot.png +0 -0
- data/images/penguins_species_body_mass_g_bar_plot_h.png +0 -0
- data/images/penguins_species_body_mass_g_bar_plot_v.png +0 -0
- data/images/penguins_species_body_mass_g_box_plot_h.png +0 -0
- data/images/penguins_species_body_mass_g_box_plot_v.png +0 -0
- data/images/penguins_species_body_mass_g_sex_bar_plot_v.png +0 -0
- data/images/penguins_species_body_mass_g_sex_box_plot_v.png +0 -0
- data/lib/charty.rb +14 -1
- data/lib/charty/backend_methods.rb +8 -0
- data/lib/charty/backends.rb +80 -0
- data/lib/charty/backends/bokeh.rb +32 -26
- data/lib/charty/backends/google_charts.rb +267 -0
- data/lib/charty/backends/gruff.rb +102 -83
- data/lib/charty/backends/plotly.rb +685 -0
- data/lib/charty/backends/pyplot.rb +586 -92
- data/lib/charty/backends/rubyplot.rb +82 -74
- data/lib/charty/backends/unicode_plot.rb +79 -0
- data/lib/charty/index.rb +213 -0
- data/lib/charty/linspace.rb +1 -1
- data/lib/charty/missing_value_support.rb +14 -0
- data/lib/charty/plot_methods.rb +184 -0
- data/lib/charty/plotter.rb +48 -40
- data/lib/charty/plotters.rb +11 -0
- data/lib/charty/plotters/abstract_plotter.rb +183 -0
- data/lib/charty/plotters/bar_plotter.rb +201 -0
- data/lib/charty/plotters/box_plotter.rb +79 -0
- data/lib/charty/plotters/categorical_plotter.rb +380 -0
- data/lib/charty/plotters/count_plotter.rb +7 -0
- data/lib/charty/plotters/estimation_support.rb +84 -0
- data/lib/charty/plotters/random_support.rb +25 -0
- data/lib/charty/plotters/relational_plotter.rb +518 -0
- data/lib/charty/plotters/scatter_plotter.rb +104 -0
- data/lib/charty/plotters/vector_plotter.rb +6 -0
- data/lib/charty/statistics.rb +114 -0
- data/lib/charty/table.rb +80 -3
- data/lib/charty/table_adapters.rb +25 -0
- data/lib/charty/table_adapters/active_record_adapter.rb +63 -0
- data/lib/charty/table_adapters/base_adapter.rb +69 -0
- data/lib/charty/table_adapters/daru_adapter.rb +70 -0
- data/lib/charty/table_adapters/datasets_adapter.rb +49 -0
- data/lib/charty/table_adapters/hash_adapter.rb +224 -0
- data/lib/charty/table_adapters/narray_adapter.rb +76 -0
- data/lib/charty/table_adapters/nmatrix_adapter.rb +67 -0
- data/lib/charty/table_adapters/pandas_adapter.rb +81 -0
- data/lib/charty/util.rb +20 -0
- data/lib/charty/vector.rb +69 -0
- data/lib/charty/vector_adapters.rb +183 -0
- data/lib/charty/vector_adapters/array_adapter.rb +109 -0
- data/lib/charty/vector_adapters/daru_adapter.rb +171 -0
- data/lib/charty/vector_adapters/narray_adapter.rb +187 -0
- data/lib/charty/vector_adapters/nmatrix_adapter.rb +37 -0
- data/lib/charty/vector_adapters/numpy_adapter.rb +168 -0
- data/lib/charty/vector_adapters/pandas_adapter.rb +200 -0
- data/lib/charty/version.rb +1 -1
- metadata +179 -10
- data/.travis.yml +0 -11
- data/lib/charty/backends/google_chart.rb +0 -167
- data/lib/charty/plotter_adapter.rb +0 -17
data/lib/charty/linspace.rb
CHANGED
@@ -0,0 +1,184 @@
|
|
1
|
+
module Charty
|
2
|
+
module PlotMethods
|
3
|
+
# Show the given data as rectangular bars.
|
4
|
+
#
|
5
|
+
# @param x x-dimension input for plotting long-form data.
|
6
|
+
# @param y y-dimension input for plotting long-form data.
|
7
|
+
# @param color color-dimension input for plotting long-form data.
|
8
|
+
# @param data Dataset for plotting.
|
9
|
+
# @param order Order of the categorical dimension to plot the categorical levels in.
|
10
|
+
# @param color_order Order of the color dimension to plot the categorical levels in.
|
11
|
+
# @param estimator Statistical function to estimate withint each categorical bin.
|
12
|
+
# @param ci Size of confidence intervals to draw around estimated values.
|
13
|
+
# @param n_boot The size of bootstrap sample to use when computing confidence intervals.
|
14
|
+
# @param units Identifier of sampling unit.
|
15
|
+
# @param random Random seed or random number generator for reproducible bootstrapping.
|
16
|
+
# @param orient Orientation of the plot (:v for vertical, or :h for
|
17
|
+
# horizontal).
|
18
|
+
# @param key_color Color for all of the elements, or seed for a gradient palette.
|
19
|
+
# @param palette Colors to use for the different levels of the color-dimension variable.
|
20
|
+
# @param saturation Propotion of the original saturation to draw colors.
|
21
|
+
# @param error_color Color for the lines that represent the confidence intervals.
|
22
|
+
# @param error_width Thickness of error bar lines (and caps).
|
23
|
+
# @param cap_size Width of the caps on error bars.
|
24
|
+
# @param dodge [true,false] If true, bar position is shifted along the
|
25
|
+
# categorical axis for avoid overlapping when the color-dimension is used.
|
26
|
+
def bar_plot(x: nil, y: nil, color: nil, data: nil,
|
27
|
+
order: nil, color_order: nil,
|
28
|
+
estimator: :mean, ci: 95, n_boot: 1000, units: nil, random: nil,
|
29
|
+
orient: nil, key_color: nil, palette: nil, saturation: 1r,
|
30
|
+
error_color: [0.26, 0.26, 0.26], error_width: nil, cap_size: nil,
|
31
|
+
dodge: true, **options, &block)
|
32
|
+
Plotters::BarPlotter.new(
|
33
|
+
data: data, variables: { x: x, y: y, color: color },
|
34
|
+
order: order, orient: orient,
|
35
|
+
estimator: estimator, ci: ci, n_boot: n_boot, units: units, random: random,
|
36
|
+
color_order: color_order, key_color: key_color, palette: palette, saturation: saturation,
|
37
|
+
error_color: error_color, error_width: error_width, cap_size: cap_size,
|
38
|
+
dodge: dodge,
|
39
|
+
**options, &block
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def count_plot(x: nil, y: nil, color: nil, data: nil,
|
44
|
+
order: nil, color_order: nil,
|
45
|
+
orient: nil, key_color: nil, palette: nil, saturation: 1r,
|
46
|
+
dodge: true, **options, &block)
|
47
|
+
case
|
48
|
+
when x.nil? && !y.nil?
|
49
|
+
x = y
|
50
|
+
orient = :h
|
51
|
+
when y.nil? && !x.nil?
|
52
|
+
y = x
|
53
|
+
orient = :v
|
54
|
+
when !x.nil? && !y.nil?
|
55
|
+
raise ArgumentError,
|
56
|
+
"Unable to pass both x and y to count_plot"
|
57
|
+
end
|
58
|
+
|
59
|
+
Plotters::CountPlotter.new(
|
60
|
+
data: data,
|
61
|
+
variables: { x: x, y: y, color: color },
|
62
|
+
order: order,
|
63
|
+
orient: orient,
|
64
|
+
estimator: :count,
|
65
|
+
ci: nil,
|
66
|
+
units: nil,
|
67
|
+
random: nil,
|
68
|
+
color_order: color_order,
|
69
|
+
key_color: key_color,
|
70
|
+
palette: palette,
|
71
|
+
saturation: saturation,
|
72
|
+
dodge: dodge,
|
73
|
+
**options
|
74
|
+
) do |plotter|
|
75
|
+
plotter.value_label = "count"
|
76
|
+
block.(plotter) unless block.nil?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Show the distributions of the given data by boxes and whiskers.
|
81
|
+
#
|
82
|
+
# @param x X-dimension input for plotting long-Form data.
|
83
|
+
# @param y Y-dimension input for plotting long-form data.
|
84
|
+
# @param color Color-dimension input for plotting long-form data.
|
85
|
+
# @param data Dataset for plotting.
|
86
|
+
# @param order Order of the categorical dimension to plot the categorical
|
87
|
+
# levels in.
|
88
|
+
# @param color_order Order of the color dimension to plot the categorical
|
89
|
+
# levels in.
|
90
|
+
# @param orient Orientation of the plot (:v for vertical, or :h for
|
91
|
+
# horizontal).
|
92
|
+
# @param key_color Color for all of the elements, or seed for a gradient
|
93
|
+
# palette.
|
94
|
+
# @param palette Colors to use for the different levels of the
|
95
|
+
# color-dimension variable.
|
96
|
+
# @param saturation Propotion of the original saturation to draw colors.
|
97
|
+
# @param width Width of a full element when not using the color-dimension,
|
98
|
+
# or width of all the elements for one level of the major grouping
|
99
|
+
# variable.
|
100
|
+
# @param dodge [true,false] If true, bar position is shifted along the
|
101
|
+
# categorical axis for avoid overlapping when the color-dimension
|
102
|
+
# is used.
|
103
|
+
# @param flier_size Size of the markers used to indicate outlier
|
104
|
+
# observations.
|
105
|
+
# @param line_width Width of the gray lines that frame the plot elements.
|
106
|
+
# @param whisker Propotion of the IQR past the low and high quartiles to
|
107
|
+
# extend the plot whiskers. Points outside of this range will be
|
108
|
+
# treated as outliers.
|
109
|
+
def box_plot(x: nil, y: nil, color: nil, data: nil,
|
110
|
+
order: nil, color_order: nil,
|
111
|
+
orient: nil, key_color: nil, palette: nil, saturation: 1r,
|
112
|
+
width: 0.8r, dodge: true, flier_size: 5, line_width: nil,
|
113
|
+
whisker: 1.5, **options, &block)
|
114
|
+
Plotters::BoxPlotter.new(
|
115
|
+
data: data,
|
116
|
+
variables: { x: x, y: y, color: color },
|
117
|
+
order: order,
|
118
|
+
color_order: color_order,
|
119
|
+
orient: orient,
|
120
|
+
key_color: key_color,
|
121
|
+
palette: palette,
|
122
|
+
saturation: saturation,
|
123
|
+
width: width,
|
124
|
+
dodge: dodge,
|
125
|
+
flier_size: flier_size,
|
126
|
+
line_width: line_width,
|
127
|
+
whisker: whisker,
|
128
|
+
**options,
|
129
|
+
&block
|
130
|
+
)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Scatter plot
|
134
|
+
#
|
135
|
+
# @param x [vector-like object, key in data]
|
136
|
+
# @param y [vector-like object, key in data]
|
137
|
+
# @param color [vector-like object, key in data]
|
138
|
+
# @param style [vector-like object, key in data]
|
139
|
+
# @param size [vector-like object, key in data]
|
140
|
+
# @param data [table-like object]
|
141
|
+
# @param key_color [color object]
|
142
|
+
# @param palette [String,Array<Numeric>,Palette]
|
143
|
+
# @param color_order [Array<String>,Array<Symbol>]
|
144
|
+
# @param color_norm
|
145
|
+
# @param sizes [Array, Hash]
|
146
|
+
# @param size_order [Array]
|
147
|
+
# @param size_norm
|
148
|
+
# @param markers [true, false, Array, Hash]
|
149
|
+
# @param marker_order [Array]
|
150
|
+
# @param alpha [scalar number]
|
151
|
+
# Propotional opacity of the points.
|
152
|
+
# @param legend [:auto, :brief, :full, false]
|
153
|
+
# How to draw legend. If :brief, numeric color and size variables
|
154
|
+
# will be represented with a sample of evenly spaced values. If
|
155
|
+
# :full, every group will get an entry in the legend. If :auto,
|
156
|
+
# choose between brief or full representation based on number of
|
157
|
+
# levels. If false, no legend data is added and no legend is drawn.
|
158
|
+
def scatter_plot(x: nil, y: nil, color: nil, style: nil, size: nil,
|
159
|
+
data: nil, key_color: nil, palette: nil, color_order: nil,
|
160
|
+
color_norm: nil, sizes: nil, size_order: nil, size_norm: nil,
|
161
|
+
markers: true, marker_order: nil, alpha: nil, legend: :auto,
|
162
|
+
**options, &block)
|
163
|
+
Plotters::ScatterPlotter.new(
|
164
|
+
data: data,
|
165
|
+
variables: { x: x, y: y, color: color, style: style, size: size },
|
166
|
+
key_color: key_color,
|
167
|
+
palette: palette,
|
168
|
+
color_order: color_order,
|
169
|
+
color_norm: color_norm,
|
170
|
+
sizes: sizes,
|
171
|
+
size_order: size_order,
|
172
|
+
size_norm: size_norm,
|
173
|
+
markers: markers,
|
174
|
+
marker_order: marker_order,
|
175
|
+
alpha: alpha,
|
176
|
+
legend: legend,
|
177
|
+
**options,
|
178
|
+
&block
|
179
|
+
)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
extend PlotMethods
|
184
|
+
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,25 +237,25 @@ module Charty
|
|
229
237
|
end
|
230
238
|
|
231
239
|
def render(filename=nil)
|
232
|
-
@
|
240
|
+
@backend.old_style_render(self, filename)
|
233
241
|
end
|
234
242
|
|
235
|
-
def save(filename=nil)
|
236
|
-
@
|
243
|
+
def save(filename=nil, **kw)
|
244
|
+
@backend.old_style_save(self, filename, **kw)
|
237
245
|
end
|
238
246
|
|
239
|
-
def apply(
|
247
|
+
def apply(backend)
|
240
248
|
case
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
249
|
+
when !@series.empty?
|
250
|
+
backend.series = @series
|
251
|
+
when @function
|
252
|
+
linspace = Linspace.new(@range[:x], 100)
|
253
|
+
# TODO: set label with function
|
254
|
+
# TODO: set ys to xs when gruff curve with function
|
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
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative "plotters/abstract_plotter"
|
2
|
+
require_relative "plotters/random_support"
|
3
|
+
require_relative "plotters/estimation_support"
|
4
|
+
require_relative "plotters/categorical_plotter"
|
5
|
+
require_relative "plotters/bar_plotter"
|
6
|
+
require_relative "plotters/box_plotter"
|
7
|
+
require_relative "plotters/count_plotter"
|
8
|
+
|
9
|
+
require_relative "plotters/vector_plotter"
|
10
|
+
require_relative "plotters/relational_plotter"
|
11
|
+
require_relative "plotters/scatter_plotter"
|
@@ -0,0 +1,183 @@
|
|
1
|
+
module Charty
|
2
|
+
module Plotters
|
3
|
+
class AbstractPlotter
|
4
|
+
def initialize(x, y, color, **options)
|
5
|
+
self.x = x
|
6
|
+
self.y = y
|
7
|
+
self.color = color
|
8
|
+
self.data = data
|
9
|
+
self.palette = palette
|
10
|
+
substitute_options(options)
|
11
|
+
yield self if block_given?
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :data, :x, :y, :color
|
15
|
+
attr_reader :color_order, :key_color, :palette
|
16
|
+
|
17
|
+
def inspect
|
18
|
+
"#<#{self.class}:0x%016x>" % self.object_id
|
19
|
+
end
|
20
|
+
|
21
|
+
def data=(data)
|
22
|
+
@data = case data
|
23
|
+
when nil, Charty::Table
|
24
|
+
data
|
25
|
+
else
|
26
|
+
Charty::Table.new(data)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def x=(x)
|
31
|
+
@x = check_dimension(x, :x)
|
32
|
+
end
|
33
|
+
|
34
|
+
def y=(y)
|
35
|
+
@y = check_dimension(y, :y)
|
36
|
+
end
|
37
|
+
|
38
|
+
def color=(color)
|
39
|
+
@color = check_dimension(color, :color)
|
40
|
+
end
|
41
|
+
|
42
|
+
def color_order=(color_order)
|
43
|
+
#@color_order = XXX
|
44
|
+
unless color_order.nil?
|
45
|
+
raise NotImplementedError,
|
46
|
+
"Specifying color_order is not supported yet"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# TODO: move to categorical_plotter
|
51
|
+
def key_color=(key_color)
|
52
|
+
#@key_color = XXX
|
53
|
+
unless key_color.nil?
|
54
|
+
raise NotImplementedError,
|
55
|
+
"Specifying key_color is not supported yet"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def palette=(palette)
|
60
|
+
@palette = case palette
|
61
|
+
when nil, Palette, Symbol, String
|
62
|
+
palette
|
63
|
+
else
|
64
|
+
raise ArgumentError,
|
65
|
+
"invalid type for palette (given #{palette.class}, " +
|
66
|
+
"expected Palette, Symbol, or String)"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private def substitute_options(options)
|
71
|
+
options.each do |key, val|
|
72
|
+
send("#{key}=", val)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
private def check_dimension(value, name)
|
77
|
+
case value
|
78
|
+
when nil, Symbol, String
|
79
|
+
value
|
80
|
+
when ->(x) { x.respond_to?(:to_str) }
|
81
|
+
value.to_str
|
82
|
+
when method(:array?)
|
83
|
+
Charty::Vector.new(value)
|
84
|
+
else
|
85
|
+
raise ArgumentError,
|
86
|
+
"invalid type of dimension for #{name} (given #{value.inspect})",
|
87
|
+
caller
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private def check_number(value, name, allow_nil: false)
|
92
|
+
case value
|
93
|
+
when Numeric
|
94
|
+
value
|
95
|
+
else
|
96
|
+
if allow_nil && value.nil?
|
97
|
+
nil
|
98
|
+
else
|
99
|
+
expected = if allow_nil
|
100
|
+
"number or nil"
|
101
|
+
else
|
102
|
+
"number"
|
103
|
+
end
|
104
|
+
raise ArgumentError,
|
105
|
+
"invalid value for #{name} (%p for #{expected})" % value,
|
106
|
+
caller
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
private def check_boolean(value, name, allow_nil: false)
|
112
|
+
case value
|
113
|
+
when true, false
|
114
|
+
value
|
115
|
+
else
|
116
|
+
expected = if allow_nil
|
117
|
+
"true, false, or nil"
|
118
|
+
else
|
119
|
+
"true or false"
|
120
|
+
end
|
121
|
+
raise ArgumentError,
|
122
|
+
"invalid value for #{name} (%p for #{expected})" % value,
|
123
|
+
caller
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
private def variable_type(vector, boolean_type=:numeric)
|
128
|
+
if vector.numeric?
|
129
|
+
:numeric
|
130
|
+
elsif vector.categorical?
|
131
|
+
:categorical
|
132
|
+
else
|
133
|
+
case vector[0]
|
134
|
+
when true, false
|
135
|
+
boolean_type
|
136
|
+
else
|
137
|
+
:categorical
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
private def array?(value)
|
143
|
+
TableAdapters::HashAdapter.array?(value)
|
144
|
+
end
|
145
|
+
|
146
|
+
private def remove_na!(ary)
|
147
|
+
ary.reject! do |x|
|
148
|
+
next true if x.nil?
|
149
|
+
x.respond_to?(:nan?) && x.nan?
|
150
|
+
end
|
151
|
+
ary
|
152
|
+
end
|
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
|
+
|
173
|
+
def to_iruby
|
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
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|