Openpyxlで時刻データを含むcsvファイルからグラフを作成

## はじめに

Openpyxlで時刻データを含むcsvファイルから、X軸を時刻データとした折れ線グラフを作成するスクリプトを下記に示す。

* make_chart.py

```py
#!/usr/bin/python
# -*- coding: utf-8 -*-

"""時刻データを含むcsvファイルから、X軸を時刻データとした折れ線グラフ形式のグラフを挿入したExcelファイルを作成する

Args:
    csv_file_path (str): csvファイルパス
    y_axis_column (int): Y軸に描写する列番号

Examples:

    ::

        $ python make_chart.py file.csv
        $ python make_chart.py file.csv 2 5 7

"""

import os
import sys
import csv
import itertools
from openpyxl import Workbook
from openpyxl.chart import Reference, Series, ScatterChart
from openpyxl.chart.layout import Layout, ManualLayout
from openpyxl.styles import numbers
from datetime import datetime

#-----------------------------------------------------------------------
# 定数定義
#-----------------------------------------------------------------------

DATA_SHEET_NAME = "Data"
CHART_SHEET_NAME = "Graph"
CHART_TITLE = "Resources Graph"
Y_AXIS_TITLE = "Resource Value"
X_AXIS_TITLE = "Time"
LEGEND_POSITION = "r"
RANGE_TO_ADD_CHART = "B3"
EXTENTION_OF_FILE = ".xlsx"
BEGIN_DATA_ROW = 1
X_AXIS_COLUMN = 1
CHART_HEIGHT = 15
CHART_WHIDTH = 30
Y_AXIS_MIN = 0
Y_AXIS_MAX = 100

def convert_type(datas):
    """データの型をデータの値に応じて変換

    Args:
        datas (list): 変換対象のデータ

    Returns:
        list: 変換後データ
    """
    convert_datas = []

    for data in datas:
        try:
            # 数値データはfloatに変換
            convert_datas.append(float(data))

        except ValueError:

            try:
                # 日付データはdatetimeに変換
                data_timestamp = datetime.strptime(data, "%Y/%m/%d %H:%M:%S")
                convert_datas.append(data_timestamp)

            except ValueError:
                convert_datas.append(data)
                pass

    return convert_datas

def main():
    """メイン関数

    """

    # コマンドライン引数取得
    args = sys.argv
    csv_file_path = args[1]
    y_axis_columns = []
    x_axis_column = X_AXIS_COLUMN

    for count in range(2, len(args)):
        y_axis_columns.append(args[count])

    # 出力先ファイルパスの設定
    current_time = datetime.now()
    timestamp = current_time.strftime("%Y%m%d-%H%M%S")
    split_csv_file_name = os.path.splitext(csv_file_path)
    output_file_path = split_csv_file_name[0] + "_" + timestamp + EXTENTION_OF_FILE

    # ワークブック、ワークシートオブジェクトを作成
    work_book = Workbook()
    data_sheet = work_book.active
    data_sheet.title = DATA_SHEET_NAME
    chart_sheet = work_book.create_sheet(title=CHART_SHEET_NAME)
    work_book.active = chart_sheet

    # csvファイルの読み込み
    convert_datas = []
    with open(csv_file_path) as csv_file:
        csv_reader = csv.reader(csv_file, delimiter=',', quotechar='"')

        for line in csv_reader:
            convert_datas = convert_type(line)
            data_sheet.append(convert_datas)

        csv_columns = len(line)

        # CSVファイルの列数分、列番号をリストに追加
        if y_axis_columns == []:
            y_axis_columns = range(x_axis_column + 1, csv_columns + 1)

    # グラフの書式設定
    chart = ScatterChart()
    chart.title = CHART_TITLE
    chart.y_axis.title = Y_AXIS_TITLE
    chart.x_axis.title = X_AXIS_TITLE
    chart.y_axis.scaling.min = Y_AXIS_MIN
    chart.y_axis.scaling.max = Y_AXIS_MAX
    chart.legend.position = LEGEND_POSITION
    chart.height = CHART_HEIGHT
    chart.width = CHART_WHIDTH

    # X軸の参照先の設定
    line_number = csv_reader.line_num
    x_axis_values = Reference(data_sheet, min_col=x_axis_column, min_row=BEGIN_DATA_ROW + 1, max_row=line_number)

    # Y軸の参照先の設定
    for y_axis_column in y_axis_columns:
        y_axis_values = Reference(data_sheet, min_col=y_axis_column, min_row=BEGIN_DATA_ROW, max_row=line_number)
        series = Series(y_axis_values, x_axis_values, title_from_data=True)
        chart.series.append(series)

    # グラフの挿入
    chart_sheet.add_chart(chart, RANGE_TO_ADD_CHART)
    work_book.save(output_file_path)

    print("Result file is [%s]" % output_file_path)

if __name__ == '__main__':
    main()
```

---

## 実行例

### サンプルデータ

サンプルとして使用するCSVファイルを下記に示す。

![図3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441666/7f86f77b-2d90-ed42-9fe7-5957d3e4231e.png)

### 実行結果

#### 全ての列をプロット

```bash
$ python make_chart.py file.csv
```

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441666/a3a28835-0434-de87-55be-91f8ac475a00.png)

#### プロットする列番号を指定

```bash
$ python make_chart.py file.csv 3 5 7
```

![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441666/941eae17-d7ea-52be-9911-ff94c6afb3a1.png)