p5rb 0.0.1 → 0.0.3

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.
Files changed (4) hide show
  1. checksums.yaml +5 -5
  2. data/lib/p5rb.rb +167 -54
  3. data/p5rb.gemspec +3 -1
  4. metadata +18 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2aeb9b49c2eeadc91b80d5c207e65e71d510ec41
4
- data.tar.gz: cb3054c7c311fa1862f9395b5ff1762e055421e3
2
+ SHA256:
3
+ metadata.gz: b79ebfd6c7fa06d28955e916d1dd8c40f550eac344f03b7eaf65f6281c3bed2f
4
+ data.tar.gz: f2b2555f10efd15b009e146dc232a3b947514960cb81c81487bc0c8d39e205e1
5
5
  SHA512:
6
- metadata.gz: '074992392feb37241a790014a43b600f30f513c4307fcfddd24c0db3820eb7d69c97088fd9e44ec65ca18315133b076897ceae2487af321e38f8e2417bbff3cb'
7
- data.tar.gz: 9f1a3b74222b8d23a38cedaae63ad2d078f1e402039cbe5f767d368081a386d5dbbbeeb1a28b0db65041b5ccec5d1b2aa6b68ecfe087be9e4c41c35ec788df09
6
+ metadata.gz: 5f7ccdcb0a16223887864366aeb2957adb705d8a96bbb60f51195bda826acad9e4a7a67ae925e82f5e7f35c4fdfca2641fac32eb560e8c7d01c9ae280760e008
7
+ data.tar.gz: ee31129a27f4073937c6bb5c2bdffbcc41c9b1ae29ccb425ee7d49b1bbcca391747461899544e21bd30557d0c1fa51d5f4460d5b62f410de580fa3b01909cc72
data/lib/p5rb.rb CHANGED
@@ -3,87 +3,200 @@ module P5
3
3
  attr_reader :buffer_setup
4
4
  attr_reader :buffer_draw
5
5
  end
6
- instance_variable_set :@buffer_setup, []
7
- instance_variable_set :@buffer_draw, []
6
+ @buffer_setup = []
7
+ @buffer_draw = []
8
8
 
9
- @buffer = []
10
- class << self
11
- def background color
12
- @buffer.push "background(#{color})"
13
- end
14
- def noStroke
15
- @buffer.push "noStroke()"
16
- end
17
- def stroke color
18
- @buffer.push "stroke(#{color})"
19
- end
20
- def translate x, y
21
- @buffer.push "translate(#{x}, #{y})"
22
- end
23
- def circle x, y, r
24
- @buffer.push "circle(#{x}, #{y}, #{r})"
25
- end
26
- def ellipse *args
27
- @buffer.push "ellipse(#{args.join ?,})"
28
- end
29
- def fill color, alpha = nil
30
- @buffer.push "fill(#{color}#{", #{alpha}" if alpha})"
31
- end
32
- def rect x, y, w, h, fill: nil
33
- (@buffer.push "push()"; fill fill) if fill
34
- @buffer.push "rect(#{x}, #{y}, #{w}, #{h})"
35
- @buffer.push "pop()" if fill
36
- end
37
- def point x, y
38
- @buffer.push "point(#{x}, #{y})"
39
- end
40
- def textSize size
41
- @buffer.push "textSize(#{size})"
42
- end
43
- def textAlign *args
44
- @buffer.push "textAlign(#{args.join ", "})"
45
- end
46
- def text text, x, y, fill: nil
47
- (@buffer.push "push()"; fill fill) if fill
48
- @buffer.push "text(#{text.inspect}, #{x}, #{y})"
49
- @buffer.push "pop()" if fill
9
+ module Block
10
+ class << self
11
+ attr_writer :buffer
12
+ def raw _
13
+ @buffer.push _
14
+ end
15
+ def background color
16
+ @buffer.push "background(#{color})"
17
+ end
18
+ def noStroke
19
+ @buffer.push "noStroke()"
20
+ end
21
+ def stroke color
22
+ @buffer.push "stroke(#{color})"
23
+ end
24
+ def translate x, y
25
+ @buffer.push "translate(#{x}, #{y})"
26
+ end
27
+ def line x1, y1, x2, y2
28
+ @buffer.push "line(#{x1}, #{y1}, #{x2}, #{y2})"
29
+ end
30
+ def circle x, y, r
31
+ @buffer.push "circle(#{x}, #{y}, #{r})"
32
+ end
33
+ def ellipse *args # not tested yet
34
+ @buffer.push "ellipse(#{args.join ?,})"
35
+ end
36
+ def fill color, alpha = nil
37
+ @buffer.push "fill(#{color}#{", #{alpha}" if alpha})"
38
+ end
39
+ def rect x, y, w, h, fill: nil
40
+ (@buffer.push "push()"; fill fill) if fill
41
+ @buffer.push "rect(#{x}, #{y}, #{w}, #{h})"
42
+ @buffer.push "pop()" if fill
43
+ end
44
+ def point x, y
45
+ @buffer.push "point(#{x}, #{y})"
46
+ end
47
+ def textSize size
48
+ @buffer.push "textSize(#{size})"
49
+ end
50
+ def textAlign *args
51
+ @buffer.push "textAlign(#{args.join ", "})"
52
+ end
53
+ def textWidth text
54
+ @buffer.push "textWidth(#{text.inspect})"
55
+ end
56
+ def textAscent text
57
+ @buffer.push "textAscent(#{text.inspect})"
58
+ end
59
+ def text text, x, y, fill: nil
60
+ (@buffer.push "push()"; fill fill) if fill
61
+ @buffer.push "text(#{text.inspect}, #{x}, #{y})"
62
+ @buffer.push "pop()" if fill
63
+ end
64
+ def map *args
65
+ "map(#{args.join ", "})"
66
+ end
50
67
  end
