charty 0.2.0 → 0.2.6

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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +71 -0
  3. data/.github/workflows/nmatrix.yml +67 -0
  4. data/.github/workflows/pycall.yml +86 -0
  5. data/Dockerfile.dev +9 -1
  6. data/Gemfile +18 -0
  7. data/README.md +177 -9
  8. data/Rakefile +4 -5
  9. data/charty.gemspec +10 -4
  10. data/examples/Gemfile +1 -0
  11. data/examples/active_record.ipynb +1 -1
  12. data/examples/daru.ipynb +1 -1
  13. data/examples/iris_dataset.ipynb +1 -1
  14. data/examples/nmatrix.ipynb +1 -1
  15. data/examples/{numo-narray.ipynb → numo_narray.ipynb} +1 -1
  16. data/examples/palette.rb +71 -0
  17. data/examples/sample.png +0 -0
  18. data/examples/sample_images/hist_gruff.png +0 -0
  19. data/examples/sample_pyplot.ipynb +40 -38
  20. data/images/penguins_body_mass_g_flipper_length_mm_scatter_plot.png +0 -0
  21. data/images/penguins_body_mass_g_flipper_length_mm_species_scatter_plot.png +0 -0
  22. data/images/penguins_body_mass_g_flipper_length_mm_species_sex_scatter_plot.png +0 -0
  23. data/images/penguins_species_body_mass_g_bar_plot_h.png +0 -0
  24. data/images/penguins_species_body_mass_g_bar_plot_v.png +0 -0
  25. data/images/penguins_species_body_mass_g_box_plot_h.png +0 -0
  26. data/images/penguins_species_body_mass_g_box_plot_v.png +0 -0
  27. data/images/penguins_species_body_mass_g_sex_bar_plot_v.png +0 -0
  28. data/images/penguins_species_body_mass_g_sex_box_plot_v.png +0 -0
  29. data/lib/charty.rb +13 -1
  30. data/lib/charty/backend_methods.rb +8 -0
  31. data/lib/charty/backends.rb +26 -1
  32. data/lib/charty/backends/bokeh.rb +31 -31
  33. data/lib/charty/backends/{google_chart.rb → google_charts.rb} +75 -33
  34. data/lib/charty/backends/gruff.rb +14 -3
  35. data/lib/charty/backends/plotly.rb +774 -9
  36. data/lib/charty/backends/pyplot.rb +611 -34
  37. data/lib/charty/backends/rubyplot.rb +2 -2
  38. data/lib/charty/backends/unicode_plot.rb +79 -0
  39. data/lib/charty/dash_pattern_generator.rb +57 -0
  40. data/lib/charty/index.rb +213 -0
  41. data/lib/charty/linspace.rb +1 -1
  42. data/lib/charty/plot_methods.rb +254 -0
  43. data/lib/charty/plotter.rb +10 -10
  44. data/lib/charty/plotters.rb +12 -0
  45. data/lib/charty/plotters/abstract_plotter.rb +243 -0
  46. data/lib/charty/plotters/bar_plotter.rb +201 -0
  47. data/lib/charty/plotters/box_plotter.rb +79 -0
  48. data/lib/charty/plotters/categorical_plotter.rb +380 -0
  49. data/lib/charty/plotters/count_plotter.rb +7 -0
  50. data/lib/charty/plotters/estimation_support.rb +84 -0
  51. data/lib/charty/plotters/line_plotter.rb +300 -0
  52. data/lib/charty/plotters/random_support.rb +25 -0
  53. data/lib/charty/plotters/relational_plotter.rb +635 -0
  54. data/lib/charty/plotters/scatter_plotter.rb +80 -0
  55. data/lib/charty/plotters/vector_plotter.rb +6 -0
  56. data/lib/charty/statistics.rb +114 -0
  57. data/lib/charty/table.rb +161 -15
  58. data/lib/charty/table_adapters.rb +2 -0
  59. data/lib/charty/table_adapters/active_record_adapter.rb +17 -9
  60. data/lib/charty/table_adapters/base_adapter.rb +166 -0
  61. data/lib/charty/table_adapters/daru_adapter.rb +41 -3
  62. data/lib/charty/table_adapters/datasets_adapter.rb +17 -2
  63. data/lib/charty/table_adapters/hash_adapter.rb +143 -16
  64. data/lib/charty/table_adapters/narray_adapter.rb +25 -6
  65. data/lib/charty/table_adapters/nmatrix_adapter.rb +15 -5
  66. data/lib/charty/table_adapters/pandas_adapter.rb +163 -0
  67. data/lib/charty/util.rb +28 -0
  68. data/lib/charty/vector.rb +69 -0
  69. data/lib/charty/vector_adapters.rb +187 -0
  70. data/lib/charty/vector_adapters/array_adapter.rb +101 -0
  71. data/lib/charty/vector_adapters/daru_adapter.rb +163 -0
  72. data/lib/charty/vector_adapters/narray_adapter.rb +182 -0
  73. data/lib/charty/vector_adapters/nmatrix_adapter.rb +37 -0
  74. data/lib/charty/vector_adapters/numpy_adapter.rb +168 -0
  75. data/lib/charty/vector_adapters/pandas_adapter.rb +199 -0
  76. data/lib/charty/version.rb +1 -1
  77. metadata +121 -22
  78. data/.travis.yml +0 -10
