タイムラインを作るぞ(2)

ブロックタイプのカロリーメイトの販売期間をタイムラインで表示する。


販売期間のデータ
wikipedia:カロリーメイト
(caloriemate_timeline.txt)

チーズ味,1983-04,
フルーツ味,1984-04,
チョコレート味,1993-10,
ベジタブル味,2000-09,2007
ポテト味,2007-04,2014
メープル味,2009-09,
プレーン味,2014-09,2022
バニラ味,2022-03,

名称、発売開始年月、販売終了年月。


タイムラインを作るぞ - マイノート
のmy_timeline.pl を修正し、my_timeline2.plを作る。


主な修正点
・期間は年月日で指定できるようにした。年月日は年で表現する。
 1981-01-01 → 1981 + ( 1 - 1 ) / 365 = 1981
 1981-01-02 → 1981 + ( 2 - 1 ) / 365 = 1981.00274
 1981-12-31 → 1981 + ( 365 - 1 ) /365 = 1981.99726
 ※月、日は省略してもよい。
  月、日を省略したときは、その年の1月1日。日を省略したときはその月の1日になる。
・終了日を入力しなかった場合は、"-"をタイムラインの終了日まで継続するようにした。
・タイムラインの開始年、終了年、間隔(年)は、対数を使って自動計算するようにし、また、コマンド引数でも指定できるようにした。
 タイムラインの年は、"間隔"*10 で割りきれる場合に表示する。

(my_timeline2.pl)

$ more my_timeline2.pl 
#!/usr/bin/env perl
use DateTime::Format::ISO8601;
use DateTime;

$usage = <<"EOS";
書式
  $0 <event file> [<min date>] [<max date>] [<step>]

説明
  event file : csv形式のファイル。
               event name, start date, end date
               event name : イベントの名称
               start date : 開始日または誕生日。フォーマットはyyyy[-mm[-dd]]
               end date : 終了日または没年月日。フォーマットはyyyy[-mm[-dd]]
  min date : タイムラインの開始年を指定する。
  max date : タイムラインの終了年を指定する。
  step : タイムラインのステップを指定する。単位は年。
EOS

if( $#ARGV < 0 ){
  die $usage;
}

$min = undef;
$max = undef;

$i = 0;

open( FILE, $ARGV[0] ) || die "FILE: $ARGV[0] not found.";

while(<FILE>){

  chomp();
  ($name, $start_date, $end_date) = split(/,/);

  $event[$i]{name} = $name;

  if( $start_date =~ /^(\d{4}(-(0[1-9]|1[0-2]){1}(-(0[1-9]|[12][0-9]|3[01]){1}){0,1}){0,1})(\?*)$/ ){
    #print "$1, $2, $3, $4, $5, $6";
    $event[$i]{start_date} = $start_date;
    $event[$i]{start_question} = $6;
    $temp = DateTime::Format::ISO8601->parse_datetime($1);
    $event[$i]{start_year} = $start_year = $temp->year + ( $temp->day_of_year - 1 ) / ( 365 + $temp->is_leap_year );
  }

  if( $end_date =~ /^(\d{4}(-(0[1-9]|1[0-2]){1}(-(0[1-9]|[12][0-9]|3[01]){1}){0,1}){0,1})(\?*)$/ ){
    #print "$1, $2, $3, $4, $5, $6";
    $event[$i]{end_date} = $end_date;
    $event[$i]{end_question} = $6;
    $temp = DateTime::Format::ISO8601->parse_datetime($1);
    $event[$i]{end_year} = $end_year = $temp->year + ( $temp->day_of_year - 1 ) / ( 365 + $temp->is_leap_year );
  }else{
    $event[$i]{end_date} = "";
    $event[$i]{end_question} = "";
    $event[$i]{end_year} = "continue";
  }

  if( $min eq undef || $start_year < $min ){ $min = $start_year; }
  if( $max eq undef || $max < $end_year ){ $max = $end_year; }

  $i++;

}

$n = $i;

print "min:$min\n";
print "max:$max\n";
$diff = $max - $min;
print "diff:$diff\n\n";

$a = int(log($diff)/log(10)); #maxとminの差から10を底とする対数を求める

if( $ARGV[1] ){
  $min = int( $ARGV[1] );
}else{
  $min = int( $min / 10 ** $a ) * 10 ** $a; #下位の数字を切り捨てる
}