68
+ end
51
69
 
70
+ class << self
52
71
  def setup &block
53
- module_eval &block
54
- @buffer_setup = @buffer
55
- @buffer = []
72
+ ::P5::Block.buffer = @buffer_setup
73
+ ::P5::Block.module_eval &block
56
74
  end
57
- def draw &block
58
- module_eval &block
59
- @buffer_draw = @buffer
60
- @buffer = []
75
+ def draw &block # not tested yet
76
+ ::P5::Block.buffer = @buffer_draw
77
+ ::P5::Block.module_eval &block
61
78
  end
79
+ end
62
80
 
81
+ class << self
82
+ def plot_scatter data, reverse_y: false
83
+ size = 1000
84
+ max = nil
85
+ (x_range, x_from, x_to, x_enum, x_f),
86
+ (y_range, y_from, y_to, y_enum, y_f) = data.transpose.map do |axis|
87
+ min, max = axis.minmax
88
+ range = (min - max).abs
89
+ division = 10**Math::log10(range).floor
90
+ from = min.div(division)*division
91
+ to = -(-max).div(division)*division
92
+ [
93
+ to - from,
94
+ from, to,
95
+ from.step(to, division),
96
+ ]
97
+ end
98
+ max = [x_range, y_range].max
99
+ x_f = ->_{ 20 + (size-40.0) * (_ - x_from) / max }
100
+ y_f = ->_{ 20 + (size-40.0) * (reverse_y ? y_to - _ : _ - y_from) / max }
101
+ P5 40 + (size-40.0) * x_range / max + 50, # TODO: properly fix the issue that with wide labels the right end of the plot may be cut off
102
+ 40 + (size-40.0) * y_range / max do
103
+ setup do
104
+ textSize 15
105
+ raw "const w = max([#{y_enum.map{ |_| "textWidth(#{_})" }.join ?,}])"
106
+ raw "translate(w, 15)"
107
+ stroke 200
108
+ textAlign :CENTER, :BOTTOM; x_enum.each{ |_| line x_f[_], y_f[y_from], x_f[_], y_f[y_to]; text _, x_f[_], 20-5 }
109
+ textAlign :RIGHT, :CENTER; y_enum.each{ |_| line x_f[x_from], y_f[_], x_f[x_to], y_f[_]; text _, x_f[x_from]-5, y_f[_] }
110
+ stroke 0
111
+ data.each{ |x,y| point x_f[x], y_f[y] }
112
+ end
113
+ end
114
+ end
115
+ def plot_bar_grouped data
116
+ # TODO: this is currently pretty much hardcoded for a time dates charting
117
+ cls = data.values.flat_map(&:keys).uniq.sort
118
+ size = cls.size + 1
119
+ from, to = data.keys.minmax
120
+ max = data.values.flat_map(&:values).max
121
+ P5 500, 500 do
122
+ setup do
123
+ noStroke
124
+ textAlign :CENTER
125
+ cls.each_with_index{ |_, i| text _, 50+400/(size-2)*i, 25, fill: %w{ 'red' 'green' 'blue' }[i] }
126
+ textAlign :RIGHT, :TOP
127
+ (from..to).each do |date|
128
+ y = map date.ajd.to_i, from.ajd.to_i, to.ajd.to_i, 50, 450
129
+ text date.strftime("%m-%d"), 45, y
130
+ rect 50, y, map(data.fetch(date,{})[cls[0]]||0, 0, max, 0, 400), 400/(to-from)/size, fill: "'red'"
131
+ rect 50, "#{y}+#{400/(to-from)/size}", map(data.fetch(date,{})[cls[1]]||0, 0, max, 0, 400), 400/(to-from)/size, fill: "'green'"
132
+ rect 50, "#{y}+#{800/(to-from)/size}", map(data.fetch(date,{})[cls[2]]||0, 0, max, 0, 400), 400/(to-from)/size, fill: "'blue'"
133
+ end
134
+ end
135
+ end
136
+ end
137
+ def plot_bar_stacked data, names, colorize
138
+ count = {}
139
+ max = data.map do |_, day|
140
+ day.each{ |k,v| count[k] ||= 0; count[k] += v }.map(&:last).reduce :+
141
+ end.max
142
+ pairs = {}
143
+ data.each_cons(2) do |(_, day1), (_, day2)|
144
+ (day1.map(&:first) & day2.map(&:first)).each{ |_| pairs[_] ||= 0; pairs[_] += 1 }
145
+ end
146
+ require "pcbr"
147
+ require "set"
148
+ pcbr = PCBR.new
149
+ count.max_by(colorize){ |k,v| v }.each{ |k,v| pcbr.store k, [-v, pairs[k]||0] }
150
+ top = pcbr.sorted
151
+ size = 500
152
+ P5 size, size do
153
+ setup do
154
+ noStroke
155
+ textAlign :RIGHT, :TOP
156
+ border = 25
157
+ left = "#{border} + textWidth(\"00-00 - 00-00\") + 5"
158
+ data.each_with_index do |(bin, day), i|
159
+ y1 = map i, 0, data.size, border, size-border
160
+ y2 = map i+1, 0, data.size, border, size-border
161
+ text bin, "#{left} - 5", y1
162
+ pos = 0
163
+ day.sort_by{ |k,| top.index(k) || top.size }.each do |k, v|
164
+ rect \
165
+ map(pos, 0, max, left, size-border), y1,
166
+ map(v, 0, max, 0, "#{size}-#{border}-(#{left})"), "#{y2}-#{y1}",
167
+ fill: top.include?(k) ? "color('hsl(#{(((3-Math.sqrt(5))*180 * top.index(k)) % 360).round}, 75%, 75%)')" : "color('hsl(0, 0%, 75%)')"
168
+ pos += v
169
+ end
170
+ end
171
+ top.each_with_index{ |id, i| text names[id].inspect[1..-2], size-border, "#{border} + textAscent('X') * #{i}", fill: "color('hsl(#{(((3-Math.sqrt(5))*180 * top.index(id)) % 360).round}, 75%, 75%)')" }
172
+ end
173
+ end
174
+ end
63
175
  end
64
176
  end
65
177
 
66
178
  def P5 width, height, &block
67
- P5.module_eval &block
179
+ ::P5.module_eval &block
68
180
  <<~HEREDOC
69
181
  <html>
70
182
  <head>
183
+ <meta charset="UTF-8">
71
184
  <script src="https://github.com/processing/p5.js/releases/download/v1.4.2/p5.min.js"></script>
72
185
  <script>
73
186
  function setup() {
74
187
  createCanvas(#{width}, #{height});
75
188
  #{
76
- P5.buffer_setup.join(";\n").gsub(/^/, ?\s*8)
189
+ ::P5.buffer_setup.join(";\n").gsub(/^/, ?\s*12)
77
190
  }
78
191
  }
79
192
  function draw() {
80
193
  #{
81
- P5.buffer_draw.join(";\n").gsub(/^/, ?\s*8)
194
+ ::P5.buffer_draw.join(";\n").gsub(/^/, ?\s*12)
82
195
  }
83
196
  }