@@ -23,7 +23,7 @@ module Charty
23
23
  end
24
24
 
25
25
  def render_layout(layout)
26
- (fig, axes) = *@plot.subplots(nrows: layout.num_rows, ncols: layout.num_cols)
26
+ (_fig, axes) = *@plot.subplots(nrows: layout.num_rows, ncols: layout.num_cols)
27
27
  layout.rows.each_with_index do |row, y|
28
28
  row.each_with_index do |cel, x|
29
29
  plot = layout.num_rows > 1 ? axes[y][x] : axes[x]
@@ -33,7 +33,7 @@ module Charty
33
33
  @plot.show
34
34
  end
35
35
 
36
- def render(context, filename="")
36
+ def old_style_render(context, filename="")
37
37
  FileUtils.mkdir_p(File.dirname(filename))
38
38
  plot(@plot, context).write(filename)
39
39
  end
@@ -0,0 +1,79 @@
1
+ require 'stringio'
2
+
3
+ module Charty
4
+ module Backends
5
+ class UnicodePlot
6
+ Backends.register(:unicode_plot, self)
7
+
8
+ class << self
9
+ def prepare
10
+ require 'unicode_plot'
11
+ end
12
+ end
13
+
14
+ def begin_figure
15
+ @figure = nil
16
+ @layout = {}
17
+ end
18
+
19
+ def bar(bar_pos, values, color: nil)
20
+ @figure = {
21
+ type: :bar,
22
+ bar_pos: bar_pos,
23
+ values: values
24
+ }
25
+ end
26
+
27
+ def box_plot(plot_data, positions, color:, gray:)
28
+ @figure = { type: :box, data: plot_data }
29
+ end
30
+
31
+ def set_xlabel(label)
32
+ @layout[:xlabel] = label
33
+ end
34
+
35
+ def set_ylabel(label)
36
+ @layout[:ylabel] = label
37
+ end
38
+
39
+ def set_xticks(values)
40
+ @layout[:xticks] = values
41
+ end
42
+
43
+ def set_xtick_labels(values)
44
+ @layout[:xtick_labels] = values
45
+ end
46
+
47
+ def set_xlim(min, max)
48
+ @layout[:xlim] = [min, max]
49
+ end
50
+
51
+ def disable_xaxis_grid
52
+ # do nothing
53
+ end
54
+
55
+ def show
56
+ case @figure[:type]
57
+ when :bar
58
+ plot = ::UnicodePlot.barplot(@layout[:xtick_labels], @figure[:values], xlabel: @layout[:xlabel])
59
+ when :box
60
+ plot = ::UnicodePlot.boxplot(@layout[:xtick_labels], @figure[:data], xlabel: @layout[:xlabel])
61
+ end
62
+ sio = StringIO.new
63
+ class << sio
64
+ def tty?; true; end
65
+ end
66
+ plot.render(sio)
67
+ sio.string
68
+ end
69
+
70
+ private
71
+
72
+ def show_bar(sio, figure, i)
73
+ end
74
+
75
+ def show_box(sio, figure, i)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,57 @@
1
+ module Charty
2
+ module DashPatternGenerator
3
+ NAMED_PATTERNS = {
4
+ solid: "",
5
+ dash: [4, 1.5],
6
+ dot: [1, 1],
7
+ dashdot: [3, 1.25, 1.5, 1.25],
8
+ longdashdot: [5, 1, 1, 1],
9
+ }.freeze
10
+
11
+ def self.valid_name?(name)
12
+ name = case name
13
+ when Symbol, String
14
+ name.to_sym
15
+ else
16
+ name.to_str.to_sym
17
+ end
18
+ NAMED_PATTERNS.key?(name)
19
+ end
20
+
21
+ def self.pattern_to_name(pattern)
22
+ NAMED_PATTERNS.each do |key, val|
23
+ return key if pattern == val
24
+ end
25
+ nil
26
+ end
27
+
28
+ def self.each
29
+ return enum_for(__method__) unless block_given?
30
+
31
+ NAMED_PATTERNS.each_value do |pattern|
32
+ yield pattern
33
+ end
34
+
35
+ m = 3
36
+ while true
37
+ # Long and short dash combinations
38
+ a = [3, 1.25].repeated_combination(m).to_a[1..-2].reverse
39
+ b = [4, 1].repeated_combination(m).to_a[1..-2]
40
+
41
+ # Interleave these combinations
42
+ segment_list = a.zip(b).flatten(1)
43
+
44
+ # Insert the gaps
45
+ segment_list.each do |segment|
46
+ gap = segment.min
47
+ pattern = segment.map {|seg| [seg, gap] }.flatten
48
+ yield pattern
49
+ end
50
+
51
+ m += 1
52
+ end
53
+ end
54
+
55
+ extend Enumerable
56
+ end
57
+ end
@@ -0,0 +1,213 @@
1
+ require "forwardable"
2
+
3
+ module Charty
4
+ class Index
5
+ extend Forwardable
6
+ include Enumerable
7
+
8
+ def initialize(values, name: nil)
9
+ @values = values
10
+ @name = name
11
+ end
12
+
13
+ attr_reader :values
14
+ attr_accessor :name
15
+
16
+ def_delegators :values, :length, :size, :each, :to_a
17
+
18
+ def ==(other)
19
+ case other
20
+ when DaruIndex, PandasIndex
21
+ return false if length != other.length
22
+ to_a == other.to_a
23
+ when Index
24
+ return false if length != other.length
25
+ return true if values == other.values
26
+ to_a == other.to_a
27
+ else
28
+ super
29
+ end
30
+ end
31
+
32
+ def [](i)
33
+ case i
34
+ when 0 ... length
35
+ values[i]
36
+ else
37
+ raise IndexError, "index out of range"
38
+ end
39
+ end
40
+
41
+ def loc(key)
42
+ values.index(key)
43
+ end
44
+
45
+ def union(other)
46
+ case other
47
+ when PandasIndex
48
+ index = PandasIndex.try_convert(self)
49
+ return index.union(other) if index
50
+ end
51
+
52
+ Index.new(to_a.union(other.to_a), name: name)
53
+ end
54
+ end
55
+
56
+ class RangeIndex < Index
57
+ def initialize(values, name: nil)
58
+ if values.is_a?(Range) && values.begin.is_a?(Integer) && values.end.is_a?(Integer)
59
+ super
60
+ else
61
+ raise ArgumentError, "values must be an integer range"
62
+ end
63
+ end
64
+
65
+ def length
66
+ size
67
+ end
68
+
69
+ def [](i)
70
+ case i
71
+ when 0 ... length
72
+ values.begin + i
73
+ else
74
+ raise IndexError, "index out of range (#{i} for 0 ... #{length})"
75
+ end
76
+ end
77
+
78
+ def loc(key)
79
+ case key
80
+ when Integer
81
+ if values.cover?(key)
82
+ return key - values.begin
83
+ end
84
+ end
85
+ end
86
+
87
+ def union(other)
88
+ case other
89
+ when RangeIndex
90
+ return union(other.values)
91
+ when Range
92
+ if disjoint_range?(values, other)
93
+ return Index.new(values.to_a.union(other.to_a))
94
+ end
95
+ new_beg = [values.begin, other.begin].min
96
+ new_end = [values.end, other.end ].max
97
+ new_range = if values.end < new_end
98
+ if other.exclude_end?
99
+ new_beg ... new_end
100
+ else
101
+ new_beg .. new_end
102
+ end
103
+ elsif other.end < new_end
104
+ if values.exclude_end?
105
+ new_beg ... new_end
106
+ else
107
+ new_beg .. new_end
108
+ end
109
+ else
110
+ if values.exclude_end? && other.exclude_end?
111
+ new_beg ... new_end
112
+ else
113
+ new_beg .. new_end
114
+ end
115
+ end
116
+ RangeIndex.new(new_range)
117
+ else
118
+ super
119
+ end
120
+ end
121
+
122
+ private def disjoint_range?(r1, r2)
123
+ r1.end < r2.begin || r2.end < r1.begin
124
+ end
125
+ end
126
+
127
+ class DaruIndex < Index
128
+ def_delegators :values, :name, :name=
129
+
130
+ def length
131
+ size
132
+ end
133
+
134
+ def ==(other)
135
+ case other
136
+ when DaruIndex
137
+ values == other.values
138
+ else
139
+ super
140
+ end
141
+ end
142
+ end
143
+
144
+ class PandasIndex < Index
145
+ def self.try_convert(obj)
146
+ case obj
147
+ when PandasIndex
148
+ obj
149
+ when ->(x) { defined?(Pandas) && x.is_a?(Pandas::Index) }
150
+ PandasIndex.new(obj)
151
+ when RangeIndex, Range
152
+ obj = obj.values if obj.is_a?(RangeIndex)
153
+ stop = if obj.exclude_end?
154
+ obj.end
155
+ else
156
+ obj.end + 1
157
+ end
158
+ PandasIndex.new(Pandas.RangeIndex.new(obj.begin, stop))
159
+ when ->(x) { defined?(Enumerator::ArithmeticSequence) && x.is_a?(Enumerator::ArithmeticSequence) }
160
+ stop = if obj.exclude_end?
161
+ obj.end
162
+ else
163
+ obj.end + 1
164
+ end
165
+ PandasIndex.new(Pandas::RangeIndex.new(obj.begin, stop, obj.step))
166
+ when Index, Array, DaruIndex, ->(x) { defined?(Daru) && x.is_a?(Daru::Index) }
167
+ obj = obj.values if obj.is_a?(Index)
168
+ PandasIndex.new(Pandas::Index.new(obj.to_a))
169
+ else
170
+ nil
171
+ end
172
+ end
173
+
174
+ def_delegators :values, :name, :name=
175
+
176
+ def length
177
+ size
178
+ end
179
+
180
+ def ==(other)
181
+ case other
182
+ when PandasIndex
183
+ Numpy.all(values == other.values)
184
+ when Index
185
+ return false if length != other.length
186
+ Numpy.all(values == other.values.to_a)
187
+ else
188
+ super
189
+ end
190
+ end
191
+
192
+ def each(&block)
193
+ return enum_for(__method__) unless block_given?
194
+
195
+ i, n = 0, length
196
+ while i < n
197
+ yield self[i]
198
+ i += 1
199
+ end
200
+ end
201
+
202
+ def union(other)
203
+ other = PandasIndex.try_convert(other)
204
+ # NOTE: Using `sort=False` in pandas.Index#union does not produce pandas.RangeIndex.
205
+ # TODO: Reconsider to use `sort=True` here.
206
+ PandasIndex.new(values.union(other.values, sort: false))
207
+ end
208
+
209
+ private def arithmetic_sequence?(x)
210
+ defined?(Enumerator::ArithmeticSequence) && x.is_a?(Enumerator::ArithmeticSequence)
211
+ end
212
+ end
213
+ end
@@ -8,7 +8,7 @@ module Charty
8
8
  end
