HTML の折れ線グラフを出力する 【Python】

Python

Python で HTML の折れ線グラフを出力するスクリプトをまとめておきます。
JavaScript などのライブラリは使わず、テキストファイルの数値データから、ローカルのパソコンなどでも参照できる標準的な HTML のグラフを生成します。オープンソースで無料のデータ可視化ソフトウェアです。

以下の環境で動作確認をしています。
環境: Windows パソコン、Python 3.x

背景 ~ 折れ線グラフの生成トライ!

Python を使って、データ収集やデータ分析の自動化を試みています。データを日々収集していくと、日付つきのデータやログが増えていくことになります。
たとえば、日々の株価や為替、温湿度、天気などです。企業業績や雇用統計、経済指標についても、時系列でのデータがダウンロードできるサイトがあります。
こういったデータは、単純なテキストファイルや CSV ファイル程度であって、日時と数値が並んだ形式であることが多いです。

以前に、Python を使って、棒グラフの HTML を生成するスクリプトについてまとめています。しかし、データが多数あったり、日々増えていくような場合は、折れ線グラフのほうが扱いやすいです。
また、複数の折れ線グラフを1つの欄にまとめ、比較したいこともよくあります。

ということで、数値データを HTML の折れ線グラフに変換するスクリプトをまとめ、公開しておくことにします。
Python を実行すると、テキストファイルを読み込んで、折れ線グラフの HTML で出力することでデータの可視化が実現します。
拡張子等を変更して CSV ファイルを読み込むようにするなど、自由に改変できると思います。

なお、グラフ描画となると、一般には JavaScript のライブラリなどの可視化ツールが知られています。しかし、ライブラリに習熟するのに時間や手間がかかりますし、設定も煩雑です。知らないうちにライブラリやブラウザがバージョンアップして、動かなくなることもよくあります。
また、Excel を使うという手もありますが、どのような環境でも参照できる単純なグラフを作るだけのために Excel や VBA を扱うといった手間も減らしたいところです。
そこで、余計なライブラリやツールは使わずに、ブラウザが標準で対応しているベクター形式(SVG 形式)を Python から直接生成することで、極力シンプルで軽量なグラフを出力することにします。
出力は平易な HTML としており、SVG ファイルも出力できます。OS 環境に強く依存せず、グラフを広範に流用できるよう意図しています。

設定方法

① ローカルパソコンにフォルダ(”html_chart1″ など)を作成してください。
例: C:/user/html_chart1/
② ①のフォルダに html_line_chart1.py 等の名前でテキストを作成し、下記のサンプルスクリプトを貼りつけて保存してください。
例: C:/user/html_chart1/html_line_chart1.py
③ ①のフォルダにさらに、”chart1″、”html1″ の名前で2つのフォルダを作成してください。
例: C:/user/html_chart1/chart1/、C:/user/html_chart1/html1/
④ ③の “chart1” フォルダの中に、01_nikkei1.txt、02_currency1.txt 等の名前でテキストを作成し、下記のチャートの数値データを貼りつけて保存してください。
例: C:/user/html_chart1/chart1/01_nikkei1.txt, 02_currency1.txt
※ 数値データは単なるサンプルで、日経平均株価や為替(米ドル、ユーロ)をイメージしたものです。
丸めた数値を使っており、正確なデータの提供を意図するものではありませんので、ご理解ください。

使い方

⑤ コマンドプロンプト(または、Anaconda Prompt 等)を起動し、②のスクリプトを実行してください。
例:python C:/user/html_chart1/html_line_chart1.py

→ ③の “html1” フォルダ内に HTML ファイルが生成されたら成功です!

※ Python のスクリプトを実行すると、フォルダ(”chart1″)内のテキストファイル(*.txt)を参照し、テキストファイルごとに折れ線グラフを生成し、拡張子を .html に変え、”html1″ フォルダ内に保存します。

うまく動いたら

