gnuplotの勉強 : 日付&時刻の演算について

gnuplotの日付や時刻の扱い、まだいまいち理解出来ていないので、いつもの解説記事ではなくて勉強している過程で分かった範囲を書いておきます。ちゃんとまとまったら解説記事としてまたまとめ直そうかと予定してます。
現時点ではちゃんとしたまとめではないため、この記事に書いてあることは内容の齟齬や思い違いが含まれるかも知れません。

gnuplotの日付と時刻の扱いのおさらい

日付と時刻の扱い、基本的なことは以前の解説記事に書きました。
単に日付、時刻がデータとして含まれるデータファイルをプロットする分には、そこに書いた内容で対応出来るでしょう。今回考えていくのは、そのデータファイルの日付、時刻のデータに演算処理をしていくことについて。どういうことをしようとしてるのかは次で説明します。

演算処理が必要になる場面

演算処理が必要になる場面として、例えば以下の2つのデータを並べてプロットすることを考えます。
  • 2018年の1年365日のデータ(書式 : 2018/07/21)
  • その5年前の2013年の同様のデータ(書式 : 2013/07/21)
ここでは以下のような簡単なダミーデータを作って試すことにします(Y軸の数値は適当にcos関数で作っています)。

2018年分のダミーデータ
2018年分のダミーデータ

 同様にして2013年のデータも以下のように作っておきます(こっちのY軸はsin関数)。

2013年分のダミーデータ
2013年分のダミーデータ

プロットするにあたり、1月1日から始まるように以下のようにgnuplotの設定を行いプロットしました。
set xdata time
set timefmt "%Y/%m/%d"
set format x "%m/%d"
そしてプロット結果は以下のようになります。

異なる年のデータを並べてプロットしようとして失敗
異なる年のデータを並べてプロットしようとして失敗

プロット結果を見て分かるように、2つの年のデータが大きく離れてプロットされてしまいました。こうなってしまった原因は単純で、x軸の書式を"%m/%d"という書式にしていても開始は"01/01"ではなく"2013/01/01"から始まっているため。なので2018年のデータは5年先の"2018/01/01"の位置からプロットされてしまいこのような失敗グラフになったというわけです。

ここで期待しているのは以下のようなグラフ。
うまくいけばこういうグラフになる
うまくいけばこういうグラフになる

さて、このようなグラフにするにはどうすればよいでしょうか?
簡単に考えればどちらか一方のx軸のデータを5年分ずらせばいいのですが、日付や時刻は数値として簡単に扱えるようにはなっていないためなかなか厄介になってきます。

日付&時刻の演算処理

日付&時刻のテキストデータ書き換え

最も簡単には、gnuplotでは演算処理をせずに、外部のソフトやコマンドでデータファイルの日付からテキスト処理で年を取っ払って月日だけのデータにしてしまうという方法。2つのデータファイルの日付部分をそれぞれ以下のように変換してしまえば簡単にプロットを並べることが出来ます。
  • 2018/01/09 → 01/09
  • 2013/01/09 → 01/09
書き換える方法はsedコマンドを使えば出来るかと思いますが、今回はそこには触れません。
(gnuplotの外部コマンドの出力をそのままデータとして扱う方法を用いれば、gnuplot内でも処理を完結できるとは思います)

timecolumn関数を用いて演算処理を行う

gnuplotでは日付や時刻データは内部では1970年1月1日00:00からの秒数として管理されているようです。そこの部分の処理が詳しくは分からないのですが、日時をずらすのならその分だけの秒数を加えるか引いてやれば良さそうです。
そしてgnuplotにはデータ列の日付、時刻を扱うものとしてtimecolumn関数があります。
この関数は2つの引数を取り、
  • timecolumn(列, "日時の書式")
という形を取ります(set timefmtで書式設定をしていれば引数は列だけでいいかも)。
このtimecolumn関数は指定された書式で日時データを読み込み、1970年からの秒数に変換するようです。そしてプロット時には"set xdata time"、"set format x"の設定により再び日付となってプロットされる。そんな処理となっている模様。
仮にそのような処理になっているとすれば、timecolumn関数の部分でずらす分の日時の秒数を加えるか引いてやればいいでしょう。ものは試しでやってみます。

そしてなんやかんやで試行錯誤して、どうやら次のようにusingで指定すればデータを5年分ずらせることが分かりました(後述しますが、この式には誤りがある)。
  • using (timecolumn(1)+60*60*24*365*5):2
timecolumn関数で日付データが秒数になったところに5年分の秒数(60*60*24*365*5)を加算するという形。これでプロットすることで、上に貼ったようなグラフを得ることが出来ます。

うるう年を考慮する必要性

さて、日時の演算で細かいことですが重要なこととして、うるう年の分をちゃんと計算に入れる必要があります。先程のusingの指定でもプロット結果のグラフをよく見ると(01/01付近を拡大表示)、以下のように1日分ずれてしまっています。これではいけません。

うるう年を考慮しなかったため1日分ずれてしまっている
うるう年を考慮しなかったため1日分ずれてしまっている
比較している2018年と2013年の間の2016年がうるう年だったため、その分の1日も加算する必要があるわけです。というわけで、この場合の5年分の秒数は
  • 60*60*24*(365*5+1)
となります。

うるう秒は?

さて、ここから先が自分ではまったく分かっていない部分なのですが、うるう秒についてはどういう扱いになっているのでしょう?少し試した分にはうるう秒は無視されて扱われているように思えたんですが、このへん実際にどういう扱いになっているのか。もう少し調べてみることにします。うるう秒の挿入される場合について考えれば、影響しない分には無視する方が自然なような気も?
(また、うるう年とそうでない年を並べてプロットする場合の2/29の扱いなどいろいろ考えるべきことが多い)

strftime関数、strptime関数

timecolumn関数では列で指定しますが、個別の数値を引数として変換する関数も用意されています。strftimeとstrptime関数がそれですが、これについてはまた別の記事で使い方などまとめようと思います。


gnuplot関連のブログ記事

コメント

スポンサーリンク


このブログの人気の投稿

Ubuntu Softwareが起動しないのでいろいろと調べてみる(Ubuntu 20.04.1 LTS)

gnuplotでプロットなどの色をcolornameの指定で変更する

gnuplot : グラフにグリッド線を描く方法(set grid)

gnuplot : プロット画像のサイズ指定について(set sizeとの違い)

Pythonのformat()を使って1桁の16進数でも2桁で出力する方法