inkplot 0.3.1 → 0.3.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6adf2de18dafb5d84431bcf3d6a9505dfcf17d9a20587045b5a900e554d1c79e
4
- data.tar.gz: e175007fcd7109ef9f5a35c8c3741b94d733cf436543152fc597cc028d7dfb34
3
+ metadata.gz: 570091faeb52297dab7d74cc8bf77a37f32f69b9f8bc99e8d24df631e43082c2
4
+ data.tar.gz: 8f69487642335b444a7a50961e077f216a7cb269947749cc463449e4b19d72c0
5
5
  SHA512:
6
- metadata.gz: b5786c86bf094c6a71e3867b66d1781b0f1c58edd743c36ce843278d4792530a3112c92d996777afc2db548cdf520baf0462dfad27cdae04c6632aa11dd53563
7
- data.tar.gz: 8923af448e4d10ea8700831876a1c8f8aa0d67379f618e487b72e0ad8aeba50b13ec0b9a391d5eabe19613a21ca0b2da7c010c2db201d8dc13acac3785ef997c
6
+ metadata.gz: 279de78c919ae89c44b923e0d3880399b22a40040c84dd9b2d7d4e74e8abf0e263d7a8bd378b4d7e40b813e473885da31b14e9ebaf2c363222e983b1094034d1
7
+ data.tar.gz: cf1e3a1d032bee953d177eba082a0b3b13e96621a15363f2c586710d5e7453e73eb2eded277be046dc839bf985700fceccc0d749be99c3e1fde7595442a8945c
data/.codespellignore ADDED
File without changes
data/.yamllint ADDED
@@ -0,0 +1,16 @@
1
+ extends: default
2
+ ignore: |
3
+ build/
4
+ node_modules/
5
+ runtime/build/
6
+ tmp/
7
+ **/*.dSYM/**
8
+
9
+ rules:
10
+ comments:
11
+ min-spaces-from-content: 1
12
+ document-start: disable
13
+ line-length:
14
+ max: 200
15
+ truthy:
16
+ check-keys: false
data/CHANGELOG.md CHANGED
@@ -1,11 +1,14 @@
1
1
  # Changelog
2
2
 
3
- No 0.2.0 release was published. The 0.3.1 gem contains the PNG and chart features described below.
3
+ ## [0.3.2] - 2026-09-26
4
+
5
+ - Keep histogram scales finite at extreme numeric values and distinguish very small chart values on axes.
6
+ - Report when chart dimensions cannot fit labels or a legend.
4
7
 
5
8
  ## [0.3.1] - 2026-09-25
6
9
 
7
- - Include the PNG renderer and expanded chart features in the published gem.
8
- - Resolve optional renderer dependencies from RubyGems.
10
+ - Make PNG rendering and the expanded chart features available in the installed gem.
11
+ - Fix installation of optional renderer dependencies from RubyGems.
9
12
 
10
13
  ## [0.3.0] - 2026-09-25
11
14
 
data/lib/inkplot/core.rb CHANGED
@@ -76,7 +76,12 @@ module Inkplot
76
76
  index = value == edges.last ? counts.length - 1 : upper && (upper - 1)
77
77
  counts[index] += 1 if index&.between?(0, counts.length - 1)
78
78
  end
79
- counts.each_index.map { |index| { x: (edges[index] + edges[index + 1]) / 2.0, x0: edges[index], x1: edges[index + 1], y: counts[index] } }
79
+ counts.each_index.map do |index|
80
+ left, right = edges[index, 2]
81
+ span = right - left
82
+ center = span.finite? ? left + (span / 2.0) : (left / 2.0) + (right / 2.0)
83
+ { x: center, x0: left, x1: right, y: counts[index] }
84
+ end
80
85
  end
81
86
 
82
87
  def edges(values, bins)
@@ -84,8 +89,12 @@ module Inkplot
84
89
 
85
90
  low, high = values.minmax
86
91
  if low == high
87
- low -= 0.5
88
- high += 0.5
92
+ lower = low - 0.5
93
+ upper = high + 0.5
94
+ low = lower.finite? && lower < low ? lower : low.prev_float
95
+ high = upper.finite? && upper > high ? upper : high.next_float
96
+ low = values.first unless low.finite?
97
+ high = values.first unless high.finite?
89
98
  end
90
99
  count = if bins == :auto
91
100
  sturges = (Math.log2(values.length) + 1).ceil
@@ -98,8 +107,17 @@ module Inkplot
98
107
  raise ArgumentError, "bins must be :auto, a positive Integer, or an increasing edge Array"
99
108
  end
100
109
  count = count.clamp(1, values.length) if bins == :auto
101
- width = (high - low) / count
102
- Array.new(count + 1) { |index| index == count ? high : low + (index * width) }
110
+ span = high - low
111
+ Array.new(count + 1) do |index|
112
+ if index.zero?
113
+ low
114
+ elsif index == count
115
+ high
116
+ else
117
+ fraction = index.to_f / count
118
+ span.finite? ? low + (span * fraction) : (low * (1 - fraction)) + (high * fraction)
119
+ end
120
+ end.uniq
103
121
  end
104
122
  private_class_method :edges
105
123
 
@@ -125,6 +143,7 @@ module Inkplot
125
143
 
126
144
  def linear(minimum, maximum, count: 5)
127
145
  return [minimum] if minimum >= maximum
146
+ return [minimum, 0.0, maximum] unless (maximum - minimum).finite?
128
147
 
129
148
  step = linear_step(minimum, maximum, count:)
130
149
  first = (minimum / step).ceil * step
@@ -141,8 +160,12 @@ module Inkplot
141
160
  def linear_step(minimum, maximum, count: 5)
142
161
  return 1.0 unless maximum > minimum
143
162
 
144
- raw = (maximum - minimum).to_f / [count - 1, 1].max
163
+ span = (maximum - minimum).to_f
164
+ raw = span / [count - 1, 1].max
165
+ raw = span if raw.zero?
145
166
  power = 10.0**Math.log10(raw).floor
167
+ return raw if power.zero?
168
+
146
169
  fraction = raw / power
147
170
  (if fraction <= 1
148
171
  1
@@ -240,6 +263,8 @@ module Inkplot
240
263
  private_class_method :time_at
241
264
 
242
265
  def number_label(value)
266
+ return format("%.8g", value) if !value.zero? && value.abs < 1e-6
267
+
243
268
  value.to_i == value ? value.to_i.to_s : format("%.8f", value).sub(/0+\z/, "").sub(/\.\z/, "")
244
269
  end
245
270
  end
@@ -268,9 +293,11 @@ module Inkplot
268
293
  raise ArgumentError, "linear axis minimum must be less than maximum" unless low < high
269
294
 
270
295
  @ticks = Ticks.linear(low, high)
271
- step = Ticks.linear_step(low, high)
272
- low = (low / step).floor * step if options[:min].nil?
273
- high = (high / step).ceil * step if options[:max].nil?
296
+ if (high - low).finite?
297
+ step = Ticks.linear_step(low, high)
298
+ low = (low / step).floor * step if options[:min].nil?
299
+ high = (high / step).ceil * step if options[:max].nil?
300
+ end
274
301
  @domain = [low, high]
275
302
  end
276
303
 
@@ -278,7 +305,14 @@ module Inkplot
278
305
  value = Data.number(value)
279
306
  return nil unless value
280
307
 
281
- @range[0] + ((value - @domain[0]) * (@range[1] - @range[0]) / (@domain[1] - @domain[0]))
308
+ span = @domain[1] - @domain[0]
309
+ fraction = (value - @domain[0]) / span
310
+ unless span.finite?
311
+ numerator = (value / 2.0) - (@domain[0] / 2.0)
312
+ denominator = (@domain[1] / 2.0) - (@domain[0] / 2.0)
313
+ fraction = numerator / denominator
314
+ end
315
+ @range[0] + (fraction * (@range[1] - @range[0]))
282
316
  end
283
317
 
284
318
  def format(value) = Ticks.number_label(value)
@@ -735,6 +769,8 @@ module Inkplot
735
769
  shown_gap = plot_width.to_f / [shown_ticks.length - 1, 1].max
736
770
  rotate_ticks = height >= 180 && shown_ticks.any? { |index| TextMetrics.width(x_scale.format(x_ticks[index]), 10) > shown_gap * 0.75 }
737
771
  bottom += 42 if rotate_ticks
772
+ raise ArgumentError, "chart dimensions are too small for labels or legend" if plot_width <= 0 || height - top - bottom <= 0
773
+
738
774
  x_scale.range = [left, width - right]
739
775
  y_scale.range = [height - bottom, top]
740
776
  clip = [left, top, width - right, height - bottom]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Inkplot
4
- VERSION = "0.3.1"
4
+ VERSION = "0.3.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inkplot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yudai Takada
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-09-25 00:00:00.000000000 Z
11
+ date: 2026-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '3.0'
33
+ version: '4.1'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '3.0'
40
+ version: '4.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -74,7 +74,9 @@ executables: []
74
74
  extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
+ - ".codespellignore"
77
78
  - ".rubocop.yml"
79
+ - ".yamllint"
78
80
  - CHANGELOG.md
79
81
  - LICENSE.txt
80
82
  - README.md