vg_helper 0.1.0 → 0.1.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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +660 -15
  3. data/lib/vg_helper/version.rb +1 -1
  4. data/lib/vg_helper.rb +184 -104
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b01823993ada318ef29956c058158602b4648d28515f1051c3ffda4fd62fe67
4
- data.tar.gz: ab70be22d50b15004b11e108faa16909d0d30fa51e7dca475375676cdcff9191
3
+ metadata.gz: 4dbf940d1eca83928ba5bbb9881af79c29744be7b4287ff2cc23dc6d055a5a87
4
+ data.tar.gz: b4c473be9618bbba21f1e3bf3d297295d5206317925b95fbb6b88471f011d819
5
5
  SHA512:
6
- metadata.gz: 0615f0ecbaa49ab4d7c16adf60553344b4f1afda2f8b8693971f62bdca68830137627f83bbb65d7d3bd73bc3e8ef2d18a0b23a41174f4cd8d4c756679216dd69
7
- data.tar.gz: fa7ea6f99167a1c3ae4805ec961070d1ef07bfa49568699a8179f39c8a2e43df47901affca3e8cdfd04861be87d5f626d967b28d8ad04c220b6fceb3ecb23a29
6
+ metadata.gz: e82f4ac7b4123e4324114cc7ec897b15e6737d9e2c7c4018b4909e86a61e9bc4576d38222259028c0dab108e95e212c6535e7c1233316170f6e71754b4fb1b76
7
+ data.tar.gz: a63d810f05411f24ffc0eef693c7c06a3de2a50562c7fcb638e86d283295b487dbeae24b267d678044e5fa04a8ef725296e3fafdd43921ae7b92b51e7be47714
data/README.md CHANGED
@@ -1,34 +1,674 @@
1
- # VgHelper
1
+ # VGHelper
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
3
+ VGHelper is a small Ruby helper library for creating interactive
4
+ [Vega-Lite](https://vega.github.io/vega-lite/) charts from
5
+ `Rover::DataFrame`.
4
6
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/vg_helper`. To experiment with that code, run `bin/console` for an interactive prompt.
7
+ It provides convenient helpers for time-series and nominal x-axis charts,
8
+ with support for multiple categories, secondary y-axes, reference lines,
9
+ interactive range controls, brush statistics, and offline HTML output.
10
+
11
+ One of the main goals of VGHelper is to make Vega-Lite charts usable
12
+ even in **offline or proxy-restricted environments**.
13
+
14
+ VGHelper bundles the JavaScript runtimes required by Vega, Vega-Lite,
15
+ and Vega-Embed, so HTML generated by VGHelper does not need to load
16
+ these libraries from an external CDN.
17
+
18
+ ## Features
19
+
20
+ - Time-series charts (`draw_xdate`)
21
+ - Nominal / categorical x-axis charts (`draw_xnominal`)
22
+ - Multiple series and multiple category columns
23
+ - Line charts with optional point markers
24
+ - Secondary y-axis with bar charts
25
+ - Stacked bars using a secondary category
26
+ - Horizontal reference lines
27
+ - Vertical reference lines
28
+ - Configurable colors for reference lines
29
+ - Interactive x-axis range controls
30
+ - Interactive y-axis range controls
31
+ - Category visibility checkboxes
32
+ - Brush selection
33
+ - Statistics for the selected / displayed range
34
+ - count
35
+ - mean
36
+ - standard deviation
37
+ - maximum
38
+ - minimum
39
+ - Statistics based on total stacked-bar height for the secondary axis
40
+ - Daily and exact-time modes for temporal data
41
+ - Reversible left/right y-axis orientation
42
+ - Self-contained offline HTML output
43
+ - No CDN access required for generated HTML
44
+
45
+ ---
6
46
 
7
47
  ## Installation
8
48
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
49
+ Add this line to your application's Gemfile:
50
+
51
+ ```ruby
52
+ gem "vg_helper"
53
+ ```
54
+
55
+ and run:
56
+
57
+ ```sh
58
+ bundle install
59
+ ```
60
+
61
+ Or install it directly:
62
+
63
+ ```sh
64
+ gem install vg_helper
65
+ ```
66
+
67
+ Then:
68
+
69
+ ```ruby
70
+ require "vg_helper"
71
+ require "rover"
72
+ ```
73
+
74
+ ---
75
+
76
+ ## Quick Start
77
+
78
+ ```ruby
79
+ require "vg_helper"
80
+ require "rover"
81
+
82
+ df = Rover::DataFrame.new(
83
+ {
84
+ "datetime" => [
85
+ "2026-01-01 10:00:00",
86
+ "2026-01-02 10:00:00",
87
+ "2026-01-03 10:00:00",
88
+ "2026-01-04 10:00:00"
89
+ ],
90
+ "category" => [
91
+ "A", "A", "A", "A"
92
+ ],
93
+ "value" => [
94
+ 10, 15, 12, 18
95
+ ]
96
+ }
97
+ )
98
+
99
+ chart = VGHelper.draw_xdate(
100
+ df,
101
+ "datetime",
102
+ "value",
103
+ "category"
104
+ )
105
+ ```
106
+
107
+ ### Jupyter Notebook / IRuby
108
+
109
+ In Jupyter Notebook with IRuby, place the chart object at the end of
110
+ the cell to display it directly:
111
+
112
+ ```ruby
113
+ chart
114
+ ```
115
+
116
+ A complete cell can simply end with:
117
+
118
+ ```ruby
119
+ chart = VGHelper.draw_xdate(
120
+ df,
121
+ "datetime",
122
+ "value",
123
+ "category"
124
+ )
125
+
126
+ chart
127
+ ```
128
+
129
+ The same applies to charts created with `draw_xnominal`.
130
+
131
+ ### Offline HTML output
132
+
133
+ To write the chart to an HTML file instead, use `write_htmls`:
134
+
135
+ ```ruby
136
+ VGHelper.write_htmls(chart, "chart.html")
137
+ ```
138
+
139
+ `write_htmls` uses the bundled `vega.min.js`, `vega-lite.min.js`, and
140
+ `vega-embed.min.js` files. The generated HTML does not load these
141
+ libraries from a CDN and can be viewed without a network connection.
142
+
143
+ Open `chart.html` in a browser to view the interactive chart.
144
+
145
+ ---
146
+
147
+ # `draw_xdate`
148
+
149
+ `draw_xdate` creates a chart with a temporal x-axis.
150
+
151
+ ```ruby
152
+ VGHelper.draw_xdate(
153
+ df,
154
+ x_col,
155
+ y_col,
156
+ category_col,
157
+ ...
158
+ )
159
+ ```
160
+
161
+ Basic example:
162
+
163
+ ```ruby
164
+ chart = VGHelper.draw_xdate(
165
+ df,
166
+ "datetime",
167
+ "temperature",
168
+ "station"
169
+ )
170
+ ```
171
+
172
+ The fourth argument specifies the column used to separate the data
173
+ into series.
174
+
175
+ ---
176
+
177
+ ## Multiple category columns
178
+
179
+ An array of columns can be supplied as `category_col`.
180
+
181
+ ```ruby
182
+ chart = VGHelper.draw_xdate(
183
+ df,
184
+ "datetime",
185
+ "temperature",
186
+ ["pref", "city"]
187
+ )
188
+ ```
189
+
190
+ VGHelper combines the values internally and treats each combination
191
+ as an independent series.
192
+
193
+ ---
194
+
195
+ ## Time modes
196
+
197
+ `draw_xdate` supports two time modes.
198
+
199
+ ### Daily mode
200
+
201
+ ```ruby
202
+ time_mode: :day
203
+ ```
204
+
205
+ Dates are normalized to the beginning of each calendar day.
206
+
207
+ This is useful when the time of day is irrelevant and the x-axis
208
+ should represent daily observations.
209
+
210
+ ```ruby
211
+ chart = VGHelper.draw_xdate(
212
+ df,
213
+ "datetime",
214
+ "value",
215
+ "category",
216
+ time_mode: :day
217
+ )
218
+ ```
219
+
220
+ ### Exact-time mode
221
+
222
+ ```ruby
223
+ time_mode: :exact
224
+ ```
225
+
226
+ The time of day is preserved.
227
+
228
+ ```ruby
229
+ chart = VGHelper.draw_xdate(
230
+ df,
231
+ "datetime",
232
+ "value",
233
+ "category",
234
+ time_mode: :exact
235
+ )
236
+ ```
237
+
238
+ Use this for hourly, minute-level, or other intraday data.
239
+
240
+ ---
241
+
242
+ # `draw_xnominal`
243
+
244
+ `draw_xnominal` creates a chart whose x-axis consists of discrete
245
+ ordered values.
246
+
247
+ For example:
248
+
249
+ ```ruby
250
+ df = Rover::DataFrame.new(
251
+ {
252
+ "step" => [
253
+ "STEP_001",
254
+ "STEP_002",
255
+ "STEP_003",
256
+ "STEP_004"
257
+ ],
258
+ "value" => [
259
+ 10, 13, 18, 16
260
+ ],
261
+ "category" => [
262
+ "A", "A", "A", "A"
263
+ ]
264
+ }
265
+ )
266
+
267
+ chart = VGHelper.draw_xnominal(
268
+ df,
269
+ "step",
270
+ "value",
271
+ "category"
272
+ )
273
+ ```
274
+
275
+ The original order of x values is preserved.
276
+
277
+ This makes `draw_xnominal` useful for data such as:
278
+
279
+ ```text
280
+ STEP_001
281
+ STEP_002
282
+ STEP_003
283
+ ...
284
+ ```
285
+
286
+ where the x values are categories but their sequence is meaningful.
287
+
288
+ ---
289
+
290
+ ## Limiting the initial x range
291
+
292
+ For large nominal datasets:
293
+
294
+ ```ruby
295
+ initialxpoints: 100
296
+ ```
297
+
298
+ controls the number of x positions initially displayed.
299
+
300
+ For example:
301
+
302
+ ```ruby
303
+ chart = VGHelper.draw_xnominal(
304
+ df,
305
+ "step",
306
+ "value",
307
+ "category",
308
+ initialxpoints: 100
309
+ )
310
+ ```
311
+
312
+ ---
313
+
314
+ # Interactive controls
315
+
316
+ ## X-axis controls
317
+
318
+ The x-axis range controls can be enabled or disabled.
319
+
320
+ ```ruby
321
+ xslide: true
322
+ ```
323
+
324
+ or:
325
+
326
+ ```ruby
327
+ xslide: false
328
+ ```
329
+
330
+ For `draw_xdate`, the controls modify the temporal range.
331
+
332
+ For `draw_xnominal`, they modify the range of displayed x positions.
333
+
334
+ ---
335
+
336
+ ## Y-axis controls
337
+
338
+ Y-axis controls can be enabled with:
339
+
340
+ ```ruby
341
+ yslide: true
342
+ ```
343
+
344
+ and disabled with:
345
+
346
+ ```ruby
347
+ yslide: false
348
+ ```
349
+
350
+ The control type can also be selected:
351
+
352
+ ```ruby
353
+ yrangechanger: "number"
354
+ ```
355
+
356
+ or:
10
357
 
11
- Install the gem and add to the application's Gemfile by executing:
358
+ ```ruby
359
+ yrangechanger: "range"
360
+ ```
361
+
362
+ Explicit y ranges can be supplied where appropriate:
363
+
364
+ ```ruby
365
+ miny: 0,
366
+ maxy: 100
367
+ ```
368
+
369
+ ---
370
+
371
+ ## Category checkboxes
372
+
373
+ Series visibility can be controlled interactively.
374
+
375
+ ```ruby
376
+ category_check: true
377
+ ```
378
+
379
+ This adds a checkbox for each category.
380
+
381
+ To hide these controls:
382
+
383
+ ```ruby
384
+ category_check: false
385
+ ```
386
+
387
+ ---
388
+
389
+ # Brush selection and statistics
390
+
391
+ Both chart helpers support interactive x-axis brush selection.
392
+
393
+ Drag across part of the chart to select a range.
394
+
395
+ VGHelper displays statistics for the selected data:
396
+
397
+ ```text
398
+ n
399
+ avg
400
+ std
401
+ max
402
+ min
403
+ ```
404
+
405
+ For example:
406
+
407
+ ```text
408
+ temperature n: 32 avg: 21.45 std: 2.18 max: 25.60 min: 17.90
409
+ ```
410
+
411
+ When no smaller brush range is selected, the statistics correspond
412
+ to the currently displayed range.
413
+
414
+ Category visibility settings are also reflected in the statistics.
415
+
416
+ ---
417
+
418
+ # Secondary y-axis
419
+
420
+ A second `Rover::DataFrame` can be displayed as bars using a
421
+ secondary y-axis.
422
+
423
+ ```ruby
424
+ chart = VGHelper.draw_xdate(
425
+ df,
426
+ "datetime",
427
+ "temperature",
428
+ "station",
429
+
430
+ df2: volume_df,
431
+ x2_col: "datetime",
432
+ y2_col: "volume"
433
+ )
434
+ ```
435
+
436
+ This produces a main chart together with bars using an independent
437
+ y scale.
438
+
439
+ ---
440
+
441
+ ## Stacked secondary-axis bars
442
+
443
+ A category can also be assigned to the secondary data.
444
+
445
+ ```ruby
446
+ chart = VGHelper.draw_xdate(
447
+ df,
448
+ "datetime",
449
+ "temperature",
450
+ "station",
451
+
452
+ df2: volume_df,
453
+ x2_col: "datetime",
454
+ y2_col: "volume",
455
+ y2_category_col: "product"
456
+ )
457
+ ```
458
+
459
+ Rows sharing the same x position are displayed as stacked bars.
460
+
461
+ For statistical calculations, VGHelper first calculates the total
462
+ height of each stacked bar.
463
+
464
+ For example, if one x position contains:
465
+
466
+ ```text
467
+ Product A : 10
468
+ Product B : 15
469
+ Product C : 5
470
+ ```
471
+
472
+ it is treated as one observation:
473
+
474
+ ```text
475
+ 30
476
+ ```
477
+
478
+ The mean, standard deviation, maximum, minimum, and count displayed
479
+ for the secondary axis are then calculated from these stacked totals,
480
+ rather than from the individual bar segments.
481
+
482
+ ---
483
+
484
+ # Axis orientation
485
+
486
+ By default, the main y-axis is displayed on the left and the
487
+ secondary y-axis on the right.
488
+
489
+ The orientation can be reversed:
490
+
491
+ ```ruby
492
+ reverse_orient: true
493
+ ```
494
+
495
+ This places the main axis on the right and the secondary axis
496
+ on the left.
497
+
498
+ ---
499
+
500
+ # Horizontal reference lines
501
+
502
+ Horizontal reference lines can be added with `horizontallines`.
12
503
 
13
- ```bash
14
- bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
504
+ ```ruby
505
+ horizontallines: [
506
+ [20, "Target"],
507
+ [30, "Upper Limit"]
508
+ ]
15
509
  ```
16
510
 
17
- If bundler is not being used to manage dependencies, install the gem by executing:
511
+ Colors can be specified separately:
18
512
 
19
- ```bash
20
- gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
513
+ ```ruby
514
+ horizontalcolors: [
515
+ "#0000ff",
516
+ "#ff0000"
517
+ ]
21
518
  ```
22
519
 
23
- ## Usage
520
+ Reference lines are useful for targets, limits, thresholds,
521
+ specifications, and other fixed values.
24
522
 
25
- TODO: Write usage instructions here
523
+ ---
26
524
 
27
- ## Development
525
+ # Vertical reference lines
28
526
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
527
+ Vertical reference lines can also be added.
30
528
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
529
+ For a date chart:
530
+
531
+ ```ruby
532
+ verticallines: [
533
+ ["2026-01-10", "Close"],
534
+ ["2026-01-20", "Restart"]
535
+ ]
536
+ ```
537
+
538
+ For a nominal chart:
539
+
540
+ ```ruby
541
+ verticallines: [
542
+ ["STEP_020", "Event A"],
543
+ ["STEP_050", "Event B"]
544
+ ]
545
+ ```
546
+
547
+ Colors can be specified with:
548
+
549
+ ```ruby
550
+ verticalcolors: [
551
+ "#0000ff",
552
+ "#ff0000"
553
+ ]
554
+ ```
555
+
556
+ Vertical lines can be used to indicate important x positions.
557
+
558
+ ---
559
+
560
+ # Custom marks
561
+
562
+ The Vega-Lite mark definition can be customized with `markkind`.
563
+
564
+ For example:
565
+
566
+ ```ruby
567
+ markkind: {
568
+ type: "line",
569
+ point: {
570
+ filled: true,
571
+ size: 40
572
+ },
573
+ tooltip: true
574
+ }
575
+ ```
576
+
577
+ This allows VGHelper to expose Vega-Lite's mark configuration while
578
+ providing convenient defaults.
579
+
580
+ ---
581
+
582
+ # Offline HTML output
583
+
584
+ VGHelper is designed to work without access to external CDNs.
585
+
586
+ The gem bundles local copies of:
587
+
588
+ ```text
589
+ vega.min.js
590
+ vega-lite.min.js
591
+ vega-embed.min.js
592
+ ```
593
+
594
+ `write_htmls` embeds these JavaScript files directly into the output
595
+ HTML.
596
+
597
+ ```ruby
598
+ VGHelper.write_htmls(
599
+ chart,
600
+ "chart.html"
601
+ )
602
+ ```
603
+
604
+ The resulting file can therefore be opened without accessing
605
+ jsDelivr, unpkg, or another CDN.
606
+
607
+ This can be particularly useful in:
608
+
609
+ - corporate proxy environments
610
+ - restricted networks
611
+ - isolated analysis environments
612
+ - offline machines
613
+
614
+ Multiple charts can also be written to the same HTML file:
615
+
616
+ ```ruby
617
+ VGHelper.write_htmls(
618
+ [chart1, chart2, chart3],
619
+ "charts.html"
620
+ )
621
+ ```
622
+
623
+ ---
624
+
625
+
626
+ # TODO
627
+
628
+ VGHelper is still under development.
629
+
630
+ Planned features include:
631
+
632
+ - [ ] Export charts as images
633
+ - [ ] Improve customization of Vega-Lite parameters
634
+ - [ ] Improve documentation and examples
635
+
636
+ ---
637
+
638
+ # Dependencies
639
+
640
+ VGHelper currently uses:
641
+
642
+ - Ruby
643
+ - `vega`
644
+ - `rover`
645
+
646
+ Vega, Vega-Lite, and Vega-Embed JavaScript runtimes are bundled
647
+ for offline HTML output.
648
+
649
+ ---
650
+
651
+ # Development
652
+
653
+ After checking out the repository:
654
+
655
+ ```sh
656
+ bundle install
657
+ ```
658
+
659
+ Run the test suite with:
660
+
661
+ ```sh
662
+ bundle exec rspec
663
+ ```
664
+
665
+ To build the gem locally:
666
+
667
+ ```sh
668
+ gem build vg_helper.gemspec
669
+ ```
670
+
671
+ ---
32
672
 
33
673
  ## Contributing
34
674
 
@@ -37,3 +677,8 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERN
37
677
  ## License
38
678
 
39
679
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
680
+
681
+ The bundled Vega, Vega-Lite, and Vega-Embed JavaScript files remain
682
+ subject to their respective licenses.
683
+
684
+ Please see the relevant license files for details.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module VgHelper
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.2"
5
5
  end
data/lib/vg_helper.rb CHANGED
@@ -1,14 +1,18 @@
1
1
  require "vega"
2
2
  require "rover"
3
+ require "json"
3
4
 
4
5
  # パラメータを任意に足せる/変更できるようにするには?
5
- # 第2軸の設定は?
6
- # 垂直線も入れたい
7
- # 日付軸の水平線 点線未対応
8
6
 
9
7
  # Use Rover::DataFrame, Not Daru
10
8
  # Usage: VGHelper::draw_xdate(df, "datetime", "value", ["category1", "category2"])
11
9
 
10
+ # TODO:
11
+ # With a secondary y-axis, the horizontal-line layer creates another
12
+ # y-axis overlapping the main y-axis because y scales are independent.
13
+ # Currently both axes intentionally use the same style.
14
+ # Refactor main + horizontal layers into a nested layer in a future release.
15
+
12
16
  module VGHelper
13
17
 
14
18
  # functionalize
@@ -51,6 +55,60 @@ module VGHelper
51
55
  Time.local(t.year, t.month, t.day).to_i * 1000
52
56
  end
53
57
 
58
+ def mark_preset(kind)
59
+ case kind
60
+ when :line
61
+ {
62
+ type: "line",
63
+ tooltip: true,
64
+ clip: true
65
+ }
66
+
67
+ when :line_dot
68
+ {
69
+ type: "line",
70
+ point: {
71
+ filled: true,
72
+ size: 40
73
+ },
74
+ tooltip: true,
75
+ clip: true
76
+ }
77
+
78
+ when :small_dot
79
+ {
80
+ type: "point",
81
+ filled: true,
82
+ size: 25,
83
+ opacity: 0.75,
84
+ tooltip: true,
85
+ clip: true
86
+ }
87
+
88
+ when :large_dot
89
+ {
90
+ type: "point",
91
+ filled: true,
92
+ size: 100,
93
+ opacity: 0.75,
94
+ tooltip: true,
95
+ clip: true
96
+ }
97
+
98
+ when :bar
99
+ {
100
+ type: "bar",
101
+ opacity: 0.75,
102
+ tooltip: true,
103
+ clip: true
104
+ }
105
+
106
+ else
107
+ raise ArgumentError,
108
+ "unknown mark preset: #{kind.inspect}"
109
+ end
110
+ end
111
+
54
112
  def draw_xdate(df, x_col, y_col, category_col,
55
113
  df2: nil, x2_col: nil, y2_col: nil, y2_category_col: nil,
56
114
  horizontallines: [], horizontalcolors: nil,
@@ -78,11 +136,11 @@ module VGHelper
78
136
  values1 = df.dup
79
137
 
80
138
  if category_col.is_a?(Array)
81
- values1["multicategory"] =
82
- values1[category_col].to_a.map { _1.values.join("_") }
83
- category_col = "multicategory"
139
+ values1["multicategory"] =
140
+ values1[category_col].to_a.map { _1.values.join("_") }
141
+ category_col = "multicategory"
84
142
  else
85
- category_col = category_col.to_s
143
+ category_col = category_col.to_s
86
144
  end
87
145
  ############################
88
146
  # Default Settings
@@ -90,21 +148,36 @@ module VGHelper
90
148
 
91
149
  categories ||= values1[category_col].to_a.uniq
92
150
 
93
- markkind ||= {
94
- type: "line",
95
- point: { filled: true, size: 40 },
96
- tooltip: true,
97
- clip: true
98
- }
151
+ #markkind ||= {
152
+ # type: "line",
153
+ # point: { filled: true, size: 40 },
154
+ # tooltip: true,
155
+ # clip: true
156
+ #}
157
+
158
+ markkind =
159
+ case markkind
160
+ when nil
161
+ mark_preset(:line_dot)
162
+ when Symbol
163
+ mark_preset(markkind)
164
+ when Hash
165
+ markkind
166
+ else
167
+ raise ArgumentError,
168
+ "markkind must be a Symbol or Hash"
169
+ end
170
+
171
+
99
172
  title ||= y_col
100
173
 
101
174
  colorset ||= (["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd",
102
175
  "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf",
103
176
  "#393b79", "#637939", "#8c6d31", "#843c39", "#7b4173"] * 10)[0...(categories.length)]
104
177
  horizontalcolors ||= (["#0000ff", "#ff0000"] * 6)[0...(horizontallines.length)]
105
- colorset += horizontalcolors
178
+ # colorset += horizontalcolors
106
179
  verticalcolors ||= (["#0000ff", "#ff0000"] * 6)[0...(verticallines.length)]
107
- colorset += verticalcolors
180
+ # colorset += verticalcolors
108
181
 
109
182
  x1_msec = values1[x_col].to_a.map { |v| udate(v) }
110
183
 
@@ -235,6 +308,12 @@ module VGHelper
235
308
  # x_encoding[:timeUnit] = "utcyearmonthdate"
236
309
  #end
237
310
 
311
+ main_y_axis = {
312
+ orient: reverse_orient ? :right : :left,
313
+ titleFontSize: 16,
314
+ labelFontSize: 14
315
+ }
316
+
238
317
  # 水平線データの構築
239
318
  horiz_layer = []
240
319
  if horizontallines && !horizontallines.empty?
@@ -265,7 +344,8 @@ module VGHelper
265
344
  field: y_col,
266
345
  type: "quantitative",
267
346
  scale: { domain: [{expr: "min_y"}, {expr: "max_y"}] },
268
- axis: nil
347
+ axis: main_y_axis
348
+ #axis: nil
269
349
  },
270
350
  color: {
271
351
  field: category_col,
@@ -275,7 +355,8 @@ module VGHelper
275
355
  range: horizontalcolors
276
356
  }
277
357
  }
278
- }
358
+ },
359
+
279
360
  }]
280
361
  end
281
362
 
@@ -314,14 +395,6 @@ module VGHelper
314
395
  # filtering parameter settings
315
396
  ############################
316
397
 
317
- # categ_params = categories.map do |c|
318
- # {
319
- # name: "show_#{c}",
320
- # value: true,
321
- # bind: { input: "checkbox", name: c }
322
- # }
323
- # end
324
-
325
398
  params = []
326
399
 
327
400
  if xslide
@@ -393,9 +466,9 @@ module VGHelper
393
466
  ]
394
467
  end
395
468
 
396
- categ_params = categories.map do |c|
469
+ categ_params = categories.map.with_index do |c, i|
397
470
  ctp = {
398
- name: "show_#{c}",
471
+ name: "show_#{i}",
399
472
  value: true
400
473
  }
401
474
 
@@ -411,7 +484,9 @@ module VGHelper
411
484
 
412
485
  params += categ_params
413
486
 
414
- categ_transforms = categories.map {|c| "(show_#{c} && datum.#{category_col} == '#{c}')" }.join(" || ")
487
+ categ_transforms = categories.map.with_index {|c, i|
488
+ "(show_#{i} && datum[#{category_col.to_s.to_json}] == #{c.to_s.to_json})" }
489
+ .join(" || ")
415
490
 
416
491
  # 第二縦軸
417
492
  bar_layer = []
@@ -478,11 +553,12 @@ module VGHelper
478
553
  field: y_col,
479
554
  type: "quantitative",
480
555
  title: y_col,
481
- axis: {
482
- orient: reverse_orient ? :right : :left,
483
- titleFontSize: 16,
484
- labelFontSize: 14
485
- },
556
+ axis: main_y_axis,
557
+ # axis: {
558
+ # orient: reverse_orient ? :right : :left,
559
+ # titleFontSize: 16,
560
+ # labelFontSize: 14
561
+ #},
486
562
  scale: { domain: [{expr: "min_y"}, {expr: "max_y"}] }
487
563
  },
488
564
  color: {
@@ -655,12 +731,17 @@ module VGHelper
655
731
  .width(width)
656
732
  .height(height)
657
733
 
658
- if !v2_array.empty?
659
- builder = builder.resolve(
660
- scale: { y: "independent", color: "independent", x: "shared" },
661
- axis: { x: "shared" }
734
+ resolve_scale = {
735
+ color: "independent",
736
+ x: "shared"
737
+ }
738
+
739
+ resolve_scale[:y] = "independent" unless v2_array.empty?
740
+
741
+ builder = builder.resolve(
742
+ scale: resolve_scale,
743
+ axis: { x: "shared" }
662
744
  )
663
- end
664
745
 
665
746
  builder
666
747
 
@@ -721,15 +802,28 @@ module VGHelper
721
802
  # Mark settings
722
803
  ############################
723
804
 
724
- markkind = {
725
- type: "line",
726
- tooltip: true,
727
- point: {
728
- filled: false,
729
- size: 20
730
- },
731
- clip: true
732
- }.merge(markkind || {})
805
+ # markkind = {
806
+ # type: "line",
807
+ # tooltip: true,
808
+ # point: {
809
+ # filled: false,
810
+ # size: 20
811
+ # },
812
+ # clip: true
813
+ # }.merge(markkind || {})
814
+
815
+ markkind =
816
+ case markkind
817
+ when nil
818
+ mark_preset(:line_dot)
819
+ when Symbol
820
+ mark_preset(markkind)
821
+ when Hash
822
+ markkind
823
+ else
824
+ raise ArgumentError,
825
+ "markkind must be a Symbol or Hash"
826
+ end
733
827
 
734
828
  ############################
735
829
  # Main dataframe
@@ -1036,9 +1130,9 @@ module VGHelper
1036
1130
 
1037
1131
  if category_check
1038
1132
  category_params =
1039
- categories.map do |c|
1133
+ categories.map.with_index do |c, i|
1040
1134
  {
1041
- name: "show_#{c}",
1135
+ name: "show_#{i}",
1042
1136
  value: true,
1043
1137
  bind: {
1044
1138
  input: "checkbox",
@@ -1050,8 +1144,8 @@ module VGHelper
1050
1144
  params += category_params
1051
1145
 
1052
1146
  categ_filter_str =
1053
- categories.map do |c|
1054
- "(show_#{c} && datum['#{category_col_str}'] == '#{c}')"
1147
+ categories.map.with_index do |c, i|
1148
+ "(show_#{i} && datum[#{category_col_str.to_s.to_json}] == #{c.to_s.to_json})"
1055
1149
  end.join(" || ")
1056
1150
 
1057
1151
  category_transforms = [
@@ -1062,6 +1156,16 @@ module VGHelper
1062
1156
  ]
1063
1157
  end
1064
1158
 
1159
+ ############################
1160
+ # Y Axises
1161
+ ############################
1162
+
1163
+ main_y_axis = {
1164
+ orient: reverse_orient ? :right : :left,
1165
+ titleFontSize: 16,
1166
+ labelFontSize: 14
1167
+ }
1168
+
1065
1169
  ############################
1066
1170
  # Common X encoding
1067
1171
  ############################
@@ -1176,21 +1280,12 @@ module VGHelper
1176
1280
 
1177
1281
  encoding: {
1178
1282
  y: {
1179
- field:
1180
- y_col_str,
1181
-
1182
- type:
1183
- "quantitative",
1184
-
1185
- scale: {
1186
- domain:
1187
- ydomain
1188
- },
1189
-
1190
- axis:
1191
- nil
1283
+ field: y_col_str,
1284
+ type: "quantitative",
1285
+ scale: { domain: ydomain },
1286
+ axis: main_y_axis
1287
+ #axis: nil
1192
1288
  },
1193
-
1194
1289
  color: {
1195
1290
  field:
1196
1291
  category_col_str,
@@ -1300,27 +1395,15 @@ module VGHelper
1300
1395
  field:
1301
1396
  y_col_str,
1302
1397
 
1303
- type:
1304
- "quantitative",
1305
-
1306
- axis: {
1307
- orient:
1308
- reverse_orient ? :right : :left,
1309
-
1310
- title:
1311
- y_col_str,
1312
-
1313
- titleFontSize:
1314
- 16,
1315
-
1316
- labelFontSize:
1317
- 14
1318
- },
1319
-
1320
- scale: {
1321
- domain:
1322
- ydomain
1323
- }
1398
+ type: "quantitative",
1399
+ # axis: {
1400
+ # orient: reverse_orient ? :right : :left,
1401
+ # title: y_col_str,
1402
+ # titleFontSize: 16,
1403
+ # labelFontSize: 14,
1404
+ # },
1405
+ axis: main_y_axis,
1406
+ scale: { domain: ydomain }
1324
1407
  },
1325
1408
 
1326
1409
  color: {
@@ -1539,29 +1622,26 @@ module VGHelper
1539
1622
  ############################
1540
1623
  # Build
1541
1624
  ############################
1542
-
1625
+
1543
1626
  builder =
1544
1627
  Vega.lite
1545
- .data(values: all_data)
1546
- .params(params)
1547
- .encoding(x: x_encoding)
1548
- .layer(layers)
1549
- .width(width)
1550
- .height(height)
1551
- .title(title)
1628
+ .data(values: all_data)
1629
+ .params(params)
1630
+ .encoding(x: x_encoding)
1631
+ .layer(layers)
1632
+ .width(width)
1633
+ .height(height)
1634
+ .title(title)
1635
+
1636
+ resolve_scale = {
1637
+ color: "independent"
1638
+ }
1552
1639
 
1553
- unless v2_array.empty?
1554
- builder =
1555
- builder.resolve(
1556
- scale: {
1557
- y:
1558
- "independent",
1640
+ resolve_scale[:y] = "independent" unless v2_array.empty?
1559
1641
 
1560
- color:
1561
- "independent"
1562
- }
1642
+ builder = builder.resolve(
1643
+ scale: resolve_scale
1563
1644
  )
1564
- end
1565
1645
 
1566
1646
  builder
1567
1647
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vg_helper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - showata
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-08-25 00:00:00.000000000 Z
11
+ date: 2026-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rover-df