9
9
 
10
10
  def each(&block)
11
- step = (@range.end - @range.begin).to_f / @num_step
11
+ step = (@range.end - @range.begin).to_r / (@num_step - 1)
12
12
  (@num_step - 1).times do |i|
13
13
  block.call(@range.begin + i * step)
14
14
  end
@@ -0,0 +1,254 @@
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
+ # Line 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 dashes [true, false, Array, Hash]
149
+ # @param markers [true, false, Array, Hash]
150
+ # @param style_order [Array]
151
+ # @param units [vector-like object, key in data]
152
+ # @param estimator [:mean]
153
+ # @param n_boot [Integer]
154
+ # @param random [Integer, Random, nil]
155
+ # @param sort [true, false]
156
+ # @param err_style [:band, :bars]
157
+ # @param err_params [Hash]
158
+ # @param error_bar
159
+ # @param x_scale [:linear, :log10]
160
+ # @param y_scale [:linear, :log10]
161
+ # @param legend [:auto, :brief, :full, false]
162
+ # How to draw legend. If :brief, numeric color and size variables
163
+ # will be represented with a sample of evenly spaced values. If
164
+ # :full, every group will get an entry in the legend. If :auto,
165
+ # choose between brief or full representation based on number of
166
+ # levels. If false, no legend data is added and no legend is drawn.
167
+ def line_plot(x: nil, y: nil, color: nil, style: nil, size: nil,
168
+ data: nil, key_color: nil, palette: nil, color_order: nil,
169
+ color_norm: nil, sizes: nil, size_order: nil, size_norm: nil,
170
+ markers: nil, dashes: true, style_order: nil,
171
+ units: nil, estimator: :mean, n_boot: 1000, random: nil,
172
+ sort: true, err_style: :band, err_params: nil, error_bar: [:ci, 95],
173
+ x_scale: :linear, y_scale: :linear, legend: :auto, **options, &block)
174
+ Plotters::LinePlotter.new(
175
+ data: data,
176
+ variables: { x: x, y: y, color: color, style: style, size: size },
177
+ key_color: key_color,
178
+ palette: palette,
179
+ color_order: color_order,
180
+ color_norm: color_norm,
181
+ sizes: sizes,
182
+ size_order: size_order,
183
+ size_norm: size_norm,
184
+ markers: markers,
185
+ dashes: dashes,
186
+ style_order: style_order,
187
+ units: units,
188
+ estimator: estimator,
189
+ n_boot: n_boot,
190
+ random: random,
191
+ sort: sort,
192
+ err_style: err_style,
193
+ err_params: err_params,
194
+ error_bar: error_bar,
195
+ x_scale: x_scale,
196
+ y_scale: y_scale,
197
+ legend: legend,
198
+ **options,
199
+ &block
200
+ )
201
+ end
202
+
203
+ # Scatter plot
204
+ #
205
+ # @param x [vector-like object, key in data]
206
+ # @param y [vector-like object, key in data]
207
+ # @param color [vector-like object, key in data]
208
+ # @param style [vector-like object, key in data]
209
+ # @param size [vector-like object, key in data]
210
+ # @param data [table-like object]
211
+ # @param key_color [color object]
212
+ # @param palette [String,Array<Numeric>,Palette]
213
+ # @param color_order [Array<String>,Array<Symbol>]
214
+ # @param color_norm
215
+ # @param sizes [Array, Hash]
216
+ # @param size_order [Array]
217
+ # @param size_norm
218
+ # @param markers [true, false, Array, Hash]
219
+ # @param style_order [Array]
220
+ # @param alpha [scalar number]
221
+ # Propotional opacity of the points.
222
+ # @param legend [:auto, :brief, :full, false]
223
+ # How to draw legend. If :brief, numeric color and size variables
224
+ # will be represented with a sample of evenly spaced values. If
225
+ # :full, every group will get an entry in the legend. If :auto,
226
+ # choose between brief or full representation based on number of
227
+ # levels. If false, no legend data is added and no legend is drawn.
228
+ def scatter_plot(x: nil, y: nil, color: nil, style: nil, size: nil,
229
+ data: nil, key_color: nil, palette: nil, color_order: nil,
230
+ color_norm: nil, sizes: nil, size_order: nil, size_norm: nil,
231
+ markers: true, style_order: nil, alpha: nil, legend: :auto,
232
+ **options, &block)
233
+ Plotters::ScatterPlotter.new(
234
+ data: data,
235
+ variables: { x: x, y: y, color: color, style: style, size: size },
236
+ key_color: key_color,
237
+ palette: palette,
238
+ color_order: color_order,
239
+ color_norm: color_norm,
240
+ sizes: sizes,
241
+ size_order: size_order,
242
+ size_norm: size_norm,
243
+ markers: markers,
244
+ style_order: style_order,
245
+ alpha: alpha,
246
+ legend: legend,
247
+ **options,
248
+ &block
249
+ )
250
+ end
251
+ end
252
+
253
+ extend PlotMethods
254
+ end