svg-lib 0.0.5

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '0958d94cf32f41cfab9959fb9a0b1334feb3fdad141179787c16f61b632211fe'
4
+ data.tar.gz: 7d03990d325e1cfd66df81a112eee1b39dbdc9ee4f90701bd22a6d2e75722f65
5
+ SHA512:
6
+ metadata.gz: 75509788882b34a492f5192a0ed2fbba9ad021cb0a90ac5ae5f5df9a66cc34cddbbb77dd423dea3fcaced8bb003281a745efd702d0769ff015b35156df002b6f
7
+ data.tar.gz: b79c3d399c12bac44f10460a090c89ef6264ca0dd59078ebf73406c98210b1ca443ccd2858673d8cf8ee4eee753ce54b7dfa05a77b4836008baf99a77dab955a
@@ -0,0 +1,188 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ require "svg-lib"
4
+ require "optparse"
5
+
6
+
7
+ # ARGUMENTS PARSE =============================================================
8
+
9
+ opts = {}
10
+ opts[:ylog] = false
11
+ opts[:xlog] = false
12
+ opts[:legend] = false
13
+ opts[:scatterplot] = false
14
+ opts[:minx] = nil
15
+ opts[:maxx] = nil
16
+ opts[:miny] = nil
17
+ opts[:maxy] = nil
18
+ opts[:markers] = []
19
+ opts[:labels] = []
20
+ opts[:linestyles] = []
21
+
22
+ opts[:title] = ""
23
+ opts[:xlabel] = ""
24
+
25
+ opts[:width] = 500
26
+ opts[:height] = 500
27
+
28
+ progname = File.basename($PROGRAM_NAME,File.extname($PROGRAM_NAME))
29
+ parser = OptionParser.new do |parser|
30
+ parser.banner = <<~banner
31
+ #{progname} (easy plot) is a ruby script which allows to create basic 2D
32
+ plots quickly that are write in STDOUT in the SVG format.
33
+
34
+ Usage: #{progname} [options] [FILES]
35
+
36
+ banner
37
+
38
+ parser.on("--width=INT", "plot width") do |num|
39
+ opts[:width] = num.to_i
40
+ end
41
+
42
+ parser.on("--height=INT", "plot height") do |num|
43
+ opts[:height] = num.to_i
44
+ end
45
+
46
+ parser.on("--scatter","scatter plot mode") do
47
+ opts[:scatterplot] = true
48
+ end
49
+
50
+ parser.on("--ylog","show logarithmic axis") do
51
+ opts[:ylog] = true
52
+ end
53
+
54
+ parser.on("--xlog","show logarithmic axis") do
55
+ opts[:xlog] = true
56
+ end
57
+
58
+ parser.on("--legend","show legend") do |bool|
59
+ opts[:legend] = true
60
+ end
61
+
62
+ parser.on("--title=STR","title") do |str|
63
+ opts[:title] = str
64
+ end
65
+
66
+ parser.on("--xlabel=STR","xlabel") do |str|
67
+ opts[:xlabel] = str
68
+ end
69
+
70
+ parser.on("--ylabel=STR","ylabel") do |str|
71
+ opts[:ylabel] = str
72
+ end
73
+
74
+ parser.on("--miny=FLOAT", "value min on y axis") do |num|
75
+ opts[:miny] = num.to_f
76
+ end
77
+
78
+ parser.on("--maxy=FLOAT", "value max on y axis") do |num|
79
+ opts[:maxy] = num.to_f
80
+ end
81
+
82
+ parser.on("--minx=FLOAT", "value min on x axis") do |num|
83
+ opts[:minx] = num.to_f
84
+ end
85
+
86
+ parser.on("--maxx=FLOAT", "value max on x axis") do |num|
87
+ opts[:maxx] = num.to_f
88
+ end
89
+
90
+ parser.on("--markers=\"m1,m2,m3,..\"", "markers to use") do |list|
91
+ opts[:markers] = list.split(",")
92
+ end
93
+
94
+ parser.on("--linestyles=\"ls1,ls2,ls3,..\"", "markers to use") do |list|
95
+ opts[:linestyles] = list.split(",")
96
+ end
97
+
98
+ parser.on("--labels=\"STR1,STR2,ST3,...\"","title of each plot") do |list|
99
+ opts[:labels] = list.split(",")
100
+ end
101
+
102
+
103
+ parser.on("-h","--help","shows this message") do
104
+ STDERR.puts parser
105
+ exit(0)
106
+ end
107
+ end
108
+ parser.parse!
109
+
110
+ # Get files
111
+
112
+ files = []
113
+ ARGV.each do |fname|
114
+ files.push(fname) if File.exists?(fname) || (fname == "-")
115
+ end
116
+
117
+ # Check there is at least one file to plot
118
+ if files.empty?
119
+ puts parser
120
+ exit 1
121
+ end
122
+
123
+ # MAIN PROGRAM ================================================================
124
+
125
+ SVG.new(x: 0.0, y: 0.0, width: opts[:width], height: opts[:height],font_family: "monospace") do |svg|
126
+ plt = SVG::Plot.new(svg)
127
+ plt.title = opts[:title];
128
+ plt.xlabel = opts[:xlabel];
129
+ plt.ylabel = opts[:ylabel];
130
+ plt.minx = opts[:minx];
131
+ plt.maxx = opts[:maxx];
132
+ plt.miny = opts[:miny];
133
+ plt.maxy = opts[:maxy];
134
+
135
+
136
+ datavar = []
137
+ data = []
138
+ rawx = []
139
+ rawvar = []
140
+ rawdata = []
141
+
142
+ rawx = []
143
+ files.each do |fname|
144
+ name = File.basename(fname,File.extname(fname))
145
+ name = name.split("--")[1] || name
146
+ opts[:labels].push(name) if opts[:labels].size < files.size
147
+ lines = if (fname == "-")
148
+ STDIN.each_line.to_a
149
+ else
150
+ File.readlines(fname)
151
+ end
152
+ data = lines.map{|e| e.split(/\s+/).map{|e| e.to_f}}
153
+ if data.first.size > 1
154
+ x = data.map{|e| e[0]}
155
+ data = data.map{|e| e[1]}
156
+ else
157
+ x = (1 .. data.size).to_a.map{|e| e.to_f}
158
+ data = data.map{|e| e[0]}
159
+ end
160
+ rawx.push(x)
161
+ rawdata.push(data)
162
+ end
163
+
164
+ plt.minmax(rawx,rawdata,xlog: opts[:xlog], ylog: opts[:ylog])
165
+
166
+ rawdata.each_with_index do |y,i|
167
+ if opts[:scatterplot]
168
+ plt.scatter(rawx[i],y,
169
+ ylog: opts[:ylog],
170
+ label: opts[:labels][i],
171
+ marker: opts[:markers][i])
172
+ else
173
+ plt.plot(rawx[i],y,
174
+ ylog: opts[:ylog],
175
+ label: opts[:labels][i],
176
+ marker: opts[:markers][i],
177
+ linestyle: opts[:linestyles][i])
178
+ end
179
+
180
+ end
181
+
182
+ plt.legend if opts[:legend]
183
+ plt.axes(xlog: opts[:xlog],ylog: opts[:ylog])
184
+ plt.title
185
+ end
186
+
187
+
188
+
@@ -0,0 +1,24 @@
1
+ class SVG
2
+ def defs
3
+ @io.puts "<defs>"
4
+ yield self
5
+ @io.puts "</defs>"
6
+ end
7
+
8
+ def marker(id:,viewBox:,refX:,refY:,title: "",**args)
9
+ @io.print %(<marker id="#{id}" viewBox="#{viewBox.join(" ")}" refX="#{refX}" refY="#{refY}" )
10
+ print_args(**args)
11
+ @io.puts " >"
12
+ print_title(title)
13
+ yield self
14
+ @io.puts "</marker>"
15
+ end
16
+
17
+ def g(**args)
18
+ @io.print %(<g )
19
+ print_args(**args)
20
+ @io.puts %( >)
21
+ yield self
22
+ @io.puts %(</g>)
23
+ end
24
+ end
@@ -0,0 +1,535 @@
1
+ require "stringio"
2
+ class SVG
3
+ def plot
4
+ return Plot.new
5
+ end
6
+
7
+ class Plot
8
+ @svg
9
+ @@colors = [
10
+ "cyan","red","green","blue","orange","deeppink","lightgreen","black","purple","gray",
11
+ "gray","cyan","purple","tomato","black","green","lightgreen","cornflowerblue","pink","orange"] * 2
12
+
13
+ def self.colors()
14
+ return @@colors
15
+ end
16
+ @@markers = [".","o","s","1","*","x","+","d","p","H"] * 4
17
+ def self.markers()
18
+ return @@markers
19
+ end
20
+ @@linestyles = [
21
+ "-","--","-.",":","3","10 1","10 5","5 10","5 2 2 5","2 10",
22
+ "2 10","5 2 2 5","5 10","10 5","10 1","3",":","-.","--","-"
23
+ ] * 2
24
+ def self.linestyles
25
+ return @@linestyles
26
+ end
27
+
28
+ attr_accessor :minx,:maxx,:miny,:maxy
29
+ @minx = -1.0/0.0
30
+ @maxx = 1.0/0.0
31
+ @miny = -1.0/0.0
32
+ @maxy = 1.0/0.0
33
+
34
+ def minmax(x,y,xlog: false,ylog: false)
35
+ miny,maxy = y.flatten.minmax
36
+ @miny = miny unless (@miny && @miny.finite?)
37
+ @maxy = maxy unless (@maxy && @maxy.finite?)
38
+
39
+ if ylog
40
+ @miny = Math.log([1e-12,@miny].max,10)
41
+ @maxy = Math.log(@maxy,10)
42
+ end
43
+ minx,maxx = x.flatten.minmax
44
+ @minx = minx unless (@minx && @minx.finite?)
45
+ @maxx = maxx unless (@maxx && @maxx.finite?)
46
+
47
+ if xlog
48
+ @minx = Math.log([1e-12,@minx].max,10)
49
+ @maxx = Math.log(@maxx,10)
50
+ end
51
+ end
52
+
53
+ attr_accessor :padleft, :padright,:padtop,:padbottom,:colors,:labels,:markers,
54
+ :linestyles,:opacities,:linewidth
55
+
56
+
57
+ attr_accessor :markernum,:markersize
58
+ attr_accessor :xlabel,:ylabel,:axcolor,:axlinewidth,:axlabelstrokewidth,
59
+ :axlabelfontsize
60
+ attr_accessor :ticksnum,:tickslen,:tickstextlen,:ticksfontsize,:ticksstrokewidth
61
+ attr_accessor :legendfontsize,:legendbgcolor,:legendbgopacity,:legendfgcolor,
62
+ :legendlinelen,:legendheight,:legendpad
63
+ attr_accessor :title, :titlefontsize
64
+
65
+ def initialize(svg)
66
+ @svg = svg
67
+
68
+ @padleft = 100
69
+ @padright = 50
70
+ @padtop = 50
71
+ @padbottom = 80
72
+ @colors = []
73
+ @labels = []
74
+ @markers = []
75
+ @linestyles = []
76
+ @opacities = []
77
+ @linewidth = 2
78
+
79
+ @markernum = 10
80
+ @markersize = 15
81
+
82
+ @xlabel = ""
83
+ @ylabel = ""
84
+ @axcolor = "black"
85
+ @axlinewidth = 2
86
+ @axlabelstrokewidth = 0.5
87
+ @axlabelfontsize = 20
88
+
89
+
90
+ @ticksnum = 5
91
+ @tickslen = 10
92
+ @tickstextlen = 60
93
+ @ticksfontsize = 12
94
+ @ticksstrokewidth = 0.1
95
+
96
+ @legendfontsize = 10
97
+ @legendbgcolor = "white"
98
+ @legendbgopacity = 0.5
99
+ @legendfgcolor = "black"
100
+ @legendlinelen = 50
101
+ @legendheight = 100
102
+ @legendpad = 10
103
+
104
+ @title = ""
105
+ @titlefontsize = 20
106
+ end
107
+
108
+ def self.mapxcoords(x,minx,maxx,w,padleft,padright,log)
109
+ x = log ? Math.log(x,10) : x
110
+ xnew = padleft + ((x - minx)/((maxx-minx) + 1e-100))*(w-(padleft + padright))
111
+ end
112
+
113
+ def self.mapycoords(y,miny,maxy,h,padtop,padbottom,log)
114
+ y = log ? Math.log(y,10) : y
115
+ ynew = padtop + ((maxy - y)/((maxy-miny) + 1e-100))*(h-(padtop + padbottom))
116
+ end
117
+
118
+ def map_and_zip(xraw,yraw,minx,maxx,miny,maxy,xlog,ylog)
119
+ xp = xraw.map{|v| Plot.mapxcoords(v,minx,maxx,@svg.width,@padleft,@padright,xlog)}
120
+ yp = yraw.map{|v| Plot.mapycoords(v,miny,maxy,@svg.height,@padtop,@padbottom,ylog)}
121
+
122
+ return xp.zip(yp)
123
+ end
124
+
125
+ def set_plot_style(label,color,marker,linestyle,opacity)
126
+ label = @labels.size.to_s if !label
127
+ color = @@colors[@labels.size] if !color
128
+ marker = @@markers[@labels.size] if !marker
129
+ linestyle = @@linestyles[@labels.size] if !linestyle
130
+ opacity = 1.0 if !opacity
131
+
132
+ @labels.push(label)
133
+ @colors.push(color)
134
+ @markers.push(marker)
135
+ @linestyles.push(linestyle)
136
+ @opacities.push(opacity)
137
+ end
138
+
139
+ def scatter(
140
+ xraw, yraw,
141
+ minx: @minx, maxx: @maxx, miny: @miny, maxy: @maxy,
142
+ label: nil,
143
+ color: nil,
144
+ marker: nil,
145
+ opacity: nil,
146
+ xlog: false, ylog: false,**args)
147
+
148
+ self.set_plot_style(label,color,marker,"",opacity)
149
+ points = self.map_and_zip(xraw,yraw,minx,maxx,miny,maxy,xlog,ylog)
150
+
151
+ @svg.g(id: @labels.last, stroke: "none",fill: @colors.last,opacity: @opacities.last) do |g|
152
+ points.each_with_index do |(x,y),i|
153
+ self.marker(@markers.last,x,y,"%g" % yraw[i])
154
+ end
155
+ end
156
+
157
+ end
158
+
159
+ def plot(
160
+ xraw, yraw,
161
+ minx: @minx,maxx: @maxx,miny: @miny,maxy: @maxy,
162
+ label: nil,
163
+ color: nil,
164
+ marker: nil,
165
+ linestyle: nil,
166
+ opacity: nil,
167
+ xlog: false,ylog: false)
168
+
169
+ self.set_plot_style(label,color,marker,linestyle,opacity)
170
+ points = self.map_and_zip(xraw,yraw,minx,maxx,miny,maxy,xlog,ylog)
171
+
172
+ @svg.g(
173
+ id: @labels.last,
174
+ stroke: @colors.last,
175
+ fill: @colors.last,
176
+ stroke_width: @linewidth,
177
+ opacity: @opacities.last) do |g|
178
+
179
+ g.path(title: @labels.last,fill: "none",stroke_dasharray: self.linestyle(linestyle)) do |path|
180
+ missing = true
181
+ points.each do |(x,y)|
182
+ if !x.finite? || !y.finite?
183
+ missing = true
184
+ next
185
+ end
186
+ if missing
187
+ path.m(x,y)
188
+ missing = false
189
+ end
190
+ path.l(x,y)
191
+ end
192
+ end
193
+
194
+ g.g(id: @labels.last+"-markers", fill: @colors.last) do |mg|
195
+ points.each_with_index do |(x,y),i|
196
+ next if ((i % (points.size.to_i / @markernum.to_i)) != 0) || !x.finite? || !y.finite?
197
+ self.marker(@markers.last,x,y,yraw[i].round(2))
198
+ end
199
+ end
200
+ end
201
+
202
+ end
203
+
204
+ def title
205
+ @svg.g(id: "title",text_anchor: "middle") do |g|
206
+ g.text(
207
+ x: (@svg.width).to_i / 2, y: @titlefontsize,
208
+ text: @title,
209
+ font_size: @titlefontsize)
210
+ end
211
+ end
212
+
213
+ def legend
214
+ legendwidth = @legendlinelen + 2*@legendpad + @legendfontsize*@labels.map{|e| e.size}.max
215
+ legendheight = 2*@legendpad + @labels.size*2*@legendfontsize
216
+
217
+ t = SVG.transform do |t|
218
+ t.translate(@svg.width-legendwidth-@padright,0)
219
+ end
220
+
221
+ @svg.g(id: "legend",transform: t) do |g|
222
+ g.rect(
223
+ x: 0,
224
+ y: 0 ,
225
+ width: legendwidth,
226
+ height: legendheight,
227
+ stroke: "none" ,
228
+ fill: @legendbgcolor,
229
+ opacity: @legendbgopacity)
230
+
231
+ @labels.size.times do |i|
232
+ y = (i+1)*(2*@legendfontsize)
233
+ g.g(id: "legend-marker-line-"+@labels[i],fill: @colors[i],stroke: @colors[i]) do |g|
234
+ g.line(
235
+ x1: @legendpad,
236
+ y1: y - @legendfontsize.to_i / 4,
237
+ x2: @legendpad+@legendlinelen,
238
+ y2: y - @legendfontsize.to_i / 4,
239
+ stroke_dasharray: self.linestyle(@linestyles[i]))
240
+ self.marker(
241
+ @markers[i],
242
+ @legendpad + @legendlinelen.to_i / 2,
243
+ y - @legendfontsize.to_i / 4,
244
+ "",
245
+ @legendfontsize)
246
+ end
247
+ g.text(x: @legendpad+@legendfontsize+@legendlinelen,y: y ,text: @labels[i])
248
+ end
249
+ end
250
+ end
251
+
252
+ def xaxis(min= @minx,max= @maxx,log= false)
253
+ @svg.g(id: "xaxis",text_anchor: "middle") do |xaxis|
254
+ xaxis.path(fill: "none") do |path|
255
+ path.m(@padleft,@svg.height-@padbottom)
256
+ path.l(@svg.width-@padright,@svg.height - @padbottom)
257
+ end
258
+
259
+ t = SVG.transform do |t|
260
+ t.translate(@svg.width / 2,@svg.height-@axlabelfontsize)
261
+ end
262
+ xaxis.g(id: "xlabel",transform: t) do |g|
263
+ g.text(text: @xlabel ,x: 0,y: 0,stroke_width: @axlabelstrokewidth)
264
+ end
265
+
266
+
267
+ tickypos = @svg.height - @padbottom - (@tickslen / 2)
268
+ ticks = [[min,Plot.mapxcoords(min,min,max,@svg.width,@padleft,@padright,false)]]
269
+ @ticksnum.times do |i|
270
+ v = min + ((max - min)/(@ticksnum+1))*(i+1)
271
+ ticks.push([v,Plot.mapxcoords(v,min,max,@svg.width,@padleft,@padright,false)])
272
+ end
273
+ ticks.push([max,Plot.mapxcoords(max,min,max,@svg.width,@padleft,@padright,false)])
274
+
275
+ # Dibujar los ticks
276
+ xaxis.path do |tickspath|
277
+ ticks.each do |tick|
278
+ tickspath.m(tick.last,tickypos)
279
+ tickspath.l(0,@tickslen,relative: true)
280
+ end
281
+ end
282
+
283
+ tickypos += @tickstextlen/2
284
+ ticks.each do |tick|
285
+ txt = tick.first.round(2).to_s
286
+ txt = log ? "10^"+txt : txt
287
+ xaxis.text(
288
+ x: tick.last,
289
+ y: tickypos,
290
+ text: txt,
291
+ font_size: @ticksfontsize,
292
+ stroke_width: @ticksstrokewidth)
293
+
294
+ end
295
+
296
+ end
297
+ end
298
+
299
+ def yaxis(min = @miny,max = @maxy ,log = false)
300
+ @svg.g(id: "yaxis") do |yaxis|
301
+ yaxis.path(fill: "none") do |path|
302
+ path.m(@padleft,@padtop)
303
+ path.l(@padleft,@svg.height-@padbottom)
304
+ end
305
+
306
+ # Mostrar el nombre
307
+ t = SVG.transform do |t|
308
+ t.translate(@axlabelfontsize,@svg.height/2)
309
+ t.rotate(-90,0,0)
310
+ end
311
+ yaxis.g(id: "yaxislabel",transform: t) do |g|
312
+ g.text(text: @ylabel ,x: 0,y: 0,stroke_width: @axlabelstrokewidth)
313
+ end
314
+
315
+
316
+ # Obtener la posición de los ticks
317
+ tickxpos = @padleft-@tickslen/2
318
+ ticks = [[min,Plot.mapycoords(min,min,max,@svg.height,@padtop,@padbottom,false)]]
319
+ @ticksnum.times do |i|
320
+ v = min + ((max - min) / (@ticksnum+1)) * (i+1)
321
+ ticks.push([v,Plot.mapycoords(v,min,max,@svg.height,@padtop,@padbottom,false)])
322
+ end
323
+ ticks.push([max,Plot.mapycoords(max,min,max,@svg.height,@padtop,@padbottom,false)])
324
+
325
+ # Dibujar los ticks
326
+ yaxis.path do |tickspath|
327
+ ticks.each do |tick|
328
+ tickspath.m(tickxpos,tick.last)
329
+ tickspath.l(@tickslen,0,relative: true)
330
+ end
331
+ end
332
+
333
+ # Colocar los valores
334
+ tickxpos -= @tickstextlen/2
335
+ ticks.each do |tick|
336
+ txt = tick.first.round(2).to_s
337
+ txt = log ? "10^"+txt : txt
338
+ yaxis.text(
339
+ x: tickxpos, y: tick.last,
340
+ text: txt,
341
+ text_anchor: "middle",
342
+ stroke_width: @ticksstrokewidth,
343
+ font_size: @ticksfontsize)
344
+ end
345
+ end
346
+ end
347
+
348
+ def axes(minx: @minx,maxx: @maxx,miny: @miny,maxy: @maxy,xlog: false,ylog: false)
349
+ @svg.g(id: "axis" , stroke: @axcolor,fill: @axcolor,stroke_width: @axlinewidth) do |g|
350
+ self.xaxis(minx,maxx,xlog)
351
+ self.yaxis(miny,maxy,ylog)
352
+ end
353
+ end
354
+
355
+ def linestyle(style)
356
+ case style
357
+ when "-" then "5 0"
358
+ when "--","dashed" then "5"
359
+ when "-.","dashdot" then "6 3 3 3"
360
+ when ":","dotted" then "2"
361
+ when " ","","none" then "0 1"
362
+ else style
363
+ end
364
+ end
365
+
366
+ def marker(marker,x,y,val,ms = @markersize)
367
+ t = SVG.transform do |t|
368
+ t.translate(x,y)
369
+ t.scale(ms)
370
+ case marker
371
+ when "D","x","X" then t.rotate(45)
372
+ when ">","2","H" then t.rotate(90)
373
+ when "v","3" then t.rotate(180)
374
+ when "<","4" then t.rotate(270)
375
+ else nil
376
+ end
377
+ end
378
+
379
+ case marker
380
+ when "." then self.marker_point(t,val)
381
+ when "," then self.marker_pixel(t,val)
382
+ when "o" then self.marker_circle(t,val)
383
+ when "^",">","v","<" then self.marker_triangle(t,val)
384
+ when "s","D" then self.marker_square(t,val)
385
+ when "d" then self.marker_diamond(t,val)
386
+ when "+","x" then self.marker_plus(t,0.1,val)
387
+ when "P","X" then self.marker_plus(t,0.2,val)
388
+ when "1","2","3","4" then self.marker_tri(t,val)
389
+ when "h","H" then self.marker_hexagon(t,val)
390
+ when "p" then self.marker_pentagon(t,val)
391
+ when "8" then self.marker_octagon(t,val)
392
+ when "*" then self.marker_star(t,val)
393
+ else raise "unkown marker #{marker}"
394
+ end
395
+ end
396
+
397
+ def marker_point(t,val="")
398
+ @svg.circle(cx: 0, cy: 0, r: 0.3, transform: t,title: val,stroke_width: 0)
399
+ end
400
+
401
+ def marker_pixel(t,val="")
402
+ @svg.circle(cx: 0, cy: 0, r: 0.2, transform: t,title: val,stroke_width: 0)
403
+ end
404
+
405
+ def marker_circle(t,val="")
406
+ @svg.circle(cx: 0, cy: 0, r: 0.45, transform: t,title: val,stroke_width: 0)
407
+ end
408
+
409
+ def marker_triangle(t,val="")
410
+ @svg.path(transform: t, title: val,stroke_width: 0) do |path|
411
+ path.m(0,-0.5)
412
+ path.l(0.5,0.5)
413
+ path.l(-0.5,0.5)
414
+ path.z
415
+ end
416
+ end
417
+
418
+ def marker_square(t,val="")
419
+ @svg.path(transform: t, title: val,stroke_width: 0) do |path|
420
+ path.m(-0.4,-0.4)
421
+ path.h(0.4)
422
+ path.v(0.4)
423
+ path.h(-0.4)
424
+ path.z
425
+ end
426
+ end
427
+
428
+ def marker_diamond(t,val="")
429
+ @svg.path(transform: t, title: val,stroke_width: 0) do |path|
430
+ path.m(0,-0.5)
431
+ path.l(0.3,0)
432
+ path.l(0,0.5)
433
+ path.l(-0.3,0.0)
434
+ path.z
435
+ end
436
+ end
437
+
438
+ def marker_plus(t,width,val="")
439
+ @svg.path(transform: t, title: val,stroke_width: 0 ) do |path|
440
+ path.m(-width,-0.5)
441
+ path.h(width)
442
+ path.v(0.5)
443
+ path.h(-width)
444
+ path.z
445
+ end
446
+ @svg.path(transform: t, title: val,stroke_width: 0 ) do |path|
447
+ path.m(-0.5,-width)
448
+ path.v(width)
449
+ path.h(0.5)
450
+ path.v(-width)
451
+ path.z
452
+ end
453
+ end
454
+
455
+ def marker_tri(t,val="")
456
+ @svg.g(title: val, transform: t,stroke_width: 0) do |g|
457
+ width = 0.1
458
+ @svg.path(title: val) do |path|
459
+ path.m(-width,0.5)
460
+ path.h(width)
461
+ path.v(0.0)
462
+ path.h(-width)
463
+ path.z
464
+ end
465
+ @svg.path(
466
+ title: val,
467
+ transform: SVG.transform{|t| t.rotate(135)}) do |path|
468
+ path.m(-width,0.5)
469
+ path.h(width)
470
+ path.v(0.0)
471
+ path.h(-width)
472
+ path.z
473
+ end
474
+ @svg.path(
475
+ title: val,
476
+ transform: SVG.transform{|t| t.rotate(225)}) do |path|
477
+ path.m(-width,0.5)
478
+ path.h(width)
479
+ path.v(0.0)
480
+ path.h(-width)
481
+ path.z
482
+ end
483
+ end
484
+ end
485
+
486
+ def marker_hexagon(t,val="")
487
+ @svg.path(title: val, transform: t,stroke_width: 0) do |path|
488
+ path.m( 0.00,-0.50)
489
+ path.l( 0.40,-0.20)
490
+ path.l( 0.40, 0.30)
491
+ path.l( 0.00, 0.50)
492
+ path.l(-0.40, 0.30)
493
+ path.l(-0.40,-0.20)
494
+ path.z
495
+ end
496
+ end
497
+
498
+ def marker_pentagon(t,val="")
499
+ @svg.path(title: val, transform: t,stroke_width: 0) do |path|
500
+ path.m( 0.00,-0.50)
501
+ path.l( 0.45,-0.10)
502
+ path.l( 0.30, 0.50)
503
+ path.l(-0.30, 0.50)
504
+ path.l(-0.45,-0.10)
505
+ path.z
506
+ end
507
+ end
508
+
509
+ def marker_octagon(t,val="")
510
+ @svg.path(title: val, transform: t,stroke_width: 0) do |path|
511
+ path.m(-0.25,-0.50)
512
+ path.l( 0.18,-0.50)
513
+ path.l( 0.50,-0.25)
514
+ path.l( 0.50, 0.18)
515
+ path.l( 0.18, 0.50)
516
+ path.l(-0.25, 0.50)
517
+ path.l(-0.50, 0.18)
518
+ path.l(-0.50,-0.25)
519
+ path.z
520
+ end
521
+ end
522
+
523
+ def marker_star(t,val="")
524
+ @svg.path(title: val, transform: t,stroke_width: 0) do |path|
525
+ path.m(0,-0.5)
526
+ path.l(-0.3,0.5)
527
+ path.l(0.5,-0.1)
528
+ path.l(-0.5,-0.1)
529
+ path.l(0.3,0.5)
530
+ path.z
531
+ end
532
+ end
533
+
534
+ end
535
+ end
@@ -0,0 +1,97 @@
1
+ class SVG
2
+ def rect(x:,y:,width:,height:,title: "",**args)
3
+ @io.print %(<rect x="#{x}" y="#{y}" width="#{width}" height="#{height}" )
4
+ print_args(**args)
5
+ @io.print " >"
6
+ print_title(title)
7
+ @io.puts("</rect>")
8
+ end
9
+
10
+ def line(x1:,y1:,x2:,y2:,title: "",**args)
11
+ @io.print %(<line x1="#{x1}" y1="#{y1}" x2="#{x2}" y2="#{y2}" )
12
+ print_args(**args)
13
+ @io.print " >"
14
+ print_title(title)
15
+ @io.puts("</line>")
16
+ end
17
+
18
+ def circle(cx:,cy:,r:,title: "",**args)
19
+ @io.print %(<circle cx="#{cx}" cy="#{cy}" r="#{r}" )
20
+ print_args(**args)
21
+ @io.print " >"
22
+ print_title(title)
23
+ @io.puts("</circle>")
24
+ end
25
+
26
+ def polygon(points:,title: "",**args)
27
+ @io.print "<polygon "
28
+ @io.print "points=\""
29
+ points.each do |p|
30
+ @io.print p[0],",",p[1]," "
31
+ end
32
+ @io.print "\" "
33
+ print_args(**args)
34
+ @io.print " >"
35
+ print_title(title)
36
+ @io.puts "</polygon>"
37
+ end
38
+
39
+
40
+ def path(title: "",**args)
41
+ @io.print %(<path d=")
42
+ yield Path.new(self)
43
+ @io.print %(" )
44
+ print_args(**args)
45
+ @io.puts %( >)
46
+ print_title(title)
47
+ @io.puts %(</path>)
48
+ end
49
+
50
+ class SVG::Path
51
+ def initialize(svg)
52
+ @svg = svg
53
+ end
54
+
55
+ def m(x,y,relative=false)
56
+ @svg.print %(#{relative ? "m" : "M"} #{x} #{y} )
57
+ end
58
+
59
+ def l(x,y,relative=false)
60
+ @svg.print %(#{relative ? "l" : "L"} #{x} #{y} )
61
+ end
62
+
63
+ def h(x,relative=false)
64
+ @svg.print %(#{relative ? "h" : "H"} #{x} )
65
+ end
66
+
67
+ def v(y,relative=false)
68
+ @svg.print %(#{relative ? "v" : "V"} #{y} )
69
+ end
70
+
71
+ def c(x1,y1,x2,y2,x,y,relative=false)
72
+ @svg.print %(#{relative ? "c" : "C"} #{x1} #{y1} #{x2} #{y2} #{x} #{y} )
73
+ end
74
+
75
+ def s(x2,y2,x,y,relative=false)
76
+ @svg.print %(#{relative ? "s" : "S"} #{x2} #{y2} #{x} #{y} )
77
+ end
78
+
79
+ def q(x1,y1,x,y,relative=false)
80
+ @svg.print %(#{relative ? "q" : "Q"} #{x1} #{y1} #{x} #{y} )
81
+ end
82
+
83
+ def t(x,y,relative=false)
84
+ @svg.print %(#{relative ? "t" : "T"} #{x} #{y} )
85
+ end
86
+
87
+ def a(rx,ry,x_axis_rot,large_arc_flag,sweep_flag,x,y,relative=true)
88
+ @svg.print %(#{relative ? "a" : "A"} #{rx} #{ry} #{x_axis_rot} #{large_arc_flag} #{sweep_flag} #{x} #{y} )
89
+ end
90
+
91
+ def z()
92
+ @svg.print %(z )
93
+ end
94
+ end
95
+ end
96
+
97
+
@@ -0,0 +1,39 @@
1
+ require "stringio"
2
+
3
+ class SVG
4
+ attr :width
5
+ attr :height
6
+ def initialize(io,width,height)
7
+ @io = io
8
+ @width = width
9
+ @height = height
10
+ end
11
+ def puts(*args)
12
+ @io.puts(*args)
13
+ end
14
+ def print(*args)
15
+ @io.print(*args)
16
+ end
17
+ def self.new(x:,y:,width:,height:,io: STDOUT,**args)
18
+ svg = super(io,width,height)
19
+ svg.print %(<svg viewBox="#{x} #{y} #{width} #{height}" version="1.1" xmlns="http://www.w3.org/2000/svg" )
20
+ svg.print_args(**args)
21
+ svg.print(" >")
22
+ yield svg
23
+ svg.puts "</svg>"
24
+ end
25
+ def print_args(**args)
26
+ args.each do |k,v|
27
+ @io.print k.to_s.gsub("_","-"),"=","\"",v,"\""," "
28
+ end
29
+ end
30
+ def print_title(title)
31
+ @io.puts %(<title>#{title}</title>) if title != ""
32
+ end
33
+ end
34
+
35
+ require "shapes"
36
+ require "text"
37
+ require "containers"
38
+ require "transform"
39
+ require "plot2d"
@@ -0,0 +1,10 @@
1
+ class SVG
2
+ def text(x:,y:,text:,title: "",**args)
3
+ @io.print %(<text x="#{x}" y="#{y}" )
4
+ print_args(**args)
5
+ @io.print " >"
6
+ print_title(title)
7
+ @io.print text
8
+ @io.puts "</text>"
9
+ end
10
+ end
@@ -0,0 +1,43 @@
1
+ class SVG
2
+ class Transform
3
+ def initialize(io)
4
+ @io = io
5
+ end
6
+
7
+ def translate(x,y)
8
+ @io.print %(translate(#{x} #{y}) )
9
+ self
10
+ end
11
+
12
+ def rotate(d,x=nil,y=nil)
13
+ @io.print %(rotate(#{d} #{x} #{y}) )
14
+ self
15
+ end
16
+
17
+ def scale(x,y=nil)
18
+ @io.print %(scale(#{x} #{y}) )
19
+ self
20
+ end
21
+
22
+ def skewx(a)
23
+ @io.print %(skewX(#{a}) )
24
+ self
25
+ end
26
+
27
+ def skewy(a)
28
+ @io.print %(skewY(#{a}) )
29
+ self
30
+ end
31
+
32
+ def matrix(a,b,c,d,e,f)
33
+ @io.print %(matrix(#{a} #{b} #{c} #{d} #{e} #{f}) )
34
+ self
35
+ end
36
+ end
37
+
38
+ def self.transform
39
+ io = StringIO.new
40
+ yield Transform.new(io)
41
+ return io.string
42
+ end
43
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: svg-lib
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ platform: ruby
6
+ authors:
7
+ - Ricardo Nieto
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-09-28 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: basic svg-lib ruby implementation
14
+ email: nifr91@gmail.com
15
+ executables:
16
+ - eplot
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/eplot
21
+ - lib/containers.rb
22
+ - lib/plot2d.rb
23
+ - lib/shapes.rb
24
+ - lib/svg-lib.rb
25
+ - lib/text.rb
26
+ - lib/transform.rb
27
+ homepage:
28
+ licenses:
29
+ - MIT
30
+ metadata: {}
31
+ post_install_message:
32
+ rdoc_options: []
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ requirements: []
46
+ rubygems_version: 3.1.4
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: svg-lib ruby
50
+ test_files: []