・ うまく動いたら、数値データの冒頭の文字列 “nikkei1″、”JPY/USD” や数値などを書き換えて、テキストファイルの内容(変更)が反映されることを確認してみてください。
各行での区切りは、カンマ “,” + 半角スペース ” “ としています。
半角スペースを入れているのは、株価などの金額を扱う際、ダウンロードした/ウェブスクレイピングで取得した数値データの中にカンマ “,” が入りこむことがあり、誤動作の原因となることがあるためです。
そこで、Python でテキストファイルの読み書きをする際は経験的に、区切り文字をカンマ + 半角スペースとすることで、誤動作の原因を未然になくすようにしています。
通常のカンマ区切りに対応させる場合は、get_a1() の関数を修正し、”, ” の部分を “,” (半角スペースなし)に変更してください。また、金額表示などのカンマを外すため、’.replace( “,”, “” )’ としている箇所も必要があれば削除してください。
・ グラフの X軸、Y軸部分での index1、date1 等の文字列は、generate_svg1() 関数で定義しています。グリッドラインの数は x1_grid、y1_grid で定義しています。これらの文字列や数値をいくらか修正してみて、グラフ作成の要領を確認してみてください。
グラフの大きさや背景色などのデザインも同様に修正可能です。
・ また、フォルダ(”chart1″)にテキストファイルを追加して、HTML を生成してください。テキストファイルには、④と同等の要領で日付部分や数値を記載することで、HTML ファイルを生成できます。
・ 下記のサンプルで示したデータ用のファイルについて、冒頭の1行はヘッダー(”nikkei1″、 “JPY/USD”、 “JPY/EUR”)としてグラフで使用します。以降の行は、日付部分+数値、としています。1列めの日付部分は、グラフのX軸の表示で使用します。データファイルの1行目に、X軸の値など、日付以外を入れても動作します。(90度回転させて表示させていますが。。)
また、日付部分(X軸で用いる文字列)と数値の間の区切りは、上で説明したとおり、カンマ(”,”)+半角スペース(” “)としています。
・ インターネットのサイトからダウンロードした CSV 形式などの時系列データを使って、グラフの表示をさせてみてください。
この場合、別途、Python のスクリプトを作って、ダウンロードした CSV ファイルの余計な箇所を削除して、日付や数値をサンプルと同様とした中間フォーマット(*.txt)を作成し、このテキストファイルを HTML や SVG ファイルに変換するようにすると楽です。
・ また、詳細は以下で説明していますが、Python のスクリプト内では、HTML の標準的なテンプレートに折れ線グラフの図形(<svg></svg>タグ)を差し込む程度の処理としています。
HTML がわかる方、興味のある方は、HTML のテンプレートを修正してタイトルを入れるなど、デザインを洗練したものに修正してみてください。

スクリプトの説明

・ 冒頭でスクリプトで使用するライブラリをインポートしています。math は、グラフ描画の際の切り上げのためです。glob は、フォルダ内の全テキストファイルを抽出する際に使用します。
・ read1()、write1() 関数は、テキストファイルの読み書きのために定義しています。
・ get_a1() は、カンマ区切りのファイルを読み取ってリスト(配列)形式で取得するための関数です。通常の CSV ファイルを読み込む等する場合は、この関数を修正してください。
・ get_col1() は、取得したリストから、指定した列を取得する関数です。get_T1() は、取得した配列の行と列を変換する(転置する)関数です。時系列データの場合、各列ごとにデータを取得したいためです。
・ get_min_max1() は、リストの数値から最大値と最小値を取得する関数です。グラフのY方向の描画範囲を決めるために使用します。サンプルスクリプトでは、最小値は 0 としたいため、この関数の中で最小値 y1_min は 0 となるように設定しています。マイナスの範囲も含めて領域内に描画したい等の場合は、この関数を修正してください。
・ svg_polyline1() は、渡されたリストから折れ線の SVG データを生成する関数です。HTML 形式で使用する SVG タグの文字列を生成します。
・ svg_text1() は、HTML の SVG の描画領域で文字列の SVG データを生成するための関数です。
描画する座標 x1, y1 と、文字列の回転角、描画する文字列等を渡すと、SVG のタグを生成します。
・ svg_line1() は、ラインを描画するための関数です。グラフの描画位置と描画範囲、グリッド数を渡すと、ラインに相当する SVG タグの文字列を生成します。
・ color_function1() は、整数値を渡すと、カラーの文字列を生成する関数です。折れ線グラフを生成する際のカラーの割り振りに使います。系列が複数あっても、色分け(レッド、グリーン、ブルー、シアン、マゼンタ、イエローの巡回)できるようにしています。
・ svg_grid_lines1() は、グラフの描画領域で、X軸、Y軸とグリッドを描画するための関数です。
・ svg_profiles1() は、複数の折れ線グラフと、それらに付随する文字列を描画するための関数です。svg_polyline1() と svg_text1() を、描画する折れ線グラフの個数分呼び出して、それぞれ描画します。
・ svg_labels1() は、グラフの欄外の文字列を描くための関数です。X軸、Y軸のラベルを生成します。
・ svg_tags1() は、生成したラインや文字列を SVG のタグ <svg></svg> でくくって、ブラウザで実行できる SVG のタグを生成する関数です。
・ generate_svg1() は、上記の関数を使って、一連のタグを生成する関数です。座標領域やグリッド数等を設定し、グリッドラインを描画し、折れ線グラフのプロファイルを生成し、X軸、Y軸のラベルを生成しています。
・ generate_html1() は、HTMLファイルの文字列を生成する関数です。上記で生成した SVG のタグの文字列を挿し込むことで、一般的な HTML ファイルを生成します。
もし、HTML ファイルのデザインを変えたい場合は、この関数を修正してください。
・ path1 = … とした行以降で、上記の関数を実行して、HTML を書き出しています。
まず、chart1 フォルダを参照して全テキストファイル(*.txt)を取得します。
つぎに、for ループ内で、取得したそれぞれのテキストファイルについて、SVG タグを生成し、HTML のテンプレートに挿し込むことで HTML ファイルを生成しています。
もし、*.html 形式ではなく、*.svg 形式でもファイルを出力したい場合は、for ループ内でコメントアウトしてある部分の # を外し、スクリプトを実行してみてください。SVG のタグ(上記の generate_svg1 関数の出力)を直接出力することで、SVG ファイルを生成することが可能です。
この SVG ファイルを1つの HTML ファイルから読み込むようにすることで、10個の折れ線グラフを1つのメインのページに表示させる、メインのページのグラフを随時自動更新する、などの応用が可能です。

