charty 0.2.6 → 0.2.10
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/charty.gemspec +2 -1
- data/examples/bar_plot.rb +19 -0
- data/examples/box_plot.rb +17 -0
- data/examples/scatter_plot.rb +17 -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 +2 -0
- data/lib/charty/backends/plotly.rb +127 -24
- data/lib/charty/backends/plotly_helpers/html_renderer.rb +203 -0
- data/lib/charty/backends/plotly_helpers/notebook_renderer.rb +89 -0
- data/lib/charty/backends/plotly_helpers/plotly_renderer.rb +121 -0
- data/lib/charty/backends/pyplot.rb +74 -0
- data/lib/charty/backends/unicode_plot.rb +9 -9
- data/lib/charty/cache_dir.rb +27 -0
- data/lib/charty/iruby_helper.rb +18 -0
- data/lib/charty/plot_methods.rb +82 -6
- data/lib/charty/plotters.rb +3 -0
- data/lib/charty/plotters/abstract_plotter.rb +56 -16
- data/lib/charty/plotters/bar_plotter.rb +39 -0
- data/lib/charty/plotters/categorical_plotter.rb +9 -1
- data/lib/charty/plotters/distribution_plotter.rb +180 -0
- data/lib/charty/plotters/histogram_plotter.rb +244 -0
- data/lib/charty/plotters/line_plotter.rb +38 -5
- data/lib/charty/plotters/scatter_plotter.rb +4 -2
- data/lib/charty/statistics.rb +9 -0
- data/lib/charty/table.rb +30 -23
- data/lib/charty/table_adapters/base_adapter.rb +88 -0
- data/lib/charty/table_adapters/daru_adapter.rb +41 -1
- data/lib/charty/table_adapters/hash_adapter.rb +59 -1
- data/lib/charty/table_adapters/pandas_adapter.rb +49 -1
- data/lib/charty/vector.rb +29 -1
- data/lib/charty/vector_adapters.rb +16 -0
- data/lib/charty/vector_adapters/pandas_adapter.rb +10 -1
- data/lib/charty/version.rb +1 -1
- metadata +39 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d885d476eadfadd3f76f138707ffaf6166eec006b4528fb19c3acce0b97b1c85
|
4
|
+
data.tar.gz: 0630f23f19b65177f3b6dc238717a81a019f9dfa40a40c143d71dcc5c5f760f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 535a69b8d794ccbd30b4328f3188c8a8b50c850cfd84285f79b31162296a9d981313e561ea1089a68be3368b7eb1c83ccc3cb2ff511b8f79aef77e544e261bbe
|
7
|
+
data.tar.gz: 804de2468433db38b5381bcbccab4c28e84c7592bce5c5a98a539ce99c589449759e65ffe7f2e808bd3c5cb5e002ee2219219111561f66f590dbb0ac2c0757bc
|
data/charty.gemspec
CHANGED
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.require_paths = ["lib"]
|
28
28
|
|
29
29
|
spec.add_dependency "red-colors", ">= 0.3.0"
|
30
|
+
spec.add_dependency "red-datasets", ">= 0.1.2"
|
30
31
|
spec.add_dependency "red-palette", ">= 0.5.0"
|
31
32
|
|
32
33
|
spec.add_dependency "matplotlib", ">= 1.2.0"
|
@@ -36,10 +37,10 @@ Gem::Specification.new do |spec|
|
|
36
37
|
spec.add_development_dependency "bundler", ">= 1.16"
|
37
38
|
spec.add_development_dependency "rake"
|
38
39
|
spec.add_development_dependency "test-unit"
|
39
|
-
spec.add_development_dependency "red-datasets", ">= 0.1.2"
|
40
40
|
spec.add_development_dependency "daru"
|
41
41
|
spec.add_development_dependency "matrix" # need for daru on Ruby > 3.0
|
42
42
|
spec.add_development_dependency "activerecord"
|
43
43
|
spec.add_development_dependency "sqlite3"
|
44
44
|
spec.add_development_dependency "iruby", ">= 0.7.0"
|
45
|
+
spec.add_development_dependency "csv"
|
45
46
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# This example generates box_plot results in README.md
|
2
|
+
|
3
|
+
require "charty"
|
4
|
+
require "datasets"
|
5
|
+
require "matplotlib"
|
6
|
+
|
7
|
+
Charty::Backends.use(:pyplot)
|
8
|
+
Matplotlib.use(:agg)
|
9
|
+
|
10
|
+
penguins = Datasets::Penguins.new
|
11
|
+
|
12
|
+
Charty.bar_plot(data: penguins, x: :species, y: :body_mass_g)
|
13
|
+
.save("penguins_species_body_mass_g_bar_plot_v.png")
|
14
|
+
|
15
|
+
Charty.bar_plot(data: penguins, x: :body_mass_g, y: :species)
|
16
|
+
.save("penguins_species_body_mass_g_bar_plot_h.png")
|
17
|
+
|
18
|
+
Charty.bar_plot(data: penguins, x: :species, y: :body_mass_g, color: :sex)
|
19
|
+
.save("penguins_species_body_mass_g_sex_bar_plot_v.png")
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "charty"
|
2
|
+
require "datasets"
|
3
|
+
require "matplotlib"
|
4
|
+
|
5
|
+
Charty::Backends.use(:pyplot)
|
6
|
+
Matplotlib.use(:agg)
|
7
|
+
|
8
|
+
penguins = Datasets::Penguins.new
|
9
|
+
|
10
|
+
Charty.box_plot(data: penguins, x: :species, y: :body_mass_g)
|
11
|
+
.save("penguins_species_body_mass_g_box_plot_v.png")
|
12
|
+
|
13
|
+
Charty.box_plot(data: penguins, x: :body_mass_g, y: :species)
|
14
|
+
.save("penguins_species_body_mass_g_box_plot_h.png")
|
15
|
+
|
16
|
+
Charty.box_plot(data: penguins, x: :species, y: :body_mass_g, color: :sex)
|
17
|
+
.save("penguins_species_body_mass_g_sex_box_plot_v.png")
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "charty"
|
2
|
+
require "datasets"
|
3
|
+
require "matplotlib"
|
4
|
+
|
5
|
+
Charty::Backends.use(:pyplot)
|
6
|
+
Matplotlib.use(:agg)
|
7
|
+
|
8
|
+
penguins = Datasets::Penguins.new
|
9
|
+
|
10
|
+
Charty.scatter_plot(data: penguins, x: :body_mass_g, y: :flipper_length_mm)
|
11
|
+
.save("penguins_body_mass_g_flipper_length_mm_scatter_plot.png")
|
12
|
+
|
13
|
+
Charty.scatter_plot(data: penguins, x: :body_mass_g, y: :flipper_length_mm, color: :species)
|
14
|
+
.save("penguins_body_mass_g_flipper_length_mm_species_scatter_plot.png")
|
15
|
+
|
16
|
+
Charty.scatter_plot(data: penguins, x: :body_mass_g, y: :flipper_length_mm, color: :species, style: :sex)
|
17
|
+
.save("penguins_body_mass_g_flipper_length_mm_species_sex_scatter_plot.png")
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/lib/charty.rb
CHANGED
@@ -3,7 +3,9 @@ require_relative "charty/version"
|
|
3
3
|
require "colors"
|
4
4
|
require "palette"
|
5
5
|
|
6
|
+
require_relative "charty/cache_dir"
|
6
7
|
require_relative "charty/util"
|
8
|
+
require_relative "charty/iruby_helper"
|
7
9
|
require_relative "charty/dash_pattern_generator"
|
8
10
|
require_relative "charty/backends"
|
9
11
|
require_relative "charty/backend_methods"
|
@@ -2,6 +2,10 @@ require "json"
|
|
2
2
|
require "securerandom"
|
3
3
|
require "tmpdir"
|
4
4
|
|
5
|
+
require_relative "plotly_helpers/html_renderer"
|
6
|
+
require_relative "plotly_helpers/notebook_renderer"
|
7
|
+
require_relative "plotly_helpers/plotly_renderer"
|
8
|
+
|
5
9
|
module Charty
|
6
10
|
module Backends
|
7
11
|
class Plotly
|
@@ -130,10 +134,8 @@ module Charty
|
|
130
134
|
|
131
135
|
if orient == :v
|
132
136
|
x, y = bar_pos, values
|
133
|
-
x = group_names unless group_names.nil?
|
134
137
|
else
|
135
138
|
x, y = values, bar_pos
|
136
|
-
y = group_names unless group_names.nil?
|
137
139
|
end
|
138
140
|
|
139
141
|
trace = {
|
@@ -237,9 +239,9 @@ module Charty
|
|
237
239
|
}
|
238
240
|
|
239
241
|
if orient == :v
|
240
|
-
trace.update(y: values, x: group_keys)
|
242
|
+
trace.update(y: values, x: group_keys.map(&:to_s))
|
241
243
|
else
|
242
|
-
trace.update(x: values, y: group_keys)
|
244
|
+
trace.update(x: values, y: group_keys.map(&:to_s))
|
243
245
|
end
|
244
246
|
|
245
247
|
trace
|
@@ -558,6 +560,62 @@ module Charty
|
|
558
560
|
end
|
559
561
|
end
|
560
562
|
|
563
|
+
PLOTLY_HISTNORM = {
|
564
|
+
count: "".freeze,
|
565
|
+
frequency: "density".freeze,
|
566
|
+
density: "probability density".freeze,
|
567
|
+
probability: "probability".freeze
|
568
|
+
}.freeze
|
569
|
+
|
570
|
+
def univariate_histogram(hist, name, variable_name, stat,
|
571
|
+
alpha, color, key_color, color_mapper,
|
572
|
+
_multiple, _element, _fill, _shrink)
|
573
|
+
value_axis = variable_name
|
574
|
+
case value_axis
|
575
|
+
when :x
|
576
|
+
weights_axis = :y
|
577
|
+
orientation = :v
|
578
|
+
else
|
579
|
+
weights_axis = :x
|
580
|
+
orientation = :h
|
581
|
+
end
|
582
|
+
|
583
|
+
mid_points = hist.edges.each_cons(2).map {|a, b| a + (b - a) / 2 }
|
584
|
+
|
585
|
+
trace = {
|
586
|
+
type: :bar,
|
587
|
+
name: name.to_s,
|
588
|
+
value_axis => mid_points,
|
589
|
+
weights_axis => hist.weights,
|
590
|
+
orientation: orientation,
|
591
|
+
opacity: alpha
|
592
|
+
}
|
593
|
+
|
594
|
+
if color.nil?
|
595
|
+
trace[:marker] = {
|
596
|
+
color: key_color.to_rgb.to_hex_string
|
597
|
+
}
|
598
|
+
else
|
599
|
+
trace[:marker] = {
|
600
|
+
color: color_mapper[color].to_rgb.to_hex_string
|
601
|
+
}
|
602
|
+
end
|
603
|
+
|
604
|
+
@traces << trace
|
605
|
+
|
606
|
+
@layout[:bargap] = 0.05
|
607
|
+
|
608
|
+
if @traces.length > 1
|
609
|
+
@layout[:barmode] = "overlay"
|
610
|
+
@layout[:showlegend] = true
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
def set_title(title)
|
615
|
+
@layout[:title] ||= {}
|
616
|
+
@layout[:title][:text] = title
|
617
|
+
end
|
618
|
+
|
561
619
|
def set_xlabel(label)
|
562
620
|
@layout[:xaxis] ||= {}
|
563
621
|
@layout[:xaxis][:title] = label
|
@@ -602,6 +660,29 @@ module Charty
|
|
602
660
|
@layout[:yaxis][:range] = [min, max]
|
603
661
|
end
|
604
662
|
|
663
|
+
def set_xscale(scale)
|
664
|
+
scale = check_scale_type(scale, :xscale)
|
665
|
+
@layout[:xaxis] ||= {}
|
666
|
+
@layout[:xaxis][:type] = scale
|
667
|
+
end
|
668
|
+
|
669
|
+
def set_yscale(scale)
|
670
|
+
scale = check_scale_type(scale, :yscale)
|
671
|
+
@layout[:yaxis] ||= {}
|
672
|
+
@layout[:yaxis][:type] = scale
|
673
|
+
end
|
674
|
+
|
675
|
+
private def check_scale_type(val, name)
|
676
|
+
case
|
677
|
+
when :linear, :log
|
678
|
+
val
|
679
|
+
else
|
680
|
+
raise ArgumentError,
|
681
|
+
"Invalid #{name} type: %p" % val,
|
682
|
+
caller
|
683
|
+
end
|
684
|
+
end
|
685
|
+
|
605
686
|
def disable_xaxis_grid
|
606
687
|
# do nothing
|
607
688
|
end
|
@@ -699,7 +780,7 @@ module Charty
|
|
699
780
|
|
700
781
|
def render(element_id: nil, format: nil, notebook: false)
|
701
782
|
case format
|
702
|
-
when :html, "html"
|
783
|
+
when :html, "html", nil
|
703
784
|
format = "text/html"
|
704
785
|
when :png, "png"
|
705
786
|
format = "image/png"
|
@@ -708,7 +789,7 @@ module Charty
|
|
708
789
|
end
|
709
790
|
|
710
791
|
case format
|
711
|
-
when "text/html"
|
792
|
+
when "text/html"
|
712
793
|
# render html after this case cause
|
713
794
|
when "image/png", "image/jpeg"
|
714
795
|
image_data = render_image(format, element_id: element_id, notebook: false)
|
@@ -722,32 +803,54 @@ module Charty
|
|
722
803
|
"Unsupported mime type to render: %p" % format
|
723
804
|
end
|
724
805
|
|
725
|
-
# TODO: size should be customizable
|
726
|
-
html = <<~HTML
|
727
|
-
<div id="%{id}" style="width: 100%%; height:525px;"></div>
|
728
|
-
<script type="text/javascript">
|
729
|
-
requirejs(["plotly"], function (Plotly) {
|
730
|
-
Plotly.newPlot("%{id}", %{data}, %{layout});
|
731
|
-
});
|
732
|
-
</script>
|
733
|
-
HTML
|
734
|
-
|
735
806
|
element_id = SecureRandom.uuid if element_id.nil?
|
736
807
|
|
737
|
-
|
738
|
-
|
739
|
-
data: JSON.dump(@traces),
|
740
|
-
layout: JSON.dump(@layout)
|
741
|
-
}
|
742
|
-
|
808
|
+
renderer = PlotlyHelpers::HtmlRenderer.new(full_html: !notebook)
|
809
|
+
html = renderer.render({data: @traces, layout: @layout}, element_id: element_id)
|
743
810
|
if notebook
|
744
|
-
|
745
|
-
["text/html", html]
|
811
|
+
[format, html]
|
746
812
|
else
|
747
813
|
html
|
748
814
|
end
|
749
815
|
end
|
750
816
|
|
817
|
+
def render_mimebundle(include: [], exclude: [])
|
818
|
+
types = case
|
819
|
+
when IRubyHelper.vscode?,
|
820
|
+
IRubyHelper.nteract?
|
821
|
+
[:plotly_mimetype]
|
822
|
+
else
|
823
|
+
[:plotly_mimetype, :notebook]
|
824
|
+
end
|
825
|
+
bundle = Util.filter_map(types) { |type|
|
826
|
+
case type
|
827
|
+
when :plotly_mimetype
|
828
|
+
render_plotly_mimetype_bundle
|
829
|
+
when :notebook
|
830
|
+
render_notebook_bundle
|
831
|
+
end
|
832
|
+
}.to_h
|
833
|
+
bundle
|
834
|
+
end
|
835
|
+
|
836
|
+
private def render_plotly_mimetype_bundle
|
837
|
+
renderer = PlotlyHelpers::PlotlyRenderer.new
|
838
|
+
obj = renderer.render({data: @traces, layout: @layout})
|
839
|
+
[ "application/vnd.plotly.v1+json", obj ]
|
840
|
+
end
|
841
|
+
|
842
|
+
private def render_notebook_bundle
|
843
|
+
renderer = self.class.notebook_renderer
|
844
|
+
renderer.activate
|
845
|
+
html = renderer.render({data: @traces, layout: @layout})
|
846
|
+
[ "text/html", html ]
|
847
|
+
end
|
848
|
+
|
849
|
+
# for new APIs
|
850
|
+
def self.notebook_renderer
|
851
|
+
@notebook_renderer ||= PlotlyHelpers::NotebookRenderer.new
|
852
|
+
end
|
853
|
+
|
751
854
|
private def render_image(format=nil, filename: nil, element_id: nil, notebook: false,
|
752
855
|
title: nil, width: nil, height: nil)
|
753
856
|
format = "image/png" if format.nil?
|
@@ -0,0 +1,203 @@
|
|
1
|
+
require "datasets/downloader"
|
2
|
+
require "json"
|
3
|
+
require "securerandom"
|
4
|
+
|
5
|
+
module Charty
|
6
|
+
module Backends
|
7
|
+
module PlotlyHelpers
|
8
|
+
class HtmlRenderer
|
9
|
+
def initialize(use_cdn: true,
|
10
|
+
full_html: false,
|
11
|
+
requirejs: true)
|
12
|
+
@use_cdn = use_cdn
|
13
|
+
@full_html = full_html
|
14
|
+
@requirejs = requirejs
|
15
|
+
end
|
16
|
+
|
17
|
+
PLOTLY_URL = "https://plot.ly".freeze
|
18
|
+
PLOTLY_LATEST_CDN_URL = "https://cdn.plot.ly/plotly-latest.min.js".freeze
|
19
|
+
MATHJAX_CDN_URL = ("https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js").freeze
|
20
|
+
|
21
|
+
DEFAULT_WIDTH = "100%".freeze
|
22
|
+
DEFAULT_HEIGHT = 525
|
23
|
+
|
24
|
+
def render(figure, element_id: nil, post_script: nil)
|
25
|
+
element_id = SecureRandom.uuid if element_id.nil?
|
26
|
+
plotly_html_div = build_plotly_html_div(figure, element_id, post_script)
|
27
|
+
|
28
|
+
if @full_html
|
29
|
+
<<~END_HTML % {div: plotly_html_div}
|
30
|
+
<!DOCTYPE html>
|
31
|
+
<html>
|
32
|
+
<head><meta charset="utf-8" /></head>
|
33
|
+
<body>
|
34
|
+
%{div}
|
35
|
+
</body>
|
36
|
+
</html>
|
37
|
+
END_HTML
|
38
|
+
else
|
39
|
+
plotly_html_div
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private def build_plotly_html_div(figure, element_id, post_script)
|
44
|
+
layout = figure.fetch(:layout, {})
|
45
|
+
|
46
|
+
json_data = JSON.dump(figure.fetch(:data, []))
|
47
|
+
json_layout = JSON.dump(layout)
|
48
|
+
json_frames = JSON.dump(figure[:frames]) if figure.key?(:frames)
|
49
|
+
|
50
|
+
# TODO: config and responsive support
|
51
|
+
|
52
|
+
template = layout.fetch(:template, {}).fetch(:layout, {})
|
53
|
+
div_width = layout.fetch(:width, template.fetch(:width, DEFAULT_WIDTH))
|
54
|
+
div_height = layout.fetch(:height, template.fetch(:height, DEFAULT_HEIGHT))
|
55
|
+
|
56
|
+
div_width = "#{div_width}px" if Float(div_width, exception: false)
|
57
|
+
div_height = "#{div_height}px" if Float(div_height, exception: false)
|
58
|
+
|
59
|
+
# TODO: showLink and showSendToCloud support
|
60
|
+
base_url_line = "window.PLOTLYENV.BASE_URL = '%{url}';" % {url: PLOTLY_URL}
|
61
|
+
|
62
|
+
## build script body
|
63
|
+
|
64
|
+
# TODO: post_script support
|
65
|
+
then_post_script = ""
|
66
|
+
if post_script
|
67
|
+
ary = Array.try_convert(post_script)
|
68
|
+
post_script = ary || [post_script]
|
69
|
+
post_script.each do |ps|
|
70
|
+
next if ps.nil?
|
71
|
+
then_post_script << '.then(function(){ %{post_script} })' % {
|
72
|
+
post_script: ps % {plot_id: element_id}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
then_addframes = ""
|
78
|
+
then_animate = ""
|
79
|
+
if json_frames
|
80
|
+
then_addframes = <<~END_ADDFRAMES % {id: element_id, frames: json_frames}
|
81
|
+
.then(function(){
|
82
|
+
Plotly.addFrames('%{id}', {frames});
|
83
|
+
})
|
84
|
+
END_ADDFRAMES
|
85
|
+
|
86
|
+
# TODO: auto_play support
|
87
|
+
end
|
88
|
+
|
89
|
+
json_config = JSON.dump({}) # TODO: config support
|
90
|
+
|
91
|
+
script = <<~END_SCRIPT
|
92
|
+
if (document.getElementById("%{id}")) {
|
93
|
+
Plotly.newPlot("%{id}", %{data}, %{layout}, %{config})%{then_addframes}%{then_animate}%{then_post_script};
|
94
|
+
}
|
95
|
+
END_SCRIPT
|
96
|
+
script = script % {
|
97
|
+
id: element_id,
|
98
|
+
data: json_data,
|
99
|
+
layout: json_layout,
|
100
|
+
config: json_config,
|
101
|
+
then_addframes: then_addframes,
|
102
|
+
then_animate: then_animate,
|
103
|
+
then_post_script: then_post_script
|
104
|
+
}
|
105
|
+
|
106
|
+
## Handle loading/initializing plotlyjs
|
107
|
+
|
108
|
+
case
|
109
|
+
when @requirejs
|
110
|
+
include_plotlyjs = :require
|
111
|
+
include_mathjax = false
|
112
|
+
when @use_cdn
|
113
|
+
include_plotlyjs = :cdn
|
114
|
+
include_mathjax = :cdn
|
115
|
+
else
|
116
|
+
include_plotlyjs = true
|
117
|
+
include_mathjax = :cdn
|
118
|
+
end
|
119
|
+
|
120
|
+
case include_plotlyjs
|
121
|
+
when :require
|
122
|
+
require_start = 'require(["plotly"], function (Plotly) {'
|
123
|
+
require_end = '});'
|
124
|
+
when :cdn
|
125
|
+
load_plotlyjs = <<~END_LOAD_PLOTLYJS % {win_config: window_plotly_config, url: PLOTLY_LATEST_CDN_URL}
|
126
|
+
%{win_config}
|
127
|
+
<script src="%{url}"></script>
|
128
|
+
END_LOAD_PLOTLYJS
|
129
|
+
when true
|
130
|
+
load_plotlyjs = <<~END_LOAD_PLOTLYJS % {win_config: window_plotly_config, script: get_plotlyjs}
|
131
|
+
%{win_config}
|
132
|
+
<script type="text/javascript">%{script}</script>
|
133
|
+
END_LOAD_PLOTLYJS
|
134
|
+
end
|
135
|
+
|
136
|
+
## Handle loading/initializing MathJax
|
137
|
+
|
138
|
+
mathjax_tmplate = %Q[<script src="%{url}?config=TeX-AMS-MML_SVG"></script>]
|
139
|
+
case include_mathjax
|
140
|
+
when :cdn
|
141
|
+
mathjax_script = mathjax_tmplate % {url: MATHJAX_CDN_URL}
|
142
|
+
mathjax_script << <<~END_SCRIPT % {mathjax_config: mathjax_config}
|
143
|
+
<script type="text/javascript">%{mathjax_config}</script>
|
144
|
+
END_SCRIPT
|
145
|
+
else
|
146
|
+
mathjax_script = ""
|
147
|
+
end
|
148
|
+
|
149
|
+
div_template = <<~END_DIV
|
150
|
+
<div>
|
151
|
+
%{mathjax_script}
|
152
|
+
%{load_plotlyjs}
|
153
|
+
<div id="%{id}" class="plotly-graph-div" style="height: %{height}; width: %{width};"></div>
|
154
|
+
<script type="text/javascript">
|
155
|
+
%{require_start}
|
156
|
+
window.PLOTLYENV = window.PLOTLYENV || {};
|
157
|
+
%{base_url_line}
|
158
|
+
%{script}
|
159
|
+
%{require_end}
|
160
|
+
</script>
|
161
|
+
</div>
|
162
|
+
END_DIV
|
163
|
+
|
164
|
+
plotly_html_div = div_template % {
|
165
|
+
mathjax_script: mathjax_script,
|
166
|
+
load_plotlyjs: load_plotlyjs,
|
167
|
+
id: element_id,
|
168
|
+
height: div_height,
|
169
|
+
width: div_width,
|
170
|
+
require_start: require_start,
|
171
|
+
base_url_line: base_url_line,
|
172
|
+
script: script,
|
173
|
+
require_end: require_end
|
174
|
+
}
|
175
|
+
plotly_html_div.strip!
|
176
|
+
|
177
|
+
plotly_html_div
|
178
|
+
end
|
179
|
+
|
180
|
+
private def window_plotly_config
|
181
|
+
%Q(window.PlotlyConfig = {MathJaxConfig: 'local'};)
|
182
|
+
end
|
183
|
+
|
184
|
+
private def mathjax_config
|
185
|
+
%Q(if (window.MathJax) { MathJax.Hub.Config({SVG: {font: "STIX-Web"}}); })
|
186
|
+
end
|
187
|
+
|
188
|
+
private def get_plotlyjs
|
189
|
+
cache_path = CacheDir.path("plotly.min.js")
|
190
|
+
unless cache_path.exist?
|
191
|
+
download_plotlyjs(cache_path)
|
192
|
+
end
|
193
|
+
cache_path.read
|
194
|
+
end
|
195
|
+
|
196
|
+
private def download_plotlyjs(output_path)
|
197
|
+
downloader = Datasets::Downloader.new(PLOTLY_LATEST_CDN_URL)
|
198
|
+
downloader.download(output_path)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|