見出し画像

Python:CSVファイルからグラフを生成してHTMLファイルに出力する(バージョンアップ版)

以前記事にした「Python:CSVファイルからグラフを生成してHTMLファイルに出力する」が意外と読まれているのでバージョンアップしました。

Pythonにて、以下の処理を行います。

事前準備:CSVファイルを任意のファイル名で作成します。

1.ファイルダイアログからCSVファイルを選択します。
 →以前はCSVファイルの文字コードがUTF-8(BOM無)のみ可能でしたが、
  Shift-JISも読み込めるようにしました。

2.グラフを生成します。
 →以前はソース内でカラム位置を指定していましたが、
  グラフ化出来そうな数値型が含まれている全てのカラムを
  自動で判断してグラフ化するようにしました。
  ※折れ線グラフがおかしい場合は無視してください。

3.ファイルダイアログで出力するHTMLファイル名を入力して、
  HTMLファイルに出力して、起動します。
  →CSVファイルと同じフォルダに「CSVファイル名+日時.html」
   で出力します。


CSVファイルのサンプルです

従業員ID,氏名,年齢,性別,郵便番号,住所,電話番号,メールアドレス,入社日,部署,役職,給与,勤務時間,有給休暇残日数,配偶者,子供人数,車両所有,資格1,資格2,社員ランク
1001,山田太郎,35,男性,100-0001,東京都千代田区大手町1-1-1,03-1234-5678,yamada_taro@example.com,2015-04-01,営業部,課長,5000000,9:00-18:00,10,未婚,0,あり,TOEIC,日商簿記2級,中堅社員
1002,佐藤花子,28,女性,100-0002,東京都千代田区霞が関2-2-2,03-2345-6789,sato_hanako@example.com,2018-07-15,人事部,主任,4000000,10:00-19:00,12,既婚,2,なし,TOEFL,情報処理技術者試験2級,中堅社員
1003,鈴木健太,42,男性,100-0003,東京都千代田区霞が関3-3-3,03-3456-7890,suzuki_kenta@example.com,2009-11-20,経理部,課長,5500000,9:30-18:30,15,既婚,1,なし,簿記1級,英検準1級,管理職
1004,田中真理,30,女性,100-0004,東京都千代田区霞が関4-4-4,03-4567-8901,tanaka_mari@example.com,2017-03-10,マーケティング部,リーダー,4500000,9:00-18:00,8,未婚,0,なし,TOEIC,情報処理技術者試験3級,中堅社員
1005,伊藤美香,38,女性,100-0005,東京都千代田区霞が関5-5-5,03-5678-9012,ito_mika@example.com,2012-08-05,営業部,マネージャー,6000000,9:30-18:30,18,既婚,3,あり,英検1級,情報処理技術者試験1級,管理職
1006,高橋健太郎,45,男性,100-0006,東京都千代田区霞が関6-6-6,03-6789-0123,takahashi_kentarou@example.com,2007-05-15,営業部,部長,7000000,9:00-18:00,20,既婚,2,なし,TOEIC,簿記1級,管理職

Pythonのソースサンプルです。

import pandas as pd
import plotly.express as px
import tkinter as tk
from tkinter import filedialog
import os
import webbrowser
import itertools
import datetime
from tqdm import tqdm

def select_file_dialog():
    root = tk.Tk()
    root.withdraw()
    file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
    if not file_path:
        print("CSVファイルが選択されませんでした。")
    return file_path

def generate_html_filename(csv_file_path):
    base_name = os.path.splitext(os.path.basename(csv_file_path))[0]
    current_time = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
    html_file_name = f"{base_name}_{current_time}.html"
    return html_file_name

def read_csv_with_encoding(file_path):
    try:
        df = pd.read_csv(file_path, encoding='shift-jis')
    except UnicodeDecodeError:
        # Shift-JISで読み込めない場合はUTF-8で再試行
        df = pd.read_csv(file_path, encoding='utf-8')
    return df

def main():
    # CSVファイルの選択
    csv_file_path = select_file_dialog()
    if not csv_file_path:
        return

    # CSVファイルの読み込み
    df = read_csv_with_encoding(csv_file_path)

    if df.empty:
        print("CSVファイルが空です。")
        return

    print(df.info())

    # グラフ生成
    graphs = {
        "折れ線グラフ": px.line,
        "円グラフ": px.pie,
        "棒グラフ": px.bar
    }

    figures = {}
    for column in tqdm(df.columns, desc="グラフ生成中"):
        figures[column] = {}
        for graph_type, graph_func in graphs.items():
            try:
                if graph_type == "折れ線グラフ":
                    fig = graph_func(df, x=df.index, y=column, title=f"{column} - {graph_type}")
                elif graph_type == "円グラフ":
                    fig = graph_func(df, values=column, names=df.index, title=f"{column} - {graph_type}")
                else:
                    fig = graph_func(df, x=df.index, y=column, title=f"{column} - {graph_type}")
                figures[column][graph_type] = fig
            except Exception as e:
                print(f"Error generating graph for {column} - {graph_type}: {e}")
                continue

    # HTMLファイルの保存場所を選択
    html_file_name = generate_html_filename(csv_file_path)
    output_file_path = os.path.join(os.path.dirname(csv_file_path), html_file_name)

    # HTMLファイルにグラフを出力
    with open(output_file_path, 'w', encoding='utf-8') as f:
        f.write(f"<html><head><meta charset='utf-8'></head><body>")
        for column, graph_types in figures.items():
            for graph_type, fig in graph_types.items():
                f.write(f"<h1>{column} - {graph_type}</h1>")
                f.write(fig.to_html(full_html=False, include_plotlyjs='cdn'))
        f.write("</body></html>")

    print(f"グラフが{output_file_path}に保存されました。")

    webbrowser.open(output_file_path)

if __name__ == "__main__":
    main()

サンプルCSVをグラフ化した場合、以下のようになります。(全部は多いので一部抜粋)

この記事が気に入ったらサポートをしてみませんか?