まとめ

折れ線グラフを HTML ファイル形式で出力する Python のスクリプトについてまとめました。

これで、ログなどの数値データについて、ファイル数やデータ数が多くても/可変であっても、一括で折れ線グラフを生成することが可能になりました。データの可視化が実現します。
また、HTML 形式、SVG 形式のいずれの形式でも出力が可能になりました。これにより、たとえば、1つの HTML ファイルから、上記の複数の *.svg ファイルを読み込むようにすることで、複数のグラフを1ページの HTML 内で表示させるなども可能です。

なお、今回のスクリプトは、下記の関連リンクの内容を組み合わせた応用編となっています。
もし、Python のプログラミングには興味があるけれども、スクリプトが長すぎて難しいかなと思う方は、下記の「Python で HTML ファイルを出力する」あたりを動かしてみてください。30行程度のスクリプトで、HTML を生成する事例をまとめています。
興味のあるスクリプトをいくつか動かしてみて、自分の好きなデザインなどに修正していくうちに要領がつかめると思います。

関連リンク
・ Python で HTML ファイルを出力する
・ HTML の棒グラフを出力する 【Python】

・ HTML のカレンダーを生成する 【Python】
・ Python で自由曲線を描く 【HTML & SVG】
・ Python で回路図を描画する 【HTML & SVG】
・ 機械学習で株価予測 【Python】
・ 任意の単語間の相関係数を求めてみる 【Python & Google Trends】

サンプルスクリプト

折れ線グラフ生成スクリプト html_line_chart1.py

import os 
import math as ma1 
import glob as gl1 

def read1( file1 ): 
    str1 = ""
    with open( file1, 'r', encoding='utf-8' ) as f1: 
        str1 = f1.read() 
    return str1 

def write1( file1, str1 ): 
    with open( file1, 'w', encoding='utf-8' ) as f1: 
        f1.write( str1 ) 
    return 0 

def get_a1( file1 ): 
    a1 = read1( file1 ).strip().split( "\n" ) 
    a2 = []
    for i1 in range( len(a1) ): 
        a3 = a1[i1].split( ", " ) 
        a2.append( a3 ) 
    return a2 

def get_cols1( a1, n1 ): 
    a2 = [] 
    for i1 in range( len(a1) ): 
        a2.append( a1[i1][n1] ) 
    return a2 

def get_T1( a1 ): 
    a2 = [] 
    for i1 in range( len(a1[0]) ): 
        a2.append( get_cols1( a1, i1 ) ) 
    return a2 

def get_min_max1( a1 ): 
    v1 = float( a1[0].replace( ",", "" ) ) 
    v1_min = v1 
    v1_max = v1 
    for i1 in range( len(a1)-1 ): 
        v1 = float( a1[i1+1].replace( ",", "" ) ) 
        if v1 > v1_max: 
            v1_max = v1 
        if v1 < v1_min: 
            v1_min = v1 
    return v1_min, v1_max 

def ceil1( v1_max ): 
    if v1_max >= 10: 
        v1 = 2*10**(len(str(v1_max/100.0).split(".")[0])) 
        v1_max = ma1.ceil( v1_max /v1 ) * v1 
    else: 
        v1_max = ma1.ceil( v1_max * 100.0 ) / 100.0 
    return v1_max 

def get_label_min_max1( a1 ): 
    x1_label = a1[0][1:]                                                         # x-axis labels 
    n1 = len( a1[1][1:] ) 
    y1_min, y1_max = get_min_max1( a1[1][1:] ) 
    for i1 in range( len(a1)-2 ): 
        y2_min, y2_max = get_min_max1( a1[i1+2][1:] ) 
        if y2_min < y1_min: 
            y1_min = y2_min 
        if y2_max > y1_max: 
            y1_max = y2_max 
    y1_max = ceil1( y1_max ) 
#   if y1_min < 0: 
#       y1_min = -ceil1( -y1_min ) 
    y1_min = 0.0 
    return x1_label, y1_min, y1_max, n1 

def svg_polyline1( a1, y1_min, y1_max, n1, x1_offset, y1_offset, x1_range, y1_range, color1 ): 
    str1 = "" 
    for i1 in range( n1 ): 
        v1 = float( a1[i1].replace( ",", "" ) )
        x1 = x1_offset + i1/(n1-1) * x1_range 
        y1 = y1_offset + y1_range * ( 1.0 - (v1 - y1_min)/(y1_max - y1_min) ) 
        str1 = str1 + f'{x1:.1f}' + " " + f'{y1:.1f}' + " " 
    str2 = '<polyline points="' + str1 + '" stroke="' + color1 + '" fill="none" />' 
    return str2 

