charty 0.2.5 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -1
- data/charty.gemspec +8 -5
- data/lib/charty.rb +2 -2
- data/lib/charty/backends/plotly.rb +197 -8
- data/lib/charty/backends/pyplot.rb +135 -44
- data/lib/charty/dash_pattern_generator.rb +57 -0
- data/lib/charty/index.rb +1 -1
- data/lib/charty/plot_methods.rb +73 -3
- data/lib/charty/plotters.rb +1 -0
- data/lib/charty/plotters/abstract_plotter.rb +69 -9
- data/lib/charty/plotters/line_plotter.rb +300 -0
- data/lib/charty/plotters/relational_plotter.rb +213 -96
- data/lib/charty/plotters/scatter_plotter.rb +7 -31
- data/lib/charty/statistics.rb +2 -2
- data/lib/charty/table.rb +124 -14
- data/lib/charty/table_adapters/base_adapter.rb +97 -0
- data/lib/charty/table_adapters/daru_adapter.rb +2 -0
- data/lib/charty/table_adapters/datasets_adapter.rb +7 -0
- data/lib/charty/table_adapters/hash_adapter.rb +13 -2
- data/lib/charty/table_adapters/pandas_adapter.rb +82 -0
- data/lib/charty/util.rb +8 -0
- data/lib/charty/vector_adapters.rb +5 -1
- data/lib/charty/vector_adapters/array_adapter.rb +2 -10
- data/lib/charty/vector_adapters/daru_adapter.rb +3 -11
- data/lib/charty/vector_adapters/narray_adapter.rb +1 -6
- data/lib/charty/vector_adapters/numpy_adapter.rb +1 -1
- data/lib/charty/vector_adapters/pandas_adapter.rb +0 -1
- data/lib/charty/version.rb +1 -1
- metadata +54 -25
- data/lib/charty/missing_value_support.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63e13663e8213e077993e52b906b630c35a1f7f9a224abb99fd206bb700659c2
|
4
|
+
data.tar.gz: d7fd53056c32c18bf5af6b1e1a4b2a29bfe652a427b338087d3cab538a0797ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc4da146432f688eb52dd382ea516e02ab84ef7143453c80fa5bc14fef55851728550ee58fe98c1c3a5e9a1eac0f33dcfb702356bc7c0f344ceaf85f87400435
|
7
|
+
data.tar.gz: f519610073317c3fafd42b97ad5e96d124265f6a7d79a54023995cf82d1fe84624d4f914c26e3eef644ad280110400fe1cdac275ec5e32145d7e4b652ef47891
|
data/README.md
CHANGED
@@ -100,7 +100,8 @@ Charty::Backends.use(:plotly) # select plotly backend
|
|
100
100
|
plot.save("scatter.html") # save the plot as an HTML file
|
101
101
|
```
|
102
102
|
|
103
|
-
|
103
|
+
When you already have prepared [playwright-ruby-client](https://github.com/YusukeIwaki/playwright-ruby-client),
|
104
|
+
you can render a plot into a PNG file by plotly backend by specifying a filename with `.png` extension.
|
104
105
|
|
105
106
|
```ruby
|
106
107
|
plot.save("scatter.png")
|
data/charty.gemspec
CHANGED
@@ -26,17 +26,20 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
27
|
spec.require_paths = ["lib"]
|
28
28
|
|
29
|
-
spec.add_dependency "red-colors"
|
30
|
-
spec.add_dependency "red-palette", ">= 0.
|
29
|
+
spec.add_dependency "red-colors", ">= 0.3.0"
|
30
|
+
spec.add_dependency "red-palette", ">= 0.5.0"
|
31
|
+
|
32
|
+
spec.add_dependency "matplotlib", ">= 1.2.0"
|
33
|
+
spec.add_dependency "pandas", ">= 0.3.5"
|
34
|
+
spec.add_dependency "playwright-ruby-client"
|
31
35
|
|
32
36
|
spec.add_development_dependency "bundler", ">= 1.16"
|
33
37
|
spec.add_development_dependency "rake"
|
34
38
|
spec.add_development_dependency "test-unit"
|
35
|
-
spec.add_development_dependency "red-datasets", ">= 0.
|
39
|
+
spec.add_development_dependency "red-datasets", ">= 0.1.2"
|
36
40
|
spec.add_development_dependency "daru"
|
37
41
|
spec.add_development_dependency "matrix" # need for daru on Ruby > 3.0
|
38
42
|
spec.add_development_dependency "activerecord"
|
39
43
|
spec.add_development_dependency "sqlite3"
|
40
|
-
spec.add_development_dependency "
|
41
|
-
spec.add_development_dependency "iruby"
|
44
|
+
spec.add_development_dependency "iruby", ">= 0.7.0"
|
42
45
|
end
|
data/lib/charty.rb
CHANGED
@@ -4,17 +4,17 @@ require "colors"
|
|
4
4
|
require "palette"
|
5
5
|
|
6
6
|
require_relative "charty/util"
|
7
|
+
require_relative "charty/dash_pattern_generator"
|
7
8
|
require_relative "charty/backends"
|
8
9
|
require_relative "charty/backend_methods"
|
9
10
|
require_relative "charty/plotter"
|
10
11
|
require_relative "charty/index"
|
11
12
|
require_relative "charty/layout"
|
12
13
|
require_relative "charty/linspace"
|
13
|
-
require_relative "charty/missing_value_support"
|
14
14
|
require_relative "charty/plotters"
|
15
15
|
require_relative "charty/plot_methods"
|
16
|
-
require_relative "charty/table_adapters"
|
17
16
|
require_relative "charty/table"
|
17
|
+
require_relative "charty/table_adapters"
|
18
18
|
require_relative "charty/statistics"
|
19
19
|
require_relative "charty/vector_adapters"
|
20
20
|
require_relative "charty/vector"
|
@@ -248,12 +248,8 @@ module Charty
|
|
248
248
|
@traces.concat(traces)
|
249
249
|
end
|
250
250
|
|
251
|
-
def scatter(x, y, variables,
|
251
|
+
def scatter(x, y, variables, color:, color_mapper:,
|
252
252
|
style:, style_mapper:, size:, size_mapper:)
|
253
|
-
if legend == :full
|
254
|
-
warn("Plotly backend does not support full verbosity legend")
|
255
|
-
end
|
256
|
-
|
257
253
|
orig_x, orig_y = x, y
|
258
254
|
|
259
255
|
x = case x
|
@@ -277,7 +273,7 @@ module Charty
|
|
277
273
|
end
|
278
274
|
|
279
275
|
unless color.nil? && style.nil?
|
280
|
-
grouped_scatter(x, y, variables,
|
276
|
+
grouped_scatter(x, y, variables,
|
281
277
|
color: color, color_mapper: color_mapper,
|
282
278
|
style: style, style_mapper: style_mapper,
|
283
279
|
size: size, size_mapper: size_mapper)
|
@@ -305,7 +301,7 @@ module Charty
|
|
305
301
|
@traces << trace
|
306
302
|
end
|
307
303
|
|
308
|
-
private def grouped_scatter(x, y, variables,
|
304
|
+
private def grouped_scatter(x, y, variables, color:, color_mapper:,
|
309
305
|
style:, style_mapper:, size:, size_mapper:)
|
310
306
|
@layout[:showlegend] = true
|
311
307
|
|
@@ -333,7 +329,9 @@ module Charty
|
|
333
329
|
|
334
330
|
unless size.nil?
|
335
331
|
vals = size.values_at(*indices)
|
336
|
-
trace[:marker][:size] = size_mapper[vals].map
|
332
|
+
trace[:marker][:size] = size_mapper[vals].map do |x|
|
333
|
+
scale_scatter_point_size(x).to_f
|
334
|
+
end
|
337
335
|
end
|
338
336
|
|
339
337
|
name = []
|
@@ -362,6 +360,12 @@ module Charty
|
|
362
360
|
end
|
363
361
|
end
|
364
362
|
|
363
|
+
def add_scatter_plot_legend(variables, color_mapper, size_mapper, style_mapper, legend)
|
364
|
+
if legend == :full
|
365
|
+
warn("Plotly backend does not support full verbosity legend")
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
365
369
|
private def scale_scatter_point_size(x)
|
366
370
|
min = 6
|
367
371
|
max = 12
|
@@ -369,6 +373,191 @@ module Charty
|
|
369
373
|
min + x * (max - min)
|
370
374
|
end
|
371
375
|
|
376
|
+
def line(x, y, variables, color:, color_mapper:, size:, size_mapper:, style:, style_mapper:, ci_params:)
|
377
|
+
x = case x
|
378
|
+
when Charty::Vector
|
379
|
+
x.to_a
|
380
|
+
else
|
381
|
+
orig_x, x = x, Array.try_convert(x)
|
382
|
+
if x.nil?
|
383
|
+
raise ArgumentError, "Invalid value for x: %p" % orig_x
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
y = case y
|
388
|
+
when Charty::Vector
|
389
|
+
y.to_a
|
390
|
+
else
|
391
|
+
orig_y, y = y, Array.try_convert(y)
|
392
|
+
if y.nil?
|
393
|
+
raise ArgumentError, "Invalid value for y: %p" % orig_y
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
name = []
|
398
|
+
legend_title = []
|
399
|
+
|
400
|
+
if color.nil?
|
401
|
+
# TODO: do not hard code this
|
402
|
+
line_color = Colors["#1f77b4"] # the first color of D3's category10 palette
|
403
|
+
else
|
404
|
+
line_color = color_mapper[color].to_rgb
|
405
|
+
name << color
|
406
|
+
legend_title << variables[:color]
|
407
|
+
end
|
408
|
+
|
409
|
+
unless style.nil?
|
410
|
+
marker, dashes = style_mapper[style].values_at(:marker, :dashes)
|
411
|
+
name << style
|
412
|
+
legend_title << variables[:style]
|
413
|
+
end
|
414
|
+
|
415
|
+
trace = {
|
416
|
+
type: :scatter,
|
417
|
+
mode: marker.nil? ? "lines" : "lines+markers",
|
418
|
+
x: x,
|
419
|
+
y: y,
|
420
|
+
line: {
|
421
|
+
shape: :linear,
|
422
|
+
color: line_color.to_hex_string
|
423
|
+
}
|
424
|
+
}
|
425
|
+
|
426
|
+
default_line_width = 2.0
|
427
|
+
unless size.nil?
|
428
|
+
line_width = default_line_width + 2.0 * size_mapper[size]
|
429
|
+
trace[:line][:width] = line_width
|
430
|
+
end
|
431
|
+
|
432
|
+
unless dashes.nil?
|
433
|
+
trace[:line][:dash] = convert_dash_pattern(dashes, line_width || default_line_width)
|
434
|
+
end
|
435
|
+
|
436
|
+
unless marker.nil?
|
437
|
+
trace[:marker] = {
|
438
|
+
line: {
|
439
|
+
width: 1,
|
440
|
+
color: "#fff"
|
441
|
+
},
|
442
|
+
symbol: marker,
|
443
|
+
size: 10
|
444
|
+
}
|
445
|
+
end
|
446
|
+
|
447
|
+
unless ci_params.nil?
|
448
|
+
case ci_params[:style]
|
449
|
+
when :band
|
450
|
+
y_min = ci_params[:y_min].to_a
|
451
|
+
y_max = ci_params[:y_max].to_a
|
452
|
+
@traces << {
|
453
|
+
type: :scatter,
|
454
|
+
x: x,
|
455
|
+
y: y_max,
|
456
|
+
mode: :lines,
|
457
|
+
line: { shape: :linear, width: 0 },
|
458
|
+
showlegend: false
|
459
|
+
}
|
460
|
+
@traces << {
|
461
|
+
type: :scatter,
|
462
|
+
x: x,
|
463
|
+
y: y_min,
|
464
|
+
mode: :lines,
|
465
|
+
line: { shape: :linear, width: 0 },
|
466
|
+
fill: :tonexty,
|
467
|
+
fillcolor: line_color.to_rgba(alpha: 0.2).to_hex_string,
|
468
|
+
showlegend: false
|
469
|
+
}
|
470
|
+
when :bars
|
471
|
+
y_min = ci_params[:y_min].map.with_index {|v, i| y[i] - v }
|
472
|
+
y_max = ci_params[:y_max].map.with_index {|v, i| v - y[i] }
|
473
|
+
trace[:error_y] = {
|
474
|
+
visible: true,
|
475
|
+
type: :data,
|
476
|
+
array: y_max,
|
477
|
+
arrayminus: y_min
|
478
|
+
}
|
479
|
+
unless line_color.nil?
|
480
|
+
trace[:error_y][:color] = line_color
|
481
|
+
end
|
482
|
+
unless line_width.nil?
|
483
|
+
trace[:error_y][:thickness] = line_width
|
484
|
+
end
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
trace[:name] = name.uniq.join(", ") unless name.empty?
|
489
|
+
|
490
|
+
@traces << trace
|
491
|
+
|
492
|
+
unless legend_title.empty?
|
493
|
+
@layout[:showlegend] = true
|
494
|
+
@layout[:legend] ||= {}
|
495
|
+
@layout[:legend][:title] = {text: legend_title.uniq.join(", ")}
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
def add_line_plot_legend(variables, color_mapper, size_mapper, style_mapper, legend)
|
500
|
+
if legend == :full
|
501
|
+
warn("Plotly backend does not support full verbosity legend")
|
502
|
+
end
|
503
|
+
|
504
|
+
legend_order = if variables.key?(:color)
|
505
|
+
if variables.key?(:style)
|
506
|
+
# both color and style
|
507
|
+
color_mapper.levels.product(style_mapper.levels)
|
508
|
+
else
|
509
|
+
# only color
|
510
|
+
color_mapper.levels
|
511
|
+
end
|
512
|
+
elsif variables.key?(:style)
|
513
|
+
# only style
|
514
|
+
style_mapper.levels
|
515
|
+
else
|
516
|
+
# no legend entries
|
517
|
+
nil
|
518
|
+
end
|
519
|
+
|
520
|
+
if legend_order
|
521
|
+
# sort traces
|
522
|
+
legend_index = legend_order.map.with_index { |name, i|
|
523
|
+
[Array(name).uniq.join(", "), i]
|
524
|
+
}.to_h
|
525
|
+
@traces = @traces.each_with_index.sort_by { |trace, trace_index|
|
526
|
+
index = legend_index.fetch(trace[:name], legend_order.length)
|
527
|
+
[index, trace_index]
|
528
|
+
}.map(&:first)
|
529
|
+
|
530
|
+
# remove duplicated legend entries
|
531
|
+
names = {}
|
532
|
+
@traces.each do |trace|
|
533
|
+
if trace[:showlegend] != false
|
534
|
+
name = trace[:name]
|
535
|
+
if name
|
536
|
+
if names.key?(name)
|
537
|
+
# Hide duplications
|
538
|
+
trace[:showlegend] = false
|
539
|
+
else
|
540
|
+
trace[:showlegend] = true
|
541
|
+
names[name] = true
|
542
|
+
end
|
543
|
+
else
|
544
|
+
# Hide no name trace in legend
|
545
|
+
trace[:showlegend] = false
|
546
|
+
end
|
547
|
+
end
|
548
|
+
end
|
549
|
+
end
|
550
|
+
end
|
551
|
+
|
552
|
+
private def convert_dash_pattern(pattern, line_width)
|
553
|
+
case pattern
|
554
|
+
when ""
|
555
|
+
:solid
|
556
|
+
else
|
557
|
+
pattern.map {|d| "#{line_width * d}px" }.join(",")
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
372
561
|
def set_xlabel(label)
|
373
562
|
@layout[:xaxis] ||= {}
|
374
563
|
@layout[:xaxis][:title] = label
|
@@ -303,7 +303,7 @@ module Charty
|
|
303
303
|
end
|
304
304
|
end
|
305
305
|
|
306
|
-
def scatter(x, y, variables,
|
306
|
+
def scatter(x, y, variables, color:, color_mapper:,
|
307
307
|
style:, style_mapper:, size:, size_mapper:)
|
308
308
|
kwd = {}
|
309
309
|
kwd[:edgecolor] = "w"
|
@@ -317,7 +317,7 @@ module Charty
|
|
317
317
|
end
|
318
318
|
|
319
319
|
unless size.nil?
|
320
|
-
size = size_mapper[size].map(
|
320
|
+
size = size_mapper[size].map {|x| scale_scatter_point_size(x).to_f }
|
321
321
|
points.set_sizes(size)
|
322
322
|
end
|
323
323
|
|
@@ -328,14 +328,15 @@ module Charty
|
|
328
328
|
|
329
329
|
sizes = points.get_sizes
|
330
330
|
points.set_linewidths(0.08 * Numpy.sqrt(Numpy.percentile(sizes, 10)))
|
331
|
+
end
|
331
332
|
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
333
|
+
def add_scatter_plot_legend(variables, color_mapper, size_mapper, style_mapper, legend)
|
334
|
+
ax = @pyplot.gca
|
335
|
+
add_relational_plot_legend(
|
336
|
+
ax, variables, color_mapper, size_mapper, style_mapper,
|
337
|
+
legend, [:color, :s, :marker]
|
338
|
+
) do |label, kwargs|
|
339
|
+
ax.scatter([], [], label: label, **kwargs)
|
339
340
|
end
|
340
341
|
end
|
341
342
|
|
@@ -369,8 +370,8 @@ module Charty
|
|
369
370
|
|
370
371
|
RELATIONAL_PLOT_LEGEND_BRIEF_TICKS = 6
|
371
372
|
|
372
|
-
private def add_relational_plot_legend(ax,
|
373
|
-
legend_attributes, &func)
|
373
|
+
private def add_relational_plot_legend(ax, variables, color_mapper, size_mapper, style_mapper,
|
374
|
+
verbosity, legend_attributes, &func)
|
374
375
|
brief_ticks = RELATIONAL_PLOT_LEGEND_BRIEF_TICKS
|
375
376
|
verbosity = :auto if verbosity == true
|
376
377
|
|
@@ -391,24 +392,17 @@ module Charty
|
|
391
392
|
|
392
393
|
# color legend
|
393
394
|
|
394
|
-
brief_color =
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
false
|
400
|
-
else
|
401
|
-
color_mapper.levels.length > brief_ticks
|
402
|
-
end
|
403
|
-
else
|
404
|
-
false
|
405
|
-
end
|
395
|
+
brief_color = (color_mapper.map_type == :numeric) && (
|
396
|
+
(verbosity == :brief) || (
|
397
|
+
verbosity == :auto && color_mapper.levels.length > brief_ticks
|
398
|
+
)
|
399
|
+
)
|
406
400
|
case
|
407
401
|
when brief_color
|
408
402
|
# TODO: Also support LogLocator
|
409
403
|
# locator = Matplotlib.ticker.LogLocator.new(numticks: brief_ticks)
|
410
404
|
locator = Matplotlib.ticker.MaxNLocator.new(nbins: brief_ticks)
|
411
|
-
limits =
|
405
|
+
limits = color_mapper.levels.minmax
|
412
406
|
color_levels, color_formatted_levels = locator_to_legend_entries(locator, limits)
|
413
407
|
when color_mapper.levels.nil?
|
414
408
|
color_levels = color_formatted_levels = []
|
@@ -422,22 +416,14 @@ module Charty
|
|
422
416
|
|
423
417
|
color_levels.length.times do |i|
|
424
418
|
next if color_levels[i].nil?
|
425
|
-
color_value = color_mapper[color_levels[i]].to_hex_string
|
419
|
+
color_value = color_mapper[color_levels[i]].to_rgb.to_hex_string
|
426
420
|
update_legend.(variables[:color], color_formatted_levels[i], color: color_value)
|
427
421
|
end
|
428
422
|
|
429
|
-
brief_size =
|
430
|
-
|
431
|
-
size_mapper.
|
432
|
-
|
433
|
-
if size_mapper.levels.nil?
|
434
|
-
false
|
435
|
-
else
|
436
|
-
size_mapper.levels.length > brief_ticks
|
437
|
-
end
|
438
|
-
else
|
439
|
-
false
|
440
|
-
end
|
423
|
+
brief_size = (size_mapper.map_type == :numeric) && (
|
424
|
+
verbosity == :brief ||
|
425
|
+
(verbosity == :auto && size_mapper.levels.length > brief_ticks)
|
426
|
+
)
|
441
427
|
case
|
442
428
|
when brief_size
|
443
429
|
# TODO: Also support LogLocator
|
@@ -457,8 +443,9 @@ module Charty
|
|
457
443
|
|
458
444
|
size_levels.length.times do |i|
|
459
445
|
next if size_levels[i].nil?
|
460
|
-
|
461
|
-
|
446
|
+
line_width = scale_line_width(size_mapper[size_levels[i]])
|
447
|
+
point_size = scale_scatter_point_size(size_mapper[size_levels[i]])
|
448
|
+
update_legend.(variables[:size], size_formatted_levels[i], linewidth: line_width, s: point_size)
|
462
449
|
end
|
463
450
|
|
464
451
|
if legend_title.nil? && variables.key?(:style)
|
@@ -474,10 +461,12 @@ module Charty
|
|
474
461
|
else
|
475
462
|
""
|
476
463
|
end
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
464
|
+
dashes = if attrs.key?(:dashes)
|
465
|
+
attrs[:dashes]
|
466
|
+
else
|
467
|
+
""
|
468
|
+
end
|
469
|
+
update_legend.(variables[:style], level, marker: marker, dashes: dashes)
|
481
470
|
end
|
482
471
|
end
|
483
472
|
|
@@ -505,9 +494,96 @@ module Charty
|
|
505
494
|
min + x * (max - min)
|
506
495
|
end
|
507
496
|
|
497
|
+
def line(x, y, variables, color:, color_mapper:, size:, size_mapper:, style:, style_mapper:, ci_params:)
|
498
|
+
kws = {
|
499
|
+
markeredgewidth: 0.75,
|
500
|
+
markeredgecolor: "w",
|
501
|
+
}
|
502
|
+
ax = @pyplot.gca
|
503
|
+
|
504
|
+
x = x.to_a
|
505
|
+
y = y.to_a
|
506
|
+
lines = ax.plot(x, y, **kws)
|
507
|
+
|
508
|
+
lines.each do |line|
|
509
|
+
unless color.nil?
|
510
|
+
line.set_color(color_mapper[color].to_rgb.to_hex_string)
|
511
|
+
end
|
512
|
+
|
513
|
+
unless size.nil?
|
514
|
+
scaled_size = scale_line_width(size_mapper[size])
|
515
|
+
line.set_linewidth(scaled_size.to_f)
|
516
|
+
end
|
517
|
+
|
518
|
+
unless style.nil?
|
519
|
+
attributes = style_mapper[style]
|
520
|
+
if attributes.key?(:dashes)
|
521
|
+
line.set_dashes(attributes[:dashes])
|
522
|
+
end
|
523
|
+
if attributes.key?(:marker)
|
524
|
+
line.set_marker(PYPLOT_MARKERS[attributes[:marker]])
|
525
|
+
end
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
# TODO: support color, size, and style
|
530
|
+
|
531
|
+
line = lines[0]
|
532
|
+
line_color = line.get_color
|
533
|
+
line_alpha = line.get_alpha
|
534
|
+
line_capstyle = line.get_solid_capstyle
|
535
|
+
|
536
|
+
unless ci_params.nil?
|
537
|
+
y_min = ci_params[:y_min].to_a
|
538
|
+
y_max = ci_params[:y_max].to_a
|
539
|
+
case ci_params[:style]
|
540
|
+
when :band
|
541
|
+
# TODO: support to supply `alpha` via `err_kws`
|
542
|
+
ax.fill_between(x, y_min, y_max, color: line_color, alpha: 0.2)
|
543
|
+
when :bars
|
544
|
+
error_deltas = [
|
545
|
+
y.zip(y_min).map {|v, v_min| v - v_min },
|
546
|
+
y.zip(y_max).map {|v, v_max| v_max - v }
|
547
|
+
]
|
548
|
+
ebars = ax.errorbar(x, y, error_deltas,
|
549
|
+
linestyle: "", color: line_color, alpha: line_alpha)
|
550
|
+
ebars.get_children.each do |bar|
|
551
|
+
case bar
|
552
|
+
when Matplotlib.collections.LineCollection
|
553
|
+
bar.set_capstyle(line_capstyle)
|
554
|
+
end
|
555
|
+
end
|
556
|
+
end
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
560
|
+
def add_line_plot_legend(variables, color_mapper, size_mapper, style_mapper, legend)
|
561
|
+
ax = @pyplot.gca
|
562
|
+
add_relational_plot_legend(
|
563
|
+
ax, variables, color_mapper, size_mapper, style_mapper,
|
564
|
+
legend, [:color, :linewidth, :marker, :dashes]
|
565
|
+
) do |label, kwargs|
|
566
|
+
ax.plot([], [], label: label, **kwargs)
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
|
571
|
+
private def scale_line_width(x)
|
572
|
+
min = 0.5 * @default_line_width
|
573
|
+
max = 2.0 * @default_line_width
|
574
|
+
|
575
|
+
min + x * (max - min)
|
576
|
+
end
|
577
|
+
|
508
578
|
private def locator_to_legend_entries(locator, limits)
|
509
579
|
vmin, vmax = limits
|
510
|
-
|
580
|
+
dtype = case vmin
|
581
|
+
when Numeric
|
582
|
+
:float64
|
583
|
+
else
|
584
|
+
:object
|
585
|
+
end
|
586
|
+
raw_levels = locator.tick_values(vmin, vmax).astype(dtype).to_a
|
511
587
|
raw_levels.reject! {|v| v < limits[0] || limits[1] < v }
|
512
588
|
|
513
589
|
formatter = case locator
|
@@ -596,6 +672,21 @@ module Charty
|
|
596
672
|
show
|
597
673
|
end
|
598
674
|
|
675
|
+
SAVEFIG_OPTIONAL_PARAMS = [
|
676
|
+
:dpi, :quality, :optimize, :progressive, :facecolor, :edgecolor,
|
677
|
+
:orientation, :papertype, :transparent, :bbox_inches, :pad_inches,
|
678
|
+
:bbox_extra_artists, :backend, :metadata, :pil_kwargs
|
679
|
+
].freeze
|
680
|
+
|
681
|
+
def save(filename, format: nil, title: nil, width: 700, height: 500, **kwargs)
|
682
|
+
params = {}
|
683
|
+
params[:format] = format unless format.nil?
|
684
|
+
SAVEFIG_OPTIONAL_PARAMS.each do |key|
|
685
|
+
params[key] = kwargs[key] if kwargs.key?(key)
|
686
|
+
end
|
687
|
+
@pyplot.savefig(filename, **params)
|
688
|
+
end
|
689
|
+
|
599
690
|
def show
|
600
691
|
@pyplot.show
|
601
692
|
end
|