84
197
  </script>
85
198
  </head>
86
- <body><main></main></body>
199
+ <body style="margin: 0"><main></main></body>
87
200
  </html>
88
201
  HEREDOC
89
202
  end
data/p5rb.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "p5rb"
3
- spec.version = "0.0.1"
3
+ spec.version = "0.0.3"
4
4
  spec.summary = "Ruby DSL for p5.js"
5
5
 
6
6
  spec.author = "Victor Maslov aka Nakilon"
@@ -8,5 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.license = "MIT"
9
9
  spec.metadata = {"source_code_uri" => "https://github.com/nakilon/p5rb"}
10
10
 
11
+ spec.add_dependency "pcbr"
12
+
11
13
  spec.files = %w{ LICENSE p5rb.gemspec lib/p5rb.rb }
12
14
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: p5rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Maslov aka Nakilon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-10 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2022-12-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pcbr
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  description:
14
28
  email: nakilon@gmail.com
15
29
  executables: []
@@ -39,8 +53,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
39
53
  - !ruby/object:Gem::Version
40
54
  version: '0'
41
55
  requirements: []
42
- rubyforge_project:
43
- rubygems_version: 2.5.2.3
56
+ rubygems_version: 3.3.25
44
57
  signing_key:
45
58
  specification_version: 4
46
59
  summary: Ruby DSL for p5.js