if( $ARGV[2] ){
  $max = int( $ARGV[2] );
}else{
  $max = int( $max / 10 ** $a  + 1 ) * 10 ** $a; #下位の数字を切り上げる
}

print "range: $min - $max\n";

if( $ARGV[3] ){
  $step = $ARGV[3];
}else{
  $step = 10 ** $a / 10;
}

print "step:$step\n\n";

#年を描く
for($i=$min; $i<=$max; $i+=$step){
  if( $i == int($i) && $i % ( $step * 10 ) == 0 ){
    print $i;
    $len = length($i) - 1;
  }elsif( $len > 0 ){
    $len--;
  }else{
    print " ";
  }
}
print "\n";

#線を描く
for($i=$min; $i<=$max; $i+=$step){
  if( $i == int($i) && $i % ( $step * 10 ) == 0 ){
    print "+";
  }else{
    print "-";
  }
}
print "\n";

#個々のイベントを描く
for($i=0; $i<$n; $i++){

  if( $event[$i]{end_year} == "continue" ){
    $event[$i]{end_year} = $max * 10; #大きい数字にする
  }

  #print "$event[$i]{start_year} - $event[$i]{end_year}\n";

  $status = "out";
  for($j=$min; $j<=$max; $j+=$step){

    if( $j <= $event[$i]{start_year} && $event[$i]{start_year} < $j + $step ){
      if( $event[$i]{start_question} ){
        print "?";
      }else{
        print "I";
      }
    }elsif( $j <= $event[$i]{end_year} && $event[$i]{end_year} < $j + $step ){
      if( $event[$i]{end_question} ){
        print "?";
      }else{
        print "I";
      }
    }else{
      if( $event[$i]{start_year} <= $j && $j <= $event[$i]{end_year} ){
        print "-";
      }else{
        print " ";
      }
    }

  }

  print " $event[$i]{name}, $event[$i]{start_date} - $event[$i]{end_date}\n";

}


使ってみる

$ ./my_timeline2.pl caloriemate_timeline.txt 
min:1983.24657534247
max:2022
diff:38.7534246575342

range: 1980 - 2030
step:1

1980      1990      2000      2010      2020      2030
+---------+---------+---------+---------+---------+
   I----------------------------------------------- チーズ味, 1983-04 - 
    I---------------------------------------------- フルーツ味, 1984-04 - 
             I------------------------------------- チョコレート味, 1993-10 - 
                    I------I                        ベジタブル味, 2000-09 - 2007
                           I------I                 ポテト味, 2007-04 - 2014
                             I--------------------- メープル味, 2009-09 - 
                                  I-------I         プレーン味, 2014-09 - 2022
                                          I-------- バニラ味, 2022-03 - 


自動計算だとタイムラインの終了日が2030年になるので、終了年を2022年にする。

$ ./my_timeline2.pl caloriemate_timeline.txt 1980 2022
min:1983.24657534247
max:2022
diff:38.7534246575342

range: 1980 - 2022
step:1

1980      1990      2000      2010      2020
+---------+---------+---------+---------+--
   I--------------------------------------- チーズ味, 1983-04 - 
    I-------------------------------------- フルーツ味, 1984-04 - 
             I----------------------------- チョコレート味, 1993-10 - 
                    I------I                ベジタブル味, 2000-09 - 2007
                           I------I         ポテト味, 2007-04 - 2014
                             I------------- メープル味, 2009-09 - 
                                  I-------I プレーン味, 2014-09 - 2022
                                          I バニラ味, 2022-03 - 


タイムラインの間隔を0.5年に変更してみる。

$ ./my_timeline2.pl caloriemate_timeline.txt 1980 2022 0.5
min:1983.24657534247
max:2022
diff:38.7534246575342

range: 1980 - 2022
step:0.5

1980      1985      1990      1995      2000      2005      2010      2015      2020 
+---------+---------+---------+---------+---------+---------+---------+---------+----
      I------------------------------------------------------------------------------ チーズ味, 1983-04 - 
        I---------------------------------------------------------------------------- フルーツ味, 1984-04 - 
                           I--------------------------------------------------------- チョコレート味, 1993-10 - 
                                         I------------I                               ベジタブル味, 2000-09 - 2007
                                                      I-------------I                 ポテト味, 2007-04 - 2014
                                                           I------------------------- メープル味, 2009-09 - 
                                                                     I--------------I プレーン味, 2014-09 - 2022
                                                                                    I バニラ味, 2022-03 -