def svg_text1( x1, y1, size1, theta1, str1 ): 
    str2 = '<text x="' + str(x1) + '" y="' + str(y1) + '" font-size="' + str(size1) 
    str2 = str2 + '" font-family="sans-serif" transform="rotate(' + str(theta1) + ', ' + str(x1) + ', ' + str(y1) + ')" xml:space="preserve">' 
    str2 = str2 + str(str1) + '</text>' 
    return str2 

def svg_line1( x1, y1, x2, y2, color1 ): 
    str1 = '<line x1="' + str(x1) + '" y1="' + str(y1) + '" x2="' + str(x2) + '" y2="' + str(y2) + '" stroke="' + color1 + '" stroke-width="1" />' 
    return str1 

def color_function1( n1 ): 
    a1 = ["#aa0000", "#00aa00", "#0000aa", "#00aaaa", "#aa00aa", "#aaaa00"] 
    n2 = int(n1) % len(a1) 
    return a1[n2] 

def svg_grid_lines1( x1_offset, y1_offset, x1_range, y1_range, x1_grid, y1_grid ): 
    str1 = "" 
    color1 = "#f7f7f7" 
    y1 = y1_offset 
    y2 = y1_offset + y1_range 
    for i1 in range( x1_grid ):                                                  # y-axis, y-grid lines 
        x1 = x1_offset + int( x1_range * i1/(x1_grid-1) ) 
        str1 = str1 + svg_line1( x1, y1, x1, y2, color1 ) + "\n" 
    color1 = "#e3e3e3" 
    x1 = x1_offset 
    x2 = x1_offset + x1_range 
    for i1 in range( y1_grid ):                                                  # x-axis, x-grid lines 
        y1 = y1_offset + int( y1_range * ( 1.0 - i1/(y1_grid-1) ) ) 
        str1 = str1 + svg_line1( x1, y1, x2, y1, color1 ) + "\n" 
    return str1 

def svg_profiles1( x1_offset, y1_offset, x1_range, y1_range, y1_min, y1_max, n1, a1 ): 
    str2 = "" 
    for i1 in range( len(a1)-1 ): 
        a2 = a1[i1+1] 
        str2 = str2 + svg_polyline1( a2[1:], y1_min, y1_max, n1, x1_offset, y1_offset, x1_range, y1_range, color_function1(i1) ) + "\n" 
        x1 = x1_offset + x1_range + 15 
        v1 = float( a2[-1].replace( ",", "" ) )
        y1 = y1_offset + int( y1_range * (1.0 - v1/y1_max ) ) 
        str2 = str2 + svg_text1( x1, y1, 11, 0, str( a2[0] ) ) + "\n" 
    return str2 

def svg_labels1( x1_offset, y1_offset, x1_range, y1_range, y1_min, y1_max, x1_grid, y1_grid, x1_label, x1_text, y1_text, n1 ): 
    str1 = "" 
    for i1 in range( y1_grid ): 
        if y1_max > 10: 
            y2_text = str( int( (y1_max-y1_min)*(1.0 - i1/(y1_grid-1)) + y1_min ) ).rjust( 6 )
        else: 
            y2_text = f'{( (y1_max-y1_min)*(1.0 - i1/(y1_grid-1)) + y1_min  ):.3f}'.rjust( 6 )
        x1 = x1_offset - 60 
        y1 = y1_offset + int( y1_range * i1/(y1_grid-1) ) + 5  
        str1 = str1 + svg_text1( x1, y1, 11,   0, y2_text ) + "\n"               # y-text 
    for i1 in range( x1_grid ): 
        i2 = ma1.ceil((n1-1)*i1/(x1_grid-1)) 
        x2_text = x1_label[i2] 
        x1 = x1_offset + int( x1_range * i1/(x1_grid-1) ) + 5 
        y1 = y1_offset + y1_range + 80 
        str1 = str1 + svg_text1( x1, y1, 11, -90, x2_text ) + "\n"               # x-text 
    x1 = x1_offset + int(x1_range/2.0)  
    y1 = y1_offset + y1_range + 110 
    str1 = str1 + svg_text1( x1, y1, 12, 0, x1_text ) + "\n"                     # x-label 
    x1 = x1_offset - 70  
    y1 = y1_offset + int(y1_range/2.0) + 30 
    str1 = str1 + svg_text1( x1, y1, 12, -90, y1_text ) + "\n"                   # x-label 
    return str1 

def generate_svg1( a0 ): 
    x1_text = "date1" 
    y1_text = "index1" 
    w1 = 800                                                                     # width 
    h1 = 500                                                                     # height 
    x1_offset = 100 
    y1_offset =  40 
    x1_range  = 630 
    y1_range  = 330 
    x1_grid   =  10                                                              # number of grid lines 
    y1_grid   =   5 
    a1 = get_T1( a0 )                                                            # transposed matrix 
    x1_label, y1_min, y1_max, n1 = get_label_min_max1( a1 )                      # x_labels, y1 min & max 
    str1 = svg_grid_lines1( x1_offset, y1_offset, x1_range, y1_range, x1_grid, y1_grid ) 
    str2 = svg_profiles1(   x1_offset, y1_offset, x1_range, y1_range, y1_min,  y1_max, n1, a1 ) 
    str3 = svg_labels1(     x1_offset, y1_offset, x1_range, y1_range, y1_min,  y1_max, x1_grid, y1_grid, x1_label, x1_text, y1_text, n1 ) 
    str4 = str1 + str2 + str3                                                    # all objects 
    str5 = svg_tags1( str4, w1, h1 ) 
    return str5 

def svg_tags1( str1, w1, h1 ): 
    str2 = '<svg width="' + str(w1) + '" height="' + str(h1) + '" style="background-color:#ffffff;" xmlns="http://www.w3.org/2000/svg">\n' 
    str3 = '\n</svg>' 
    return str2 + str1.strip() + str3 

def generate_html1( str1 ): 
    str2 = ''' 
<!DOCTYPE html>
<html lang="ja">
<head> 
<meta charset="utf-8"> 
<meta name="viewport" content="width=device-width,initial-scale=1.0"> 
<title>chart 0.1</title> 
</head>
<body style="background-color:#eeeeee">
<br> 
<div id="div1" style="text-align:center;" > 
{0}
</div> 
</body>
</html>

    '''.format( str1 ) 
    return str2 

path1 = os.path.dirname(__file__) + "/" 

pattern1 = path1 + "chart1/*.txt" 
a1 = gl1.glob( pattern1 ) 

for i1 in range( len(a1) ): 
    file1 = a1[i1] 

    a2 = get_a1( file1 ) 
    str1 = generate_svg1( a2 ) 
    str2 = generate_html1( str1 ) 

    file2 = file1.replace( "\\", "/" ).split( "/" )[-1].replace( ".txt", ".html" ) 
    print( file2 ) 
    file3 = path1 + "html1/" + file2 
    write1( file3, str2 ) 

#   file2 = file1.replace( "\\", "/" ).split( "/" )[-1].replace( ".txt", ".svg" ) 
#   print( file2 ) 
#   file3 = path1 + "html1/" + file2 
#   write1( file3, str1 ) 




数値データの例1: 01_nikkei1.txt

date1, nikkei1
2023/06/01, 30886
2023/06/02, 31300
2023/06/05, 31864
2023/06/06, 31988
2023/06/07, 32618
2023/06/08, 31877
2023/06/09, 31927
2023/06/12, 32412
2023/06/13, 32668
2023/06/14, 33331
2023/06/15, 33493
2023/06/16, 33399
2023/06/19, 33768
2023/06/20, 33269
2023/06/21, 33200
2023/06/22, 33438
2023/06/23, 33458
2023/06/26, 32647
2023/06/27, 32629
2023/06/28, 32807
2023/06/29, 33306
2023/06/30, 33068
2023/07/03, 33517
2023/07/04, 33512
2023/07/05, 33165
2023/07/06, 33058
2023/07/07, 32450
2023/07/10, 32393
2023/07/11, 32434
2023/07/12, 32280
2023/07/13, 32106
2023/07/14, 32587
2023/07/18, 32457
2023/07/19, 32812
2023/07/20, 32803
2023/07/21, 32336
2023/07/24, 32648
2023/07/25, 32705
2023/07/26, 32704
2023/07/27, 32523
2023/07/28, 32444
2023/07/31, 33128
2023/08/01, 33292
2023/08/02, 33123
2023/08/03, 32375
2023/08/04, 32019
2023/08/07, 31921
2023/08/08, 32430
2023/08/09, 32346
2023/08/10, 32015
2023/08/14, 32456
2023/08/15, 32372
2023/08/16, 31965
2023/08/17, 31621
2023/08/18, 31321
2023/08/21, 31552
2023/08/22, 31792
2023/08/23, 31717
2023/08/24, 32130
2023/08/25, 31840
2023/08/28, 31915
2023/08/29, 32280
2023/08/30, 32432
2023/08/31, 32361
2023/09/01, 32521
2023/09/04, 32797
2023/09/05, 32941
2023/09/06, 33115
2023/09/07, 33118
2023/09/08, 32916
2023/09/11, 32690
2023/09/12, 32629
2023/09/13, 32742
2023/09/14, 32925
2023/09/15, 33428
2023/09/19, 33296
2023/09/20, 33261
2023/09/21, 32865
2023/09/22, 32189
2023/09/25, 32517
2023/09/26, 32640
2023/09/27, 32023
2023/09/28, 32119
2023/09/29, 32018
2023/10/02, 32101
2023/10/03, 31607
2023/10/04, 30765
2023/10/05, 30733
2023/10/06, 31003
2023/10/10, 31314
2023/10/11, 31847
2023/10/12, 32120
2023/10/13, 32328
2023/10/16, 31983
2023/10/17, 32063
2023/10/18, 32033
2023/10/19, 31579
2023/10/20, 31164
2023/10/23, 31151
2023/10/24, 31157
2023/10/25, 31302
2023/10/26, 30902
2023/10/27, 30713
2023/10/30, 30663
2023/10/31, 30694
2023/11/01, 31311
2023/11/02, 31987
2023/11/06, 32450
2023/11/07, 32551
2023/11/08, 32457
2023/11/09, 32316
2023/11/10, 32491
2023/11/13, 32818
2023/11/14, 32760
2023/11/15, 33112
2023/11/16, 33399
2023/11/17, 33344
2023/11/20, 33559
2023/11/21, 33453
2023/11/22, 33182
2023/11/24, 33752
2023/11/27, 33710
2023/11/28, 33520
2023/11/29, 33244
2023/11/30, 33260
2023/12/01, 33537
2023/12/04, 33318
2023/12/05, 33022
2023/12/06, 32928
2023/12/07, 33165
2023/12/08, 32600
2023/12/11, 32665
2023/12/12, 33107
2023/12/13, 32973
2023/12/14, 33032
2023/12/15, 32760
2023/12/18, 32769
2023/12/19, 32774
2023/12/20, 33467
2023/12/21, 33276
2023/12/22, 33257
2023/12/25, 33414
2023/12/26, 33295
2023/12/27, 33532
2023/12/28, 33477
2023/12/29, 33458
2024/01/04, 33193
2024/01/05, 33397
2024/01/09, 33704
2024/01/10, 33896
2024/01/11, 34871
2024/01/12, 35601
2024/01/15, 35634
2024/01/16, 35909
2024/01/17, 35850
2024/01/18, 35371
2024/01/19, 35913
2024/01/22, 36294
2024/01/23, 36605
2024/01/24, 36415
2024/01/25, 36213
2024/01/26, 36003
2024/01/29, 35814
2024/01/30, 36196
2024/01/31, 35747
2024/02/01, 36008
2024/02/02, 36249
2024/02/05, 36419
2024/02/06, 36249
2024/02/07, 36002
2024/02/08, 36258
2024/02/09, 36915
2024/02/13, 37248
2024/02/14, 37712
2024/02/15, 38017
2024/02/16, 38517
2024/02/19, 38473
2024/02/20, 38510
2024/02/21, 38191
2024/02/22, 38508
2024/02/26, 39320
2024/02/27, 39260
2024/02/28, 39189
2024/02/29, 38935
2024/03/01, 39254
2024/03/04, 40201
2024/03/05, 39881
2024/03/06, 39792
2024/03/07, 40331
2024/03/08, 39809
2024/03/11, 39232
2024/03/12, 38470
2024/03/13, 39059
2024/03/14, 38591
2024/03/15, 38548
2024/03/18, 38960
2024/03/19, 39622
2024/03/21, 40511
2024/03/22, 40942
2024/03/25, 40798
2024/03/26, 40345
2024/03/27, 40517
2024/03/28, 40324
2024/03/29, 40277
2024/04/01, 40646
2024/04/02, 39892
2024/04/03, 39503
2024/04/04, 39928
2024/04/05, 39237
2024/04/08, 39391
2024/04/09, 39496
2024/04/10, 39582
2024/04/11, 39090
2024/04/12, 39722
2024/04/15, 39056
2024/04/16, 38750
2024/04/17, 38587
2024/04/18, 37745
2024/04/19, 37724
2024/04/22, 37240
2024/04/23, 37797
2024/04/24, 37871
2024/04/25, 38065
2024/04/26, 37725
2024/04/30, 38312
2024/05/01, 38107
2024/05/02, 38004
2024/05/07, 38636
2024/05/08, 38677
2024/05/09, 38242
2024/05/10, 38361
2024/05/13, 38211
2024/05/14, 38287
2024/05/15, 38533
2024/05/16, 38645
2024/05/17, 38561
2024/05/20, 38761
2024/05/21, 39232
2024/05/22, 38823
2024/05/23, 38803
2024/05/24, 38506
2024/05/31, 38173
2024/06/03, 38734
2024/06/04, 38702
2024/06/05, 38654
2024/06/06, 38841
2024/06/07, 38597
2024/06/10, 38689
2024/06/11, 39175
2024/06/12, 38865
2024/06/13, 39182
2024/06/14, 38587
2024/06/17, 38440
2024/06/18, 38433
2024/06/19, 38653
2024/06/20, 38410
2024/06/21, 38608
2024/06/24, 38497
2024/06/25, 38833
2024/06/26, 39364
2024/06/27, 39434
2024/06/28, 39593
2024/07/01, 39839
2024/07/02, 39543
2024/07/03, 40225
2024/07/04, 40747
2024/07/05, 41009
2024/07/08, 40863
2024/07/09, 40953
2024/07/10, 41444
2024/07/11, 42343
2024/07/12, 41668
2024/07/16, 41366
2024/07/17, 41416
2024/07/18, 40521
2024/07/19, 39965

数値データの例2: 02_currency1.txt

date1, JPY/USD, JPY/EUR
2023/06/01, 139, 148
2023/06/02, 138, 149
2023/06/05, 139, 149
2023/06/06, 139, 149
2023/06/07, 139, 149
2023/06/08, 140, 149
2023/06/09, 139, 150
2023/06/12, 139, 149
2023/06/13, 139, 150
2023/06/14, 140, 151
2023/06/15, 140, 151
2023/06/16, 140, 153
2023/06/19, 141, 155
2023/06/20, 141, 155
2023/06/21, 141, 154
2023/06/22, 141, 155
2023/06/23, 143, 156
2023/06/26, 143, 156
2023/06/27, 143, 156
2023/06/28, 144, 157
2023/06/29, 144, 157
2023/06/30, 144, 157
2023/07/03, 144, 157
2023/07/04, 144, 157
2023/07/05, 144, 157
2023/07/06, 144, 156
2023/07/07, 144, 156
2023/07/10, 142, 155
2023/07/11, 141, 155
2023/07/12, 140, 154
2023/07/13, 138, 154
2023/07/14, 138, 154
2023/07/17, 138, 155
2023/07/18, 138, 155
2023/07/19, 138, 155
2023/07/20, 139, 156
2023/07/21, 140, 155
2023/07/24, 141, 157
2023/07/25, 141, 156
2023/07/26, 140, 155
2023/07/27, 140, 155
2023/07/28, 139, 153
2023/07/31, 140, 155
2023/08/01, 142, 156
2023/08/02, 143, 157
2023/08/03, 143, 156
2023/08/04, 142, 156
2023/08/07, 141, 156
2023/08/08, 142, 156
2023/08/09, 143, 157
2023/08/10, 143, 157
2023/08/11, 144, 158
2023/08/14, 144, 158
2023/08/15, 145, 158
2023/08/16, 145, 158
2023/08/17, 146, 159
2023/08/18, 145, 158
2023/08/21, 145, 158
2023/08/22, 146, 159
2023/08/23, 145, 158
2023/08/24, 144, 157
2023/08/25, 145, 157
2023/08/28, 146, 158
2023/08/29, 146, 158
2023/08/30, 145, 158
2023/08/31, 146, 159
2023/09/01, 145, 157
2023/09/04, 146, 157
2023/09/05, 146, 158
2023/09/06, 147, 158
2023/09/07, 147, 158
2023/09/08, 147, 157
2023/09/11, 147, 158
2023/09/12, 146, 157
2023/09/13, 147, 158
2023/09/14, 147, 158
2023/09/15, 147, 156
2023/09/18, 147, 157
2023/09/19, 147, 157
2023/09/20, 147, 157
2023/09/21, 148, 158
2023/09/22, 147, 157
2023/09/25, 148, 158
2023/09/26, 148, 157
2023/09/27, 149, 157
2023/09/28, 149, 157
2023/09/29, 149, 157
2023/10/02, 149, 157
2023/10/03, 149, 156
2023/10/04, 149, 155
2023/10/05, 149, 156
2023/10/06, 148, 156
2023/10/09, 149, 157
2023/10/10, 148, 156
2023/10/11, 148, 157
2023/10/12, 149, 158
2023/10/13, 149, 157
2023/10/16, 149, 157
2023/10/17, 149, 157
2023/10/18, 149, 158
2023/10/19, 149, 157
2023/10/20, 149, 158
2023/10/23, 149, 158
2023/10/24, 149, 159
2023/10/25, 149, 158
2023/10/26, 150, 158
2023/10/27, 150, 158
2023/10/30, 149, 157
2023/10/31, 149, 158
2023/11/01, 151, 160
2023/11/02, 150, 159
2023/11/03, 150, 159
2023/11/06, 149, 160
2023/11/07, 150, 160
2023/11/08, 150, 160
2023/11/09, 150, 161
2023/11/10, 151, 161
2023/11/13, 151, 161
2023/11/14, 151, 162
2023/11/15, 150, 163
2023/11/16, 151, 164
2023/11/17, 150, 163
2023/11/20, 149, 163
2023/11/21, 148, 162
2023/11/22, 148, 161
2023/11/23, 149, 162
2023/11/24, 149, 163
2023/11/27, 149, 163
2023/11/28, 148, 162
2023/11/29, 147, 162
2023/11/30, 147, 161
2023/12/01, 148, 161
2023/12/04, 146, 159
2023/12/05, 147, 159
2023/12/06, 147, 158
2023/12/07, 147, 158
2023/12/08, 144, 155
2023/12/11, 144, 155
2023/12/12, 146, 157
2023/12/13, 145, 156
2023/12/14, 142, 155
2023/12/15, 141, 155
2023/12/18, 142, 154
2023/12/19, 142, 155
2023/12/20, 143, 157
2023/12/21, 143, 157
2023/12/22, 142, 156
2023/12/25, 142, 156
2023/12/26, 142, 156
2023/12/27, 142, 157
2023/12/28, 141, 157
2023/12/29, 141, 156
2024/01/01, 140, 155
2024/01/02, 140, 155
2024/01/03, 141, 155
2024/01/04, 143, 156
2024/01/05, 144, 158
2024/01/08, 144, 158
2024/01/09, 144, 157
2024/01/10, 144, 157
2024/01/11, 145, 159
2024/01/12, 145, 159
2024/01/15, 144, 158
2024/01/16, 145, 159
2024/01/17, 147, 160
2024/01/18, 148, 161
2024/01/19, 148, 161
2024/01/22, 148, 161
2024/01/23, 148, 161
2024/01/24, 148, 160
2024/01/25, 147, 160
2024/01/26, 147, 160
2024/01/29, 148, 160
2024/01/30, 147, 159
2024/01/31, 147, 160
2024/02/01, 146, 158
2024/02/02, 146, 159
2024/02/05, 148, 159
2024/02/06, 148, 159
2024/02/07, 147, 159
2024/02/08, 148, 159
2024/02/09, 149, 160
2024/02/12, 149, 160
2024/02/13, 149, 160
2024/02/14, 150, 161
2024/02/15, 150, 161
2024/02/16, 149, 161
2024/02/19, 150, 161
2024/02/20, 150, 161
2024/02/21, 150, 162
2024/02/22, 150, 162
2024/02/23, 150, 162
2024/02/26, 150, 162
2024/02/27, 150, 163
2024/02/28, 150, 163
2024/02/29, 150, 163
2024/03/01, 149, 162
2024/03/04, 150, 162
2024/03/05, 150, 163
2024/03/06, 150, 162
2024/03/07, 149, 162
2024/03/08, 148, 162
2024/03/11, 147, 160
2024/03/12, 146, 160
2024/03/13, 147, 161
2024/03/14, 147, 161
2024/03/15, 148, 161
2024/03/18, 149, 162
2024/03/19, 149, 162
2024/03/20, 150, 163
2024/03/21, 151, 165
2024/03/22, 151, 164
2024/03/25, 151, 163
2024/03/26, 151, 164
2024/03/27, 151, 164
2024/03/28, 151, 163
2024/03/29, 151, 163
2024/04/01, 151, 163
2024/04/02, 151, 162
2024/04/03, 151, 163
2024/04/04, 151, 164
2024/04/05, 151, 163
2024/04/08, 151, 164
2024/04/09, 151, 164
2024/04/10, 151, 164
2024/04/11, 153, 164
2024/04/12, 153, 164
2024/04/15, 153, 162
2024/04/16, 154, 163
2024/04/17, 154, 164
2024/04/18, 154, 164
2024/04/19, 154, 164
2024/04/22, 154, 164
2024/04/23, 154, 164
2024/04/24, 154, 165
2024/04/25, 155, 166
2024/04/26, 155, 167
2024/04/29, 157, 169
2024/04/30, 156, 167
2024/05/01, 157, 168
2024/05/02, 154, 165
2024/05/03, 153, 164
2024/05/06, 152, 164
2024/05/07, 153, 165
2024/05/08, 154, 166
2024/05/09, 155, 167
2024/05/10, 155, 167
2024/05/13, 155, 167
2024/05/14, 156, 168
2024/05/15, 156, 169
2024/05/16, 154, 168
2024/05/17, 155, 168
2024/05/20, 155, 169
2024/05/21, 156, 169
2024/05/22, 156, 169
2024/05/23, 156, 169
2024/05/24, 156, 169
2024/05/31, 156, 169
2024/06/03, 157, 170
2024/06/04, 156, 170
2024/06/05, 154, 168
2024/06/06, 156, 169
2024/06/07, 155, 169
2024/06/10, 156, 169
2024/06/11, 157, 169
2024/06/12, 157, 168
2024/06/13, 156, 169
2024/06/14, 157, 168
2024/06/17, 157, 168
2024/06/18, 157, 169
2024/06/19, 157, 169
2024/06/20, 158, 169
2024/06/21, 158, 170
2024/06/24, 159, 170
2024/06/25, 159, 171
2024/06/26, 159, 171
2024/06/27, 160, 171
2024/06/28, 160, 172
2024/07/01, 160, 172
2024/07/02, 161, 173
2024/07/03, 161, 173
2024/07/04, 161, 174
2024/07/05, 161, 174
2024/07/08, 160, 173
2024/07/09, 160, 174
2024/07/10, 161, 174
2024/07/11, 161, 175
2024/07/12, 158, 172
2024/07/15, 157, 172
2024/07/16, 158, 172
2024/07/17, 158, 172
2024/07/18, 156, 170
2024/07/19, 157, 171
タイトルとURLをコピーしました