rbplotly 0.1.2 → 1.0.1
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 +5 -5
- data/CHANGELOG.md +88 -0
- data/LICENSE.txt +1 -1
- data/README.md +213 -50
- data/lib/plotly/assets/plotly.min.js +3620 -0
- data/lib/plotly/attributes.rb +221 -0
- data/lib/plotly/figure.rb +292 -0
- data/lib/plotly/frames.rb +38 -0
- data/lib/plotly/html.rb +161 -0
- data/lib/plotly/plot.rb +11 -28
- data/lib/plotly/schema/plot-schema.json +57258 -0
- data/lib/plotly/schema.rb +99 -0
- data/lib/plotly/serializer.rb +49 -0
- data/lib/plotly/subplots.rb +186 -0
- data/lib/plotly/version.rb +7 -1
- data/lib/plotly.rb +22 -0
- data/lib/rbplotly.rb +3 -4
- metadata +35 -179
- data/.gitignore +0 -11
- data/.rspec +0 -2
- data/.rubocop.yml +0 -22
- data/.travis.yml +0 -9
- data/CODE_OF_CONDUCT.md +0 -49
- data/Gemfile +0 -4
- data/Guardfile +0 -12
- data/Rakefile +0 -9
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/docs/images/line_chart.png +0 -0
- data/examples/Bar Charts.ipynb +0 -254
- data/examples/Basic Usage.ipynb +0 -227
- data/examples/Histograms.ipynb +0 -79
- data/examples/Line charts.ipynb +0 -88
- data/examples/Pie Charts.ipynb +0 -151
- data/examples/Scatter Plots.ipynb +0 -224
- data/examples/heatmaps.ipynb +0 -150
- data/lib/plotly/axis.rb +0 -18
- data/lib/plotly/castable.rb +0 -20
- data/lib/plotly/client.rb +0 -45
- data/lib/plotly/data.rb +0 -33
- data/lib/plotly/exportable.rb +0 -23
- data/lib/plotly/layout.rb +0 -33
- data/lib/plotly/line.rb +0 -17
- data/lib/plotly/marker.rb +0 -23
- data/lib/plotly/offline/exportable.rb +0 -36
- data/lib/plotly/offline/html.rb +0 -46
- data/lib/plotly/offline/plotly.min.js +0 -59
- data/lib/plotly/offline/templates/body.erb +0 -26
- data/lib/plotly/offline/templates/plot.erb +0 -12
- data/lib/plotly/util.rb +0 -11
- data/rbplotly.gemspec +0 -35
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Plotly
|
|
6
|
+
# The attribute tree of the bundled plotly.js release, generated by `rake schema:generate`.
|
|
7
|
+
class Schema
|
|
8
|
+
# The generated schema file.
|
|
9
|
+
PATH = File.expand_path("schema/plot-schema.json", __dir__)
|
|
10
|
+
# Numbered subplot ids: xaxis2, scene3 (plotly.js has no xaxis1).
|
|
11
|
+
SUBPLOT_SUFFIX = /\A(?<base>[a-z]+?)(?<n>[2-9]|[1-9]\d+)\z/
|
|
12
|
+
|
|
13
|
+
# One attribute: an object with children, an array of objects, or a leaf value.
|
|
14
|
+
class Node
|
|
15
|
+
attr_reader :name
|
|
16
|
+
|
|
17
|
+
def initialize(name, spec)
|
|
18
|
+
@name = name
|
|
19
|
+
@spec = spec
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def object? = @spec.key?("attrs")
|
|
23
|
+
|
|
24
|
+
def array? = @spec.key?("array")
|
|
25
|
+
|
|
26
|
+
def leaf? = @spec.key?("type")
|
|
27
|
+
|
|
28
|
+
def subplot? = @spec["subplot"] == true
|
|
29
|
+
|
|
30
|
+
# @return [Array<String>] names of the children of an object
|
|
31
|
+
def attribute_names = @spec.fetch("attrs", {}).keys
|
|
32
|
+
|
|
33
|
+
# @return [Node, nil] the child attribute, or nil when plotly.js does not define it
|
|
34
|
+
def child(key)
|
|
35
|
+
attrs = @spec["attrs"] or return nil
|
|
36
|
+
key = key.to_s
|
|
37
|
+
return Node.new(key, attrs[key]) if attrs.key?(key)
|
|
38
|
+
|
|
39
|
+
match = SUBPLOT_SUFFIX.match(key) or return nil
|
|
40
|
+
base = attrs[match[:base]]
|
|
41
|
+
Node.new(key, base) if base&.fetch("subplot", false)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @return [Node] the schema of each element of an array of objects
|
|
45
|
+
def item = Node.new(name.sub(/s\z/, ""), @spec.fetch("array"))
|
|
46
|
+
|
|
47
|
+
# @return [String, nil] plotly.js value type of a leaf: "number", "enumerated", "color", ...
|
|
48
|
+
def type = @spec["type"]
|
|
49
|
+
|
|
50
|
+
# @return [Array] allowed values of an enumerated leaf; "/.../" strings are patterns
|
|
51
|
+
def values = @spec.fetch("values", [])
|
|
52
|
+
|
|
53
|
+
# @return [Array<String>] flags of a flaglist leaf, joined with "+"
|
|
54
|
+
def flags = @spec.fetch("flags", [])
|
|
55
|
+
|
|
56
|
+
# @return [Array<String>] flaglist values that stand alone, such as "none"
|
|
57
|
+
def extras = @spec.fetch("extras", [])
|
|
58
|
+
|
|
59
|
+
# Whether the leaf also accepts an array of values, one per point.
|
|
60
|
+
def array_ok? = @spec["array_ok"] == true
|
|
61
|
+
|
|
62
|
+
# @return [Numeric, nil] lower bound of a number leaf
|
|
63
|
+
def min = @spec["min"]
|
|
64
|
+
|
|
65
|
+
# @return [Numeric, nil] upper bound of a number leaf
|
|
66
|
+
def max = @spec["max"]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @return [Schema] the schema of the bundled plotly.js release, loaded once
|
|
70
|
+
def self.default
|
|
71
|
+
@default ||= new(JSON.parse(File.read(PATH)))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def initialize(raw)
|
|
75
|
+
@raw = raw
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# @return [String] the plotly.js release the schema was generated from
|
|
79
|
+
def plotly_js_version = @raw.fetch("plotly_js")
|
|
80
|
+
|
|
81
|
+
# @return [Array<String>] every trace type: "bar", "scatter", ...
|
|
82
|
+
def trace_types = @raw.fetch("traces").keys
|
|
83
|
+
|
|
84
|
+
# @return [Node, nil]
|
|
85
|
+
def trace(type)
|
|
86
|
+
spec = @raw.fetch("traces")[type.to_s]
|
|
87
|
+
Node.new(type.to_s, spec) if spec
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# @return [Node] layout attributes, including those trace types add (barmode, ...)
|
|
91
|
+
def layout = Node.new("layout", @raw.fetch("layout"))
|
|
92
|
+
|
|
93
|
+
# @return [Node] plotly.js config options
|
|
94
|
+
def config = Node.new("config", @raw.fetch("config"))
|
|
95
|
+
|
|
96
|
+
# @return [Node] attributes of an animation frame (data and layout are validated separately)
|
|
97
|
+
def frame = Node.new("frames", @raw.fetch("frames")).item
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "date"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
module Plotly
|
|
7
|
+
# Writes figures as the JSON that plotly.js reads.
|
|
8
|
+
module Serializer
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
# Characters escaped in JSON so it can be embedded in HTML.
|
|
12
|
+
HTML_UNSAFE = {"<" => "\\u003c", ">" => "\\u003e", "&" => "\\u0026"}.freeze
|
|
13
|
+
|
|
14
|
+
# @return [String] JSON that is safe to place inside an HTML <script> element: `<`, `>`
|
|
15
|
+
# and `&` (which only occur inside strings) and U+2028/2029 are written as escapes
|
|
16
|
+
def dump(value)
|
|
17
|
+
JSON.generate(plain(value), script_safe: true).gsub(/[<>&]/, HTML_UNSAFE)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Converts a value into Hashes, Arrays, Strings, numbers, booleans and nils.
|
|
21
|
+
def plain(value)
|
|
22
|
+
case value
|
|
23
|
+
when Hash then value.to_h { |k, v| [k.to_s, plain(v)] }
|
|
24
|
+
when Array then value.map { |v| plain(v) }
|
|
25
|
+
when String, Integer, true, false, nil then value
|
|
26
|
+
when Symbol then value.to_s
|
|
27
|
+
when Float then value.finite? ? value : nil
|
|
28
|
+
when Complex then unsupported!(value)
|
|
29
|
+
when Numeric then plain(value.to_f)
|
|
30
|
+
when Time, DateTime then timestamp(value)
|
|
31
|
+
when Date then value.strftime("%Y-%m-%d")
|
|
32
|
+
when Struct then unsupported!(value) # a record, even though Struct#to_a exists
|
|
33
|
+
else
|
|
34
|
+
# Ranges, Sets, Enumerators and data frame columns (Numo::NArray, Polars::Series, ...)
|
|
35
|
+
value.respond_to?(:to_a) ? plain(value.to_a) : unsupported!(value)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# plotly.js has no time zones: a date string is drawn as the wall-clock time it names.
|
|
40
|
+
def timestamp(time)
|
|
41
|
+
fraction = time.strftime("%N").sub(/0+\z/, "")
|
|
42
|
+
time.strftime("%Y-%m-%d %H:%M:%S") + (fraction.empty? ? "" : ".#{fraction}")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def unsupported!(value)
|
|
46
|
+
raise TypeError, "#{value.inspect} (#{value.class}) cannot be written as plotly.js JSON"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Plotly
|
|
4
|
+
# Builds a figure with a grid of subplots, each with its own x and y axis.
|
|
5
|
+
#
|
|
6
|
+
# Cells are numbered from the top-left, row by row; traces are placed with
|
|
7
|
+
# `add_trace(..., row:, col:)`. Spacing defaults follow plotly.py.
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# fig = Plotly.make_subplots(rows: 1, cols: 2, subplot_titles: ["Revenue", "Users"])
|
|
11
|
+
# fig.add_bar(x: months, y: revenue, row: 1, col: 1)
|
|
12
|
+
# fig.add_scatter(x: months, y: users, row: 1, col: 2)
|
|
13
|
+
#
|
|
14
|
+
# @param rows [Integer]
|
|
15
|
+
# @param cols [Integer]
|
|
16
|
+
# @param shared_xaxes [Boolean] link the x axes of each column and label only the bottom one
|
|
17
|
+
# @param shared_yaxes [Boolean] link the y axes of each row and label only the left one
|
|
18
|
+
# @param subplot_titles [Array<String>, nil] one title per cell, in row-major order
|
|
19
|
+
# @param horizontal_spacing [Float] gap between columns, as a fraction of the figure width
|
|
20
|
+
# @param vertical_spacing [Float] gap between rows, as a fraction of the figure height
|
|
21
|
+
# @param column_widths [Array<Numeric>, nil] positive relative column widths, left to right
|
|
22
|
+
# @param row_heights [Array<Numeric>, nil] positive relative row heights, top to bottom
|
|
23
|
+
# @param specs [Array<Array<Hash>>, nil] one hash per cell; `secondary_y: true` adds a right y axis
|
|
24
|
+
# @param figure_options [Hash] passed to {Figure#initialize} (`layout:`, `config:`, `validate:`)
|
|
25
|
+
# @return [Figure]
|
|
26
|
+
def self.make_subplots(rows: 1, cols: 1, shared_xaxes: false, shared_yaxes: false, subplot_titles: nil,
|
|
27
|
+
horizontal_spacing: nil, vertical_spacing: nil, column_widths: nil, row_heights: nil, specs: nil, **figure_options)
|
|
28
|
+
grid = Subplots::Grid.new(rows, cols, horizontal_spacing, vertical_spacing,
|
|
29
|
+
column_widths: column_widths, row_heights: row_heights, specs: specs)
|
|
30
|
+
titles = Array(subplot_titles)
|
|
31
|
+
if titles.size > grid.cells.size
|
|
32
|
+
raise ArgumentError, "#{titles.size} subplot titles for #{grid.cells.size} cells"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
figure = Figure.new(**figure_options)
|
|
36
|
+
figure.subplot_grid = grid
|
|
37
|
+
figure.update_layout(grid.axes_layout(shared_xaxes, shared_yaxes))
|
|
38
|
+
annotations = grid.title_annotations(titles)
|
|
39
|
+
figure.update_layout(annotations: (figure.layout["annotations"] || []) + annotations) if annotations.any?
|
|
40
|
+
figure
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Grid layout behind {Plotly.make_subplots}.
|
|
44
|
+
# @api private
|
|
45
|
+
module Subplots
|
|
46
|
+
Cell = Struct.new(:row, :col, :index, :x_domain, :y_domain, :secondary_index) do
|
|
47
|
+
def suffix = (index == 1) ? "" : index.to_s
|
|
48
|
+
|
|
49
|
+
def axis_ids(secondary_y = false) = ["x#{suffix}", secondary_y ? "y#{secondary_index}" : "y#{suffix}"]
|
|
50
|
+
|
|
51
|
+
def layout_key(letter) = "#{letter}axis#{suffix}"
|
|
52
|
+
|
|
53
|
+
def y_keys(secondary_y = nil)
|
|
54
|
+
keys = []
|
|
55
|
+
keys << layout_key("y") unless secondary_y == true
|
|
56
|
+
keys << "yaxis#{secondary_index}" if secondary_index && secondary_y != false
|
|
57
|
+
keys
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class Grid
|
|
62
|
+
attr_reader :rows, :cols
|
|
63
|
+
|
|
64
|
+
def initialize(rows, cols, horizontal_spacing, vertical_spacing, column_widths: nil, row_heights: nil, specs: nil)
|
|
65
|
+
unless rows.is_a?(Integer) && cols.is_a?(Integer) && rows.positive? && cols.positive?
|
|
66
|
+
raise ArgumentError, "rows and cols must be positive integers"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
@rows = rows
|
|
70
|
+
@cols = cols
|
|
71
|
+
horizontal_spacing = 0.2 / cols if horizontal_spacing.nil?
|
|
72
|
+
vertical_spacing = 0.3 / rows if vertical_spacing.nil?
|
|
73
|
+
horizontal_spacing = spacing(horizontal_spacing, cols, "horizontal_spacing")
|
|
74
|
+
vertical_spacing = spacing(vertical_spacing, rows, "vertical_spacing")
|
|
75
|
+
widths = sizes(column_widths, cols, 1.0 - horizontal_spacing * (cols - 1), "column_widths")
|
|
76
|
+
heights = sizes(row_heights, rows, 1.0 - vertical_spacing * (rows - 1), "row_heights")
|
|
77
|
+
secondary = secondary_cells(specs)
|
|
78
|
+
next_axis = rows * cols
|
|
79
|
+
|
|
80
|
+
y1 = 1.0
|
|
81
|
+
@cells = (1..rows).flat_map do |row|
|
|
82
|
+
x0 = 0.0
|
|
83
|
+
cells = (1..cols).map do |col|
|
|
84
|
+
second_axis = secondary[row - 1][col - 1] ? (next_axis += 1) : nil
|
|
85
|
+
cell = Cell.new(row, col, (row - 1) * cols + col,
|
|
86
|
+
domain(x0, x0 + widths[col - 1]), domain(y1 - heights[row - 1], y1), second_axis)
|
|
87
|
+
x0 += widths[col - 1] + horizontal_spacing
|
|
88
|
+
cell
|
|
89
|
+
end
|
|
90
|
+
y1 -= heights[row - 1] + vertical_spacing
|
|
91
|
+
cells
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# @return [Array<Cell>] every cell, or the cells in the given row and/or column
|
|
96
|
+
def cells(row = nil, col = nil)
|
|
97
|
+
@cells.select { |c| (row.nil? || c.row == row) && (col.nil? || c.col == col) }
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def cell(row, col)
|
|
101
|
+
found = cells(row, col)
|
|
102
|
+
return found.first if row && col && found.size == 1
|
|
103
|
+
|
|
104
|
+
raise ArgumentError, "row #{row.inspect}, col #{col.inspect} is outside the #{rows}x#{cols} subplot grid"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def axes_layout(shared_x, shared_y)
|
|
108
|
+
@cells.each_with_object({}) do |cell, layout|
|
|
109
|
+
x_id, y_id = cell.axis_ids
|
|
110
|
+
layout[cell.layout_key("x")] = {"domain" => cell.x_domain, "anchor" => y_id}.merge(
|
|
111
|
+
(shared_x && cell.row != rows) ? linked(cell(rows, cell.col).axis_ids[0]) : {}
|
|
112
|
+
)
|
|
113
|
+
layout[cell.layout_key("y")] = {"domain" => cell.y_domain, "anchor" => x_id}.merge(
|
|
114
|
+
(shared_y && cell.col != 1) ? linked(cell(cell.row, 1).axis_ids[1]) : {}
|
|
115
|
+
)
|
|
116
|
+
if cell.secondary_index
|
|
117
|
+
layout["yaxis#{cell.secondary_index}"] = {"anchor" => x_id, "overlaying" => y_id,
|
|
118
|
+
"side" => "right", "automargin" => true}
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def title_annotations(titles)
|
|
124
|
+
titles.each_with_index.filter_map do |title, i|
|
|
125
|
+
next if title.nil? || title.to_s.empty?
|
|
126
|
+
|
|
127
|
+
cell = @cells[i]
|
|
128
|
+
{
|
|
129
|
+
"text" => title, "showarrow" => false, "font" => {"size" => 16},
|
|
130
|
+
"xref" => "paper", "yref" => "paper", "xanchor" => "center", "yanchor" => "bottom",
|
|
131
|
+
"x" => ((cell.x_domain[0] + cell.x_domain[1]) / 2).round(12), "y" => cell.y_domain[1]
|
|
132
|
+
}
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
private
|
|
137
|
+
|
|
138
|
+
def positive_number?(value)
|
|
139
|
+
value.is_a?(Numeric) && !value.is_a?(Complex) && value.finite? && value.positive?
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def spacing(value, count, name)
|
|
143
|
+
unless value.is_a?(Numeric) && !value.is_a?(Complex) && value.finite? && value.between?(0, 1)
|
|
144
|
+
raise ArgumentError, "#{name} must be a finite number between 0 and 1"
|
|
145
|
+
end
|
|
146
|
+
raise ArgumentError, "spacing leaves no room for the subplots" unless value * (count - 1) < 1
|
|
147
|
+
|
|
148
|
+
value.to_f
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def sizes(values, count, available, name)
|
|
152
|
+
values = Array.new(count, 1) if values.nil?
|
|
153
|
+
unless values.is_a?(Array) && values.size == count && values.all? { |v| positive_number?(v) }
|
|
154
|
+
raise ArgumentError, "#{name} must contain #{count} positive finite numbers"
|
|
155
|
+
end
|
|
156
|
+
largest = values.max
|
|
157
|
+
weights = values.map { |v| v.fdiv(largest) }
|
|
158
|
+
total = weights.sum
|
|
159
|
+
weights.map { |v| available * v / total }
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def secondary_cells(specs)
|
|
163
|
+
return Array.new(rows) { Array.new(cols, false) } if specs.nil?
|
|
164
|
+
unless specs.is_a?(Array) && specs.size == rows && specs.all? { |row| row.is_a?(Array) && row.size == cols }
|
|
165
|
+
raise ArgumentError, "specs must be a #{rows}x#{cols} array of cell hashes"
|
|
166
|
+
end
|
|
167
|
+
specs.map do |row|
|
|
168
|
+
row.map do |spec|
|
|
169
|
+
unless spec.is_a?(Hash) && spec.keys.all? { |k| k.to_s == "secondary_y" }
|
|
170
|
+
raise ArgumentError, "each spec must be a Hash with only the secondary_y option"
|
|
171
|
+
end
|
|
172
|
+
value = spec.transform_keys(&:to_s).fetch("secondary_y", false)
|
|
173
|
+
raise ArgumentError, "secondary_y must be true or false" unless [true, false].include?(value)
|
|
174
|
+
|
|
175
|
+
value
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Follows another axis' range and leaves the tick labels to it.
|
|
181
|
+
def linked(axis_id) = {"matches" => axis_id, "showticklabels" => false}
|
|
182
|
+
|
|
183
|
+
def domain(from, to) = [from.round(12).clamp(0.0, 1.0), to.round(12).clamp(0.0, 1.0)]
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
data/lib/plotly/version.rb
CHANGED
data/lib/plotly.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tmpdir"
|
|
4
|
+
require_relative "plotly/version"
|
|
5
|
+
|
|
6
|
+
# Interactive Plotly.js charts from Ruby.
|
|
7
|
+
module Plotly
|
|
8
|
+
# Raised when a figure uses an attribute or value that the bundled plotly.js schema rejects.
|
|
9
|
+
class ValidationError < ArgumentError; end
|
|
10
|
+
|
|
11
|
+
# Base class for other rbplotly errors.
|
|
12
|
+
class Error < StandardError; end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
require_relative "plotly/schema"
|
|
16
|
+
require_relative "plotly/attributes"
|
|
17
|
+
require_relative "plotly/serializer"
|
|
18
|
+
require_relative "plotly/html"
|
|
19
|
+
require_relative "plotly/frames"
|
|
20
|
+
require_relative "plotly/figure"
|
|
21
|
+
require_relative "plotly/subplots"
|
|
22
|
+
require_relative "plotly/plot"
|
data/lib/rbplotly.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
require 'plotly/plot'
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "plotly"
|
metadata
CHANGED
|
@@ -1,206 +1,64 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rbplotly
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
bindir: exe
|
|
7
|
+
- Yoshihiro Ashida
|
|
8
|
+
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
13
|
+
name: json
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
|
-
- - "
|
|
16
|
+
- - ">="
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
18
|
+
version: '2.9'
|
|
20
19
|
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
|
-
- - "
|
|
23
|
+
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
- - "~>"
|
|
32
|
-
- !ruby/object:Gem::Version
|
|
33
|
-
version: '2.1'
|
|
34
|
-
type: :runtime
|
|
35
|
-
prerelease: false
|
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
-
requirements:
|
|
38
|
-
- - "~>"
|
|
39
|
-
- !ruby/object:Gem::Version
|
|
40
|
-
version: '2.1'
|
|
41
|
-
- !ruby/object:Gem::Dependency
|
|
42
|
-
name: launchy
|
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
|
44
|
-
requirements:
|
|
45
|
-
- - "~>"
|
|
46
|
-
- !ruby/object:Gem::Version
|
|
47
|
-
version: '2.4'
|
|
48
|
-
type: :runtime
|
|
49
|
-
prerelease: false
|
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
-
requirements:
|
|
52
|
-
- - "~>"
|
|
53
|
-
- !ruby/object:Gem::Version
|
|
54
|
-
version: '2.4'
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: bundler
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - "~>"
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '1.12'
|
|
62
|
-
type: :development
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - "~>"
|
|
67
|
-
- !ruby/object:Gem::Version
|
|
68
|
-
version: '1.12'
|
|
69
|
-
- !ruby/object:Gem::Dependency
|
|
70
|
-
name: guard-rspec
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - "~>"
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: '4.7'
|
|
76
|
-
type: :development
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - "~>"
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: '4.7'
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: guard-rubocop
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - "~>"
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '1.2'
|
|
90
|
-
type: :development
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - "~>"
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: '1.2'
|
|
97
|
-
- !ruby/object:Gem::Dependency
|
|
98
|
-
name: rake
|
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
|
100
|
-
requirements:
|
|
101
|
-
- - "~>"
|
|
102
|
-
- !ruby/object:Gem::Version
|
|
103
|
-
version: '11.2'
|
|
104
|
-
type: :development
|
|
105
|
-
prerelease: false
|
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
-
requirements:
|
|
108
|
-
- - "~>"
|
|
109
|
-
- !ruby/object:Gem::Version
|
|
110
|
-
version: '11.2'
|
|
111
|
-
- !ruby/object:Gem::Dependency
|
|
112
|
-
name: rspec
|
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
|
114
|
-
requirements:
|
|
115
|
-
- - "~>"
|
|
116
|
-
- !ruby/object:Gem::Version
|
|
117
|
-
version: '3.5'
|
|
118
|
-
type: :development
|
|
119
|
-
prerelease: false
|
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
-
requirements:
|
|
122
|
-
- - "~>"
|
|
123
|
-
- !ruby/object:Gem::Version
|
|
124
|
-
version: '3.5'
|
|
125
|
-
- !ruby/object:Gem::Dependency
|
|
126
|
-
name: yard
|
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
|
128
|
-
requirements:
|
|
129
|
-
- - "~>"
|
|
130
|
-
- !ruby/object:Gem::Version
|
|
131
|
-
version: '0.9'
|
|
132
|
-
type: :development
|
|
133
|
-
prerelease: false
|
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
-
requirements:
|
|
136
|
-
- - "~>"
|
|
137
|
-
- !ruby/object:Gem::Version
|
|
138
|
-
version: '0.9'
|
|
139
|
-
- !ruby/object:Gem::Dependency
|
|
140
|
-
name: codeclimate-test-reporter
|
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
|
142
|
-
requirements:
|
|
143
|
-
- - "~>"
|
|
144
|
-
- !ruby/object:Gem::Version
|
|
145
|
-
version: '0.6'
|
|
146
|
-
type: :development
|
|
147
|
-
prerelease: false
|
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
-
requirements:
|
|
150
|
-
- - "~>"
|
|
151
|
-
- !ruby/object:Gem::Version
|
|
152
|
-
version: '0.6'
|
|
153
|
-
description: Rbplotly, a Ruby visualization library, allows you to create interactive
|
|
154
|
-
plots.
|
|
25
|
+
version: '2.9'
|
|
26
|
+
description: Build Plotly.js figures with plain Ruby hashes, check every attribute
|
|
27
|
+
against the plot schema of the bundled plotly.js release, and write self-contained
|
|
28
|
+
HTML that works offline, in Rails views and in Jupyter (IRuby). No account or API
|
|
29
|
+
key needed.
|
|
155
30
|
email:
|
|
156
31
|
- y4ashida@gmail.com
|
|
157
32
|
executables: []
|
|
158
33
|
extensions: []
|
|
159
34
|
extra_rdoc_files: []
|
|
160
35
|
files:
|
|
161
|
-
-
|
|
162
|
-
- ".rspec"
|
|
163
|
-
- ".rubocop.yml"
|
|
164
|
-
- ".travis.yml"
|
|
165
|
-
- CODE_OF_CONDUCT.md
|
|
166
|
-
- Gemfile
|
|
167
|
-
- Guardfile
|
|
36
|
+
- CHANGELOG.md
|
|
168
37
|
- LICENSE.txt
|
|
169
38
|
- README.md
|
|
170
|
-
-
|
|
171
|
-
-
|
|
172
|
-
-
|
|
173
|
-
-
|
|
174
|
-
-
|
|
175
|
-
-
|
|
176
|
-
- examples/Histograms.ipynb
|
|
177
|
-
- examples/Line charts.ipynb
|
|
178
|
-
- examples/Pie Charts.ipynb
|
|
179
|
-
- examples/Scatter Plots.ipynb
|
|
180
|
-
- examples/heatmaps.ipynb
|
|
181
|
-
- lib/plotly/axis.rb
|
|
182
|
-
- lib/plotly/castable.rb
|
|
183
|
-
- lib/plotly/client.rb
|
|
184
|
-
- lib/plotly/data.rb
|
|
185
|
-
- lib/plotly/exportable.rb
|
|
186
|
-
- lib/plotly/layout.rb
|
|
187
|
-
- lib/plotly/line.rb
|
|
188
|
-
- lib/plotly/marker.rb
|
|
189
|
-
- lib/plotly/offline/exportable.rb
|
|
190
|
-
- lib/plotly/offline/html.rb
|
|
191
|
-
- lib/plotly/offline/plotly.min.js
|
|
192
|
-
- lib/plotly/offline/templates/body.erb
|
|
193
|
-
- lib/plotly/offline/templates/plot.erb
|
|
39
|
+
- lib/plotly.rb
|
|
40
|
+
- lib/plotly/assets/plotly.min.js
|
|
41
|
+
- lib/plotly/attributes.rb
|
|
42
|
+
- lib/plotly/figure.rb
|
|
43
|
+
- lib/plotly/frames.rb
|
|
44
|
+
- lib/plotly/html.rb
|
|
194
45
|
- lib/plotly/plot.rb
|
|
195
|
-
- lib/plotly/
|
|
46
|
+
- lib/plotly/schema.rb
|
|
47
|
+
- lib/plotly/schema/plot-schema.json
|
|
48
|
+
- lib/plotly/serializer.rb
|
|
49
|
+
- lib/plotly/subplots.rb
|
|
196
50
|
- lib/plotly/version.rb
|
|
197
51
|
- lib/rbplotly.rb
|
|
198
|
-
|
|
199
|
-
homepage: https://github.com/y4ashida/rbplotly
|
|
52
|
+
homepage: https://github.com/ash1day/rbplotly
|
|
200
53
|
licenses:
|
|
201
54
|
- MIT
|
|
202
|
-
metadata:
|
|
203
|
-
|
|
55
|
+
metadata:
|
|
56
|
+
homepage_uri: https://github.com/ash1day/rbplotly
|
|
57
|
+
source_code_uri: https://github.com/ash1day/rbplotly
|
|
58
|
+
changelog_uri: https://github.com/ash1day/rbplotly/blob/master/CHANGELOG.md
|
|
59
|
+
bug_tracker_uri: https://github.com/ash1day/rbplotly/issues
|
|
60
|
+
documentation_uri: https://rubydoc.info/gems/rbplotly
|
|
61
|
+
rubygems_mfa_required: 'true'
|
|
204
62
|
rdoc_options: []
|
|
205
63
|
require_paths:
|
|
206
64
|
- lib
|
|
@@ -208,16 +66,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
208
66
|
requirements:
|
|
209
67
|
- - ">="
|
|
210
68
|
- !ruby/object:Gem::Version
|
|
211
|
-
version: '
|
|
69
|
+
version: '3.3'
|
|
212
70
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
213
71
|
requirements:
|
|
214
72
|
- - ">="
|
|
215
73
|
- !ruby/object:Gem::Version
|
|
216
74
|
version: '0'
|
|
217
75
|
requirements: []
|
|
218
|
-
|
|
219
|
-
rubygems_version: 2.5.2
|
|
220
|
-
signing_key:
|
|
76
|
+
rubygems_version: 4.0.20
|
|
221
77
|
specification_version: 4
|
|
222
|
-
summary:
|
|
78
|
+
summary: Interactive Plotly.js charts from Ruby, validated against the plotly.js schema
|
|
223
79
|
test_files: []
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.rubocop.yml
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
AllCops:
|
|
2
|
-
TargetRubyVersion: 2.3
|
|
3
|
-
|
|
4
|
-
Style/FrozenStringLiteralComment:
|
|
5
|
-
Enabled: false
|
|
6
|
-
|
|
7
|
-
LineLength:
|
|
8
|
-
Max: 100
|
|
9
|
-
|
|
10
|
-
MethodLength:
|
|
11
|
-
Max: 15
|
|
12
|
-
|
|
13
|
-
Documentation:
|
|
14
|
-
Enabled: false
|
|
15
|
-
|
|
16
|
-
ParameterLists:
|
|
17
|
-
CountKeywordArgs: false
|
|
18
|
-
|
|
19
|
-
RegexpLiteral:
|
|
20
|
-
Exclude:
|
|
21
|
-
- '**/*.gemspec'
|
|
22
|
-
- '**/Guardfile'
|