toji 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/toji/graph/ab.rb CHANGED
@@ -9,27 +9,27 @@ module Toji
9
9
  @expects = []
10
10
  end
11
11
 
12
- def actual(jobs, name=:actual)
13
- data = jobs.map{|j| [j.time || j.elapsed_time + jobs.day_offset, j.alcohol, j.baume]}.select{|a| a[1] && a[2]}
14
- xs = data.map{|a| a[1]}
15
- ys = data.map{|a| a[2]}
16
- texts = data.map{|a| "%s<br />alc=%s, be=%s" % a}
17
- @actuals << {x: xs, y: ys, text: texts, name: name}
18
-
12
+ def actual(moromi, name=:actual)
13
+ @actuals << [moromi, name]
19
14
  self
20
15
  end
21
16
 
22
17
  def expect(alcohol, nihonshudo)
23
18
  @expects << [alcohol.to_f, nihonshudo.to_f]
24
-
25
19
  self
26
20
  end
27
21
 
28
22
  def data
29
23
  result = []
30
24
 
31
- @actuals.each {|a|
32
- result << a
25
+ @actuals.each {|moromi, name|
26
+ data = moromi.map{|j| [j.time || j.elapsed_time + moromi.day_offset, j.alcohol, j.baume]}.select{|a| a[1] && a[2]}
27
+
28
+ xs = data.map{|a| a[1]}
29
+ ys = data.map{|a| a[2]}
30
+ texts = data.map{|a| "%s<br />alc=%s, be=%s" % a}
31
+
32
+ result << {x: xs, y: ys, text: texts, name: name}
33
33
  }
34
34
 
35
35
  @expects.each {|alcohol, nihonshudo|
@@ -44,18 +44,22 @@ module Toji
44
44
  result
45
45
  end
46
46
 
47
- def plot
48
- d = data
47
+ def min_baume
48
+ data.map{|h| h[:y].min}.min || 0
49
+ end
50
+
51
+ def max_baume
52
+ data.map{|h| h[:y].max}.max || 0
53
+ end
49
54
 
50
- #min_baume = d.map{|h| h[:y].min}.min || 0
51
- #min_baume = [min_baume-1, 0].min
52
- min_baume = 0
55
+ def plot
56
+ #_min_baume = [min_baume-1, 0].min
57
+ _min_baume = 0
53
58
 
54
- max_baume = d.map{|h| h[:y].max}.max || 0
55
- max_baume = [max_baume+1, 10].max
59
+ _max_baume = [max_baume+1, 10].max
56
60
 
57
61
  Plotly::Plot.new(
58
- data: d,
62
+ data: data,
59
63
  layout: {
60
64
  xaxis: {
61
65
  title: "Alcohol",
@@ -65,7 +69,7 @@ module Toji
65
69
  yaxis: {
66
70
  title: "Baume",
67
71
  dtick: 1,
68
- range: [min_baume, max_baume],
72
+ range: [_min_baume, _max_baume],
69
73
  }
70
74
  }
71
75
  )
@@ -0,0 +1,56 @@
1
+ module Toji
2
+ module Graph
3
+ class Bmd
4
+
5
+ def initialize
6
+ @actuals = []
7
+ @expects = []
8
+ end
9
+
10
+ def actual(moromi, name=:actual)
11
+ @actuals << [moromi, name]
12
+ self
13
+ end
14
+
15
+ def data
16
+ result = []
17
+
18
+ @actuals.each {|moromi, name|
19
+ jobs = moromi.select{|j| j.moromi_time && j.bmd}
20
+
21
+ xs = jobs.map(&:moromi_time)
22
+ ys = jobs.map(&:bmd)
23
+ texts = jobs.map{|j| "%s<br />moromi day=%d, be=%s, bmd=%s" % [j.time || j.elapsed_time + moromi.day_offset, j.moromi_day, j.baume, j.bmd]}
24
+
25
+ result << {x: xs, y: ys, text: texts, name: name}
26
+ }
27
+
28
+ result
29
+ end
30
+
31
+ def max_moromi_day
32
+ @actuals.map(&:first).map(&:moromi_days).max
33
+ end
34
+
35
+ def plot
36
+ _max_moromi_day = [max_moromi_day, 14].max
37
+
38
+ Plotly::Plot.new(
39
+ data: data,
40
+ layout: {
41
+ xaxis: {
42
+ title: "Moromi day",
43
+ dtick: Product::Job::DAY,
44
+ range: [1, _max_moromi_day].map{|d| d*Product::Job::DAY},
45
+ tickvals: _max_moromi_day.times.map{|d| d*Product::Job::DAY},
46
+ ticktext: _max_moromi_day.times.map(&:succ)
47
+ },
48
+ yaxis: {
49
+ title: "BMD",
50
+ }
51
+ }
52
+ )
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,84 @@
1
+ module Toji
2
+ module Graph
3
+ class Progress
4
+
5
+ def initialize(product)
6
+ @product = product
7
+ end
8
+
9
+ def data(keys=nil)
10
+ data = @product.map(&:to_h).map(&:compact)
11
+ if !keys
12
+ keys = data.map(&:keys).flatten.uniq
13
+ end
14
+
15
+ result = []
16
+
17
+ keys &= [:temps, :preset_temp, :room_temp, :room_psychrometry, :baume, :acid, :amino_acid, :alcohol]
18
+
19
+ keys.each {|key|
20
+ xs = []
21
+ ys = []
22
+ text = []
23
+ data.each {|h|
24
+ if h[key]
25
+ [h[key]].flatten.each_with_index {|v,i|
26
+ xs << h[:elapsed_time] + i + @product.day_offset
27
+ ys << v
28
+ text << h[:display_time]
29
+ }
30
+ end
31
+ }
32
+
33
+ line_shape = :linear
34
+ if key==:preset_temp
35
+ line_shape = :hv
36
+ end
37
+
38
+ result << {x: xs, y: ys, text: text, name: key, line: {shape: line_shape}}
39
+ }
40
+
41
+ if 0<@product.day_offset
42
+ result = result.map{|h|
43
+ h[:x].unshift(0)
44
+ h[:y].unshift(nil)
45
+ h[:text].unshift(nil)
46
+ h
47
+ }
48
+ end
49
+
50
+ result
51
+ end
52
+
53
+ def annotations
54
+ @product.select{|j| j.id}.map {|j|
55
+ {
56
+ x: j.elapsed_time + @product.day_offset,
57
+ y: j.temps.first || 0,
58
+ xref: 'x',
59
+ yref: 'y',
60
+ text: j.id,
61
+ showarrow: true,
62
+ arrowhead: 1,
63
+ ax: 0,
64
+ ay: -40
65
+ }
66
+ }
67
+ end
68
+
69
+ def plot
70
+ Plotly::Plot.new(
71
+ data: data,
72
+ layout: {
73
+ xaxis: {
74
+ dtick: Product::Job::DAY,
75
+ tickvals: @product.days.times.map{|d| d*Product::Job::DAY},
76
+ ticktext: @product.day_labels
77
+ },
78
+ annotations: annotations,
79
+ }
80
+ )
81
+ end
82
+ end
83
+ end
84
+ end
data/lib/toji/graph.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'toji/graph/progress'
2
+ require 'toji/graph/bmd'
1
3
  require 'toji/graph/ab'
2
4
 
3
5
  module Toji
@@ -0,0 +1,74 @@
1
+ module Toji
2
+ module Product
3
+ class Base
4
+ include Enumerable
5
+ extend JobAccessor
6
+
7
+ attr_accessor :date_line
8
+ attr_reader :day_offset
9
+
10
+ def initialize(arr=[], date_line: 0)
11
+ @_arr = []
12
+ @_hash = {}
13
+ @date_line = date_line
14
+ @day_offset = 0
15
+
16
+ arr.each {|j|
17
+ self << j
18
+ }
19
+ end
20
+
21
+ def [](id)
22
+ @_hash[id]
23
+ end
24
+
25
+ def <<(job)
26
+ job = Job.create(job)
27
+ if job.id
28
+ if @_hash[job.id]
29
+ @_arr.delete(@_hash[job.id])
30
+ end
31
+ @_hash[job.id] = job
32
+ end
33
+ @_arr << job
34
+ job.jobs = self
35
+ _normalization
36
+ self
37
+ end
38
+ alias_method :add, :<<
39
+
40
+ def _normalization
41
+ min_time = @_arr.select{|j| j.time}.map(&:time).sort.first
42
+
43
+ if min_time
44
+ @_arr.each {|j|
45
+ if j.time
46
+ j.elapsed_time = (j.time - min_time).to_i
47
+ else
48
+ j.time = min_time + j.elapsed_time
49
+ end
50
+ }
51
+ end
52
+
53
+ @_arr = @_arr.sort{|a,b| a.elapsed_time<=>b.elapsed_time}
54
+
55
+ t = @_arr.first&.time
56
+ if t
57
+ @day_offset = t - Time.mktime(t.year, t.month, t.day)
58
+ else
59
+ @day_offset = 0
60
+ end
61
+ @day_offset += ((24 - @date_line) % 24) * Job::HOUR
62
+ end
63
+
64
+ def each(&block)
65
+ _normalization
66
+ @_arr.each(&block)
67
+ end
68
+
69
+ def days
70
+ ((to_a.last.elapsed_time.to_f + @date_line * Job::HOUR) / Job::DAY).ceil + 1
71
+ end
72
+ end
73
+ end
74
+ end
@@ -1,5 +1,5 @@
1
1
  module Toji
2
- module Progress
2
+ module Product
3
3
  class Job
4
4
  HOUR = 60 * 60
5
5
  DAY = 24 * HOUR
@@ -13,8 +13,7 @@ module Toji
13
13
  attr_accessor :time
14
14
  attr_accessor :elapsed_time
15
15
  attr_accessor :id
16
- attr_accessor :before_temp
17
- attr_accessor :after_temp
16
+ attr_accessor :temps
18
17
 
19
18
  attr_accessor :preset_temp
20
19
  attr_accessor :room_temp
@@ -30,15 +29,14 @@ module Toji
30
29
  attr_accessor :note
31
30
 
32
31
  def initialize(
33
- time: nil, elapsed_time: nil, id: nil, before_temp: nil, after_temp: nil,
32
+ time: nil, elapsed_time: nil, id: nil, temps: nil,
34
33
  preset_temp: nil, room_temp: nil, room_psychrometry: nil,
35
34
  baume: nil, nihonshudo: nil, acid: nil, amino_acid: nil, alcohol: nil,
36
35
  warming: nil, note: nil)
37
36
  @time = time
38
37
  @elapsed_time = elapsed_time
39
38
  @id = id
40
- @before_temp = before_temp
41
- @after_temp = after_temp
39
+ self.temps = temps
42
40
 
43
41
  @preset_temp = preset_temp
44
42
  @room_temp = room_temp
@@ -54,18 +52,8 @@ module Toji
54
52
  @note = note
55
53
  end
56
54
 
57
- def temps
58
- result = []
59
-
60
- if @before_temp
61
- result << @before_temp
62
- end
63
-
64
- if @after_temp
65
- result << @after_temp
66
- end
67
-
68
- result
55
+ def temps=(val)
56
+ @temps = [val].flatten.select{|t| t}
69
57
  end
70
58
 
71
59
  def baume
@@ -86,7 +74,7 @@ module Toji
86
74
  end
87
75
  end
88
76
 
89
- def baume_display
77
+ def display_baume
90
78
  if @baume || @nihonshudo
91
79
  b = baume
92
80
  if b<3.0
@@ -97,6 +85,14 @@ module Toji
97
85
  end
98
86
  end
99
87
 
88
+ def display_time(format="%m/%d %H:%M")
89
+ if @time
90
+ time.strftime(format)
91
+ else
92
+ Time.at(elapsed_time).strftime(format)
93
+ end
94
+ end
95
+
100
96
  def moromi_time
101
97
  tome = jobs[:tome]
102
98
  if tome
@@ -124,6 +120,14 @@ module Toji
124
120
  end
125
121
  end
126
122
 
123
+ def expected_alcohol(target_alc, target_nihonshudo, coef)
124
+ _baume = baume
125
+
126
+ if _baume
127
+ target_alc - (_baume - target_nihonshudo * -0.1) * coef
128
+ end
129
+ end
130
+
127
131
  def warmings
128
132
  result = []
129
133
  if @warming & WARM_DAKI
@@ -142,10 +146,9 @@ module Toji
142
146
  {
143
147
  time: time,
144
148
  elapsed_time: elapsed_time,
149
+ display_time: display_time,
145
150
  id: id,
146
151
  preset_temp: preset_temp,
147
- before_temp: before_temp,
148
- after_temp: after_temp,
149
152
  temps: temps,
150
153
  room_temp: room_temp,
151
154
  room_psychrometry: room_psychrometry,
@@ -160,6 +163,14 @@ module Toji
160
163
  note: note,
161
164
  }
162
165
  end
166
+
167
+ def self.create(j)
168
+ if Job===j
169
+ j
170
+ else
171
+ new(**j.to_h)
172
+ end
173
+ end
163
174
  end
164
175
  end
165
176
  end
@@ -1,5 +1,5 @@
1
1
  module Toji
2
- module Progress
2
+ module Product
3
3
  module JobAccessor
4
4
  def job_reader(*args)
5
5
  args.each {|arg|
@@ -1,67 +1,62 @@
1
1
  module Toji
2
- module Progress
3
- class MakeKoji
4
- extend JobAccessor
2
+ module Product
3
+ class KojiMaking < Base
5
4
 
6
5
  TEMPLATES = {
7
6
  default: [
8
7
  Job.new(
9
8
  elapsed_time: 0 * Job::HOUR,
10
9
  id: :hikikomi,
11
- after_temp: 35.0,
10
+ temps: 35.0,
12
11
  room_temp: 28.0,
13
12
  room_psychrometry: nil,
14
13
  ),
15
14
  Job.new(
16
15
  elapsed_time: 1 * Job::HOUR,
17
16
  id: :tokomomi,
18
- after_temp: 32.0,
17
+ temps: 32.0,
19
18
  room_temp: 28.0,
20
19
  room_psychrometry: nil,
21
20
  ),
22
21
  Job.new(
23
22
  elapsed_time: 9 * Job::HOUR,
24
23
  id: :kirikaeshi,
25
- before_temp: 32.0,
26
- after_temp: 31.0,
24
+ temps: [32.0, 31.0],
27
25
  room_temp: 28.0,
28
26
  room_psychrometry: nil,
29
27
  ),
30
28
  Job.new(
31
29
  elapsed_time: 21 * Job::HOUR,
32
30
  id: :mori,
33
- before_temp: 35.0,
34
- after_temp: 33.0,
31
+ temps: [35.0, 33.0],
35
32
  room_temp: 28.0,
36
33
  room_psychrometry: 4,
37
34
  ),
38
35
  Job.new(
39
36
  elapsed_time: 29 * Job::HOUR,
40
37
  id: :naka_shigoto,
41
- before_temp: 37.0,
42
- after_temp: 35.0,
38
+ temps: [37.0, 35.0],
43
39
  room_temp: 28.0,
44
40
  room_psychrometry: 4,
45
41
  ),
46
42
  Job.new(
47
43
  elapsed_time: 35 * Job::HOUR,
48
44
  id: :shimai_shigoto,
49
- before_temp: 38.0,
50
- after_temp: 37.0,
45
+ temps: [38.0, 37.0],
51
46
  room_temp: 28.0,
52
47
  room_psychrometry: 5,
53
48
  ),
54
49
  Job.new(
55
50
  elapsed_time: 39 * Job::HOUR,
56
51
  id: :tsumikae,
57
- after_temp: 40.0,
52
+ temps: 40.0,
58
53
  room_temp: 28.0,
59
54
  room_psychrometry: 5,
60
55
  ),
61
56
  Job.new(
62
57
  elapsed_time: 44 * Job::HOUR,
63
58
  id: :dekoji,
64
- after_temp: 40.0,
59
+ temps: 40.0,
65
60
  room_temp: 28.0,
66
61
  room_psychrometry: 5,
67
62
  ),
@@ -79,17 +74,16 @@ module Toji
79
74
  job_reader :dekoji
80
75
 
81
76
 
82
- def initialize(jobs=[])
83
- @jobs = Jobs.new(jobs)
77
+ def initialize(jobs=[], date_line: 0)
78
+ super(jobs, date_line: date_line)
84
79
  end
85
80
 
86
- def add(job)
87
- @jobs << job
88
- self
81
+ def day_labels
82
+ days.times.map(&:succ)
89
83
  end
90
84
 
91
- def jobs
92
- @jobs.to_a
85
+ def progress
86
+ Graph::Progress.new(self)
93
87
  end
94
88
 
95
89
  def self.template(key=:default)