rbplotly 0.1.1 → 1.0.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 +5 -5
- data/CHANGELOG.md +64 -0
- data/LICENSE.txt +1 -1
- data/README.md +177 -39
- data/lib/plotly/assets/plotly.min.js +3620 -0
- data/lib/plotly/attributes.rb +221 -0
- data/lib/plotly/figure.rb +236 -0
- data/lib/plotly/html.rb +150 -0
- data/lib/plotly/plot.rb +11 -40
- data/lib/plotly/schema/plot-schema.json +57234 -0
- data/lib/plotly/schema.rb +96 -0
- data/lib/plotly/serializer.rb +49 -0
- data/lib/plotly/subplots.rb +118 -0
- data/lib/plotly/version.rb +7 -1
- data/lib/plotly.rb +21 -0
- data/lib/rbplotly.rb +3 -4
- metadata +34 -162
- data/.gitignore +0 -11
- data/.rspec +0 -2
- data/.rubocop.yml +0 -22
- data/.travis.yml +0 -6
- 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/basic_bar_chart.ipynb +0 -82
- data/examples/basic_histogram.ipynb +0 -78
- data/examples/basic_pie_chart.ipynb +0 -84
- data/examples/grouped_bar_chart.ipynb +0 -89
- data/examples/heatmaps.ipynb +0 -89
- data/examples/line_and_scatter_plots.ipynb +0 -227
- data/examples/stacked_bar_chart.ipynb +0 -89
- data/lib/plotly/axis.rb +0 -15
- data/lib/plotly/castable.rb +0 -20
- data/lib/plotly/client.rb +0 -40
- data/lib/plotly/data.rb +0 -22
- data/lib/plotly/exportable.rb +0 -23
- data/lib/plotly/layout.rb +0 -33
- data/lib/plotly/offline/exportable.rb +0 -31
- 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 -31
|
@@ -0,0 +1,96 @@
|
|
|
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
|
+
end
|
|
96
|
+
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,118 @@
|
|
|
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 figure_options [Hash] passed to {Figure#initialize} (`layout:`, `config:`, `validate:`)
|
|
22
|
+
# @return [Figure]
|
|
23
|
+
def self.make_subplots(rows: 1, cols: 1, shared_xaxes: false, shared_yaxes: false, subplot_titles: nil,
|
|
24
|
+
horizontal_spacing: 0.2 / cols, vertical_spacing: 0.3 / rows, **figure_options)
|
|
25
|
+
grid = Subplots::Grid.new(rows, cols, horizontal_spacing, vertical_spacing)
|
|
26
|
+
titles = Array(subplot_titles)
|
|
27
|
+
if titles.size > grid.cells.size
|
|
28
|
+
raise ArgumentError, "#{titles.size} subplot titles for #{grid.cells.size} cells"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
figure = Figure.new(**figure_options)
|
|
32
|
+
figure.subplot_grid = grid
|
|
33
|
+
figure.update_layout(grid.axes_layout(shared_xaxes, shared_yaxes))
|
|
34
|
+
annotations = grid.title_annotations(titles)
|
|
35
|
+
figure.update_layout(annotations: (figure.layout["annotations"] || []) + annotations) if annotations.any?
|
|
36
|
+
figure
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Grid layout behind {Plotly.make_subplots}.
|
|
40
|
+
# @api private
|
|
41
|
+
module Subplots
|
|
42
|
+
Cell = Struct.new(:row, :col, :index, :x_domain, :y_domain) do
|
|
43
|
+
def suffix = (index == 1) ? "" : index.to_s
|
|
44
|
+
|
|
45
|
+
def axis_ids = ["x#{suffix}", "y#{suffix}"]
|
|
46
|
+
|
|
47
|
+
def layout_key(letter) = "#{letter}axis#{suffix}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class Grid
|
|
51
|
+
attr_reader :rows, :cols
|
|
52
|
+
|
|
53
|
+
def initialize(rows, cols, horizontal_spacing, vertical_spacing)
|
|
54
|
+
unless rows.is_a?(Integer) && cols.is_a?(Integer) && rows.positive? && cols.positive?
|
|
55
|
+
raise ArgumentError, "rows and cols must be positive integers"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
@rows = rows
|
|
59
|
+
@cols = cols
|
|
60
|
+
width = (1.0 - horizontal_spacing * (cols - 1)) / cols
|
|
61
|
+
height = (1.0 - vertical_spacing * (rows - 1)) / rows
|
|
62
|
+
raise ArgumentError, "spacing leaves no room for the subplots" unless width.positive? && height.positive?
|
|
63
|
+
|
|
64
|
+
@cells = (1..rows).flat_map do |row|
|
|
65
|
+
(1..cols).map do |col|
|
|
66
|
+
x0 = (col - 1) * (width + horizontal_spacing)
|
|
67
|
+
y1 = 1.0 - (row - 1) * (height + vertical_spacing)
|
|
68
|
+
Cell.new(row, col, (row - 1) * cols + col, domain(x0, x0 + width), domain(y1 - height, y1))
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @return [Array<Cell>] every cell, or the cells in the given row and/or column
|
|
74
|
+
def cells(row = nil, col = nil)
|
|
75
|
+
@cells.select { |c| (row.nil? || c.row == row) && (col.nil? || c.col == col) }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def cell(row, col)
|
|
79
|
+
found = cells(row, col)
|
|
80
|
+
return found.first if row && col && found.size == 1
|
|
81
|
+
|
|
82
|
+
raise ArgumentError, "row #{row.inspect}, col #{col.inspect} is outside the #{rows}x#{cols} subplot grid"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def axes_layout(shared_x, shared_y)
|
|
86
|
+
@cells.each_with_object({}) do |cell, layout|
|
|
87
|
+
x_id, y_id = cell.axis_ids
|
|
88
|
+
layout[cell.layout_key("x")] = {"domain" => cell.x_domain, "anchor" => y_id}.merge(
|
|
89
|
+
(shared_x && cell.row != rows) ? linked(cell(rows, cell.col).axis_ids[0]) : {}
|
|
90
|
+
)
|
|
91
|
+
layout[cell.layout_key("y")] = {"domain" => cell.y_domain, "anchor" => x_id}.merge(
|
|
92
|
+
(shared_y && cell.col != 1) ? linked(cell(cell.row, 1).axis_ids[1]) : {}
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def title_annotations(titles)
|
|
98
|
+
titles.each_with_index.filter_map do |title, i|
|
|
99
|
+
next if title.nil? || title.to_s.empty?
|
|
100
|
+
|
|
101
|
+
cell = @cells[i]
|
|
102
|
+
{
|
|
103
|
+
"text" => title, "showarrow" => false, "font" => {"size" => 16},
|
|
104
|
+
"xref" => "paper", "yref" => "paper", "xanchor" => "center", "yanchor" => "bottom",
|
|
105
|
+
"x" => ((cell.x_domain[0] + cell.x_domain[1]) / 2).round(12), "y" => cell.y_domain[1]
|
|
106
|
+
}
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
# Follows another axis' range and leaves the tick labels to it.
|
|
113
|
+
def linked(axis_id) = {"matches" => axis_id, "showticklabels" => false}
|
|
114
|
+
|
|
115
|
+
def domain(from, to) = [from.round(12).clamp(0.0, 1.0), to.round(12).clamp(0.0, 1.0)]
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
data/lib/plotly/version.rb
CHANGED
data/lib/plotly.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
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/figure"
|
|
20
|
+
require_relative "plotly/subplots"
|
|
21
|
+
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,189 +1,63 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rbplotly
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.0
|
|
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.7'
|
|
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: rake
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - "~>"
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: '10.0'
|
|
76
|
-
type: :development
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - "~>"
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: '10.0'
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: rspec
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - "~>"
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '3.5'
|
|
90
|
-
type: :development
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - "~>"
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: '3.5'
|
|
97
|
-
- !ruby/object:Gem::Dependency
|
|
98
|
-
name: guard-rspec
|
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
|
100
|
-
requirements:
|
|
101
|
-
- - "~>"
|
|
102
|
-
- !ruby/object:Gem::Version
|
|
103
|
-
version: '4.7'
|
|
104
|
-
type: :development
|
|
105
|
-
prerelease: false
|
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
-
requirements:
|
|
108
|
-
- - "~>"
|
|
109
|
-
- !ruby/object:Gem::Version
|
|
110
|
-
version: '4.7'
|
|
111
|
-
- !ruby/object:Gem::Dependency
|
|
112
|
-
name: guard-rubocop
|
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
|
114
|
-
requirements:
|
|
115
|
-
- - "~>"
|
|
116
|
-
- !ruby/object:Gem::Version
|
|
117
|
-
version: '1.2'
|
|
118
|
-
type: :development
|
|
119
|
-
prerelease: false
|
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
-
requirements:
|
|
122
|
-
- - "~>"
|
|
123
|
-
- !ruby/object:Gem::Version
|
|
124
|
-
version: '1.2'
|
|
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
|
-
description:
|
|
25
|
+
version: '2.7'
|
|
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.
|
|
140
30
|
email:
|
|
141
31
|
- y4ashida@gmail.com
|
|
142
32
|
executables: []
|
|
143
33
|
extensions: []
|
|
144
34
|
extra_rdoc_files: []
|
|
145
35
|
files:
|
|
146
|
-
-
|
|
147
|
-
- ".rspec"
|
|
148
|
-
- ".rubocop.yml"
|
|
149
|
-
- ".travis.yml"
|
|
150
|
-
- CODE_OF_CONDUCT.md
|
|
151
|
-
- Gemfile
|
|
152
|
-
- Guardfile
|
|
36
|
+
- CHANGELOG.md
|
|
153
37
|
- LICENSE.txt
|
|
154
38
|
- README.md
|
|
155
|
-
-
|
|
156
|
-
-
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
-
|
|
160
|
-
- examples/basic_histogram.ipynb
|
|
161
|
-
- examples/basic_pie_chart.ipynb
|
|
162
|
-
- examples/grouped_bar_chart.ipynb
|
|
163
|
-
- examples/heatmaps.ipynb
|
|
164
|
-
- examples/line_and_scatter_plots.ipynb
|
|
165
|
-
- examples/stacked_bar_chart.ipynb
|
|
166
|
-
- lib/plotly/axis.rb
|
|
167
|
-
- lib/plotly/castable.rb
|
|
168
|
-
- lib/plotly/client.rb
|
|
169
|
-
- lib/plotly/data.rb
|
|
170
|
-
- lib/plotly/exportable.rb
|
|
171
|
-
- lib/plotly/layout.rb
|
|
172
|
-
- lib/plotly/offline/exportable.rb
|
|
173
|
-
- lib/plotly/offline/html.rb
|
|
174
|
-
- lib/plotly/offline/plotly.min.js
|
|
175
|
-
- lib/plotly/offline/templates/body.erb
|
|
176
|
-
- 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/html.rb
|
|
177
44
|
- lib/plotly/plot.rb
|
|
178
|
-
- lib/plotly/
|
|
45
|
+
- lib/plotly/schema.rb
|
|
46
|
+
- lib/plotly/schema/plot-schema.json
|
|
47
|
+
- lib/plotly/serializer.rb
|
|
48
|
+
- lib/plotly/subplots.rb
|
|
179
49
|
- lib/plotly/version.rb
|
|
180
50
|
- lib/rbplotly.rb
|
|
181
|
-
|
|
182
|
-
homepage: https://github.com/y4ashida/rbplotly
|
|
51
|
+
homepage: https://github.com/ash1day/rbplotly
|
|
183
52
|
licenses:
|
|
184
53
|
- MIT
|
|
185
|
-
metadata:
|
|
186
|
-
|
|
54
|
+
metadata:
|
|
55
|
+
homepage_uri: https://github.com/ash1day/rbplotly
|
|
56
|
+
source_code_uri: https://github.com/ash1day/rbplotly
|
|
57
|
+
changelog_uri: https://github.com/ash1day/rbplotly/blob/master/CHANGELOG.md
|
|
58
|
+
bug_tracker_uri: https://github.com/ash1day/rbplotly/issues
|
|
59
|
+
documentation_uri: https://rubydoc.info/gems/rbplotly
|
|
60
|
+
rubygems_mfa_required: 'true'
|
|
187
61
|
rdoc_options: []
|
|
188
62
|
require_paths:
|
|
189
63
|
- lib
|
|
@@ -191,16 +65,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
191
65
|
requirements:
|
|
192
66
|
- - ">="
|
|
193
67
|
- !ruby/object:Gem::Version
|
|
194
|
-
version: '
|
|
68
|
+
version: '3.3'
|
|
195
69
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
196
70
|
requirements:
|
|
197
71
|
- - ">="
|
|
198
72
|
- !ruby/object:Gem::Version
|
|
199
73
|
version: '0'
|
|
200
74
|
requirements: []
|
|
201
|
-
|
|
202
|
-
rubygems_version: 2.5.1
|
|
203
|
-
signing_key:
|
|
75
|
+
rubygems_version: 4.0.20
|
|
204
76
|
specification_version: 4
|
|
205
|
-
summary:
|
|
77
|
+
summary: Interactive Plotly.js charts from Ruby, validated against the plotly.js schema
|
|
206
78
|
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'
|
data/.travis.yml
DELETED
data/CODE_OF_CONDUCT.md
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# Contributor Code of Conduct
|
|
2
|
-
|
|
3
|
-
As contributors and maintainers of this project, and in the interest of
|
|
4
|
-
fostering an open and welcoming community, we pledge to respect all people who
|
|
5
|
-
contribute through reporting issues, posting feature requests, updating
|
|
6
|
-
documentation, submitting pull requests or patches, and other activities.
|
|
7
|
-
|
|
8
|
-
We are committed to making participation in this project a harassment-free
|
|
9
|
-
experience for everyone, regardless of level of experience, gender, gender
|
|
10
|
-
identity and expression, sexual orientation, disability, personal appearance,
|
|
11
|
-
body size, race, ethnicity, age, religion, or nationality.
|
|
12
|
-
|
|
13
|
-
Examples of unacceptable behavior by participants include:
|
|
14
|
-
|
|
15
|
-
* The use of sexualized language or imagery
|
|
16
|
-
* Personal attacks
|
|
17
|
-
* Trolling or insulting/derogatory comments
|
|
18
|
-
* Public or private harassment
|
|
19
|
-
* Publishing other's private information, such as physical or electronic
|
|
20
|
-
addresses, without explicit permission
|
|
21
|
-
* Other unethical or unprofessional conduct
|
|
22
|
-
|
|
23
|
-
Project maintainers have the right and responsibility to remove, edit, or
|
|
24
|
-
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
25
|
-
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
26
|
-
permanently any contributor for other behaviors that they deem inappropriate,
|
|
27
|
-
threatening, offensive, or harmful.
|
|
28
|
-
|
|
29
|
-
By adopting this Code of Conduct, project maintainers commit themselves to
|
|
30
|
-
fairly and consistently applying these principles to every aspect of managing
|
|
31
|
-
this project. Project maintainers who do not follow or enforce the Code of
|
|
32
|
-
Conduct may be permanently removed from the project team.
|
|
33
|
-
|
|
34
|
-
This code of conduct applies both within project spaces and in public spaces
|
|
35
|
-
when an individual is representing the project or its community.
|
|
36
|
-
|
|
37
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
38
|
-
reported by contacting a project maintainer at y4ashida@gmail.com. All
|
|
39
|
-
complaints will be reviewed and investigated and will result in a response that
|
|
40
|
-
is deemed necessary and appropriate to the circumstances. Maintainers are
|
|
41
|
-
obligated to maintain confidentiality with regard to the reporter of an
|
|
42
|
-
incident.
|
|
43
|
-
|
|
44
|
-
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
45
|
-
version 1.3.0, available at
|
|
46
|
-
[http://contributor-covenant.org/version/1/3/0/][version]
|
|
47
|
-
|
|
48
|
-
[homepage]: http://contributor-covenant.org
|
|
49
|
-
[version]: http://contributor-covenant.org/version/1/3/0/
|
data/Gemfile
DELETED
data/Guardfile
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
guard :rspec, all_after_pass: true, all_on_start: true, cmd: 'bundle exec rspec' do
|
|
2
|
-
watch(%r{^spec/.+_spec\.rb$})
|
|
3
|
-
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
|
4
|
-
watch(%r{^lib/(.+?)/.+\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
|
5
|
-
watch('spec/spec_helper.rb') { 'spec' }
|
|
6
|
-
watch(%r{^spec/support/.+\.rb$}) { 'spec' }
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
guard :rubocop do
|
|
10
|
-
watch(%r{.+\.rb$})
|
|
11
|
-
watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
|
|
12
|
-
end
|