Pythonでグラフ表示 matplotlib 〜グラフタイトルをCSVファイル名にする方法〜

スポンサーリンク

グラフタイトルをCSVファイル名にする方法

2020年2月11日、下の記事にjunneyさんより質問を頂きました。

Pythonでグラフ表示 matplotlib 〜タイトル、軸名、凡例の表示〜
タイトルを表示する前回、matplotlibを使って、グラフを表示する方法を解説しました。グラフは表示できたのですが、何とも味気ないグラフになっていましたよね。やはりグラフを表示したら、タイトルやX軸、Y軸...

せっかくなので記事にしつつ、質問にお答えしようと思います。

とりあえず質問はこちら。

はじめまして。

python超初心者で、現在たくさんのCSVファイルをグラフにする作業をしています。

で、色々調べていたらこちらのサイトにたどり着いたのですが、とってもわかりやすいです。

それで教えていただけたらと思うのですが、グラフのタイトルにCSVのファイル名を付けたいのですがどのようにすればよろしいでしょうか?

https://3pysci.com/python-matplotlib-2/

やり方は色々ありますし、グラフにするまでどうやってデータを読み込んでいくかによって変わっていくと思いますが、とりあえず私がよくやる方法を解説していきたいと思います。

「たくさんのCSVファイルをグラフにする」ということなので、とりあえず4つのCSVファイルを準備しました。

ファイルはこちらに置いておくので、練習用にどうぞ。

それぞれのファイルの中身はこうなっています。

・test1.csf

1,2
2,4
3,6
4,8
5,10
6,12
7,14
8,16
9,18
10,20

・test2.csv

1,2
2,4
3,8
4,16
5,32
6,64
7,128
8,256
9,512
10,1024

・test3.csv

1,1
2,3
3,5
4,7
5,9
6,11
7,13
8,15
9,17
10,19

・test4.csv

1,2
2,3
3,5
4,7
5,11
6,13
7,17
8,19
9,23
10,29

それぞれの行の一つ目の数字がXの値、二つ目の数字がYの値としています。

これを読み込んで、それぞれグラフを表示し、そのグラフタイトルにそれぞれのファイル名をつけるということをしてみましょう。

ちなみに複数のグラフを一括表示するという手法もありますが、もう解説記事を作ってストックしてあるので、今回はそちらには触れません。

申し訳ありませんが、記事がアップされるまで今しばらくお待ちくださいませ。

スポンサーリンク

ファイル名の取得

まずは今回のプログラムのファイル構成から。

新しいPythonのプログラムを先ほどのCSVファイルと同じフォルダ内に作成します。

ファイル構成ができたら、次に使用するライブラリをインポートしましょう。

今回使うのは「csv」と「os」、そして「matplotlibのpyplot」の3種類。

ということでこんな感じです。

import csv
import os
from matplotlib import pyplot as plt

今後のことを考え、ファイル拡張子、ファイルパスを簡単に変更できるよう、最初に変数に代入します。

import csv
import os
from matplotlib import pyplot as plt

file_ext = ".csv"
default_path = os.getcwd()

こうしておけば、「.txt」ファイルを読み込みたいと思ったら、「file_ext = “.txt”」とすれば、プログラム本体を変更せずに読み込めます。

またファイルの場所を設定したければ、「default_path = X」のXにパスを入れればパス設定ができます。

現状では同じフォルダ内ということで「os.getcwd()」で現在のフォルダのパスを取得しています。

(注:もちろんこの後の細かいところの調整は必要です)

ちなみに「os.getcwd()」を解説している記事はこちら。

Pythonのosモジュールによるフォルダ間移動とファイル名取得 〜絶対パスと相対パスの違いを添えて〜
フォルダ間移動前にcsvファイルの書き込みに関して説明しました。その際はプログラムと読み込むファイルは同じフォルダにある必要があり、また新規作成されるファイルは同じフォルダに作成されました。しかしプログラムとファイ...

次にファイル名の取得を行います。

その部分はこんな感じ。

files = []

for file in os.listdir(default_path):
    if file[-4:] == file_ext:
        files.append(file)

まず「files = []」で取得したファイル名を保管する空のリストを作ります。

そして「for file in os.listdir(default_path)」でdefault_path内にあるファイル名を一つずつ取得し、変数fileに代入します。

「if file[-4:] == file_ext:」でファイル名の末尾4文字が「file_ext」に、つまり今回の場合「.csv」と同じであれば、「files.append(file)」でfilesというリストにファイル名を保管していきます。

あとは最後に「print(files)」を追加しておけば、確認用に取得したファイル名を表示することができます。

ということでここまではこんな感じ。

import csv
import os
from matplotlib import pyplot as plt

file_ext = ".csv"
default_path = os.getcwd()

files = []

for file in os.listdir(default_path):
    if file[-4:] == file_ext:
        files.append(file)
        
print(files)

実行結果
['test4.csv', 'test2.csv', 'test3.csv', 'test1.csv']

ファイルの順番がおかしくなっていますが、最終的にファイル名の順番とグラフの順番は合うので、今回はこのまま進めていきます。

スポンサーリンク

データの格納

次に取得したファイル名から、それぞれのファイルを開き、データを読み込み、とりあえずリストに格納します。

まずは取得したデータを格納する空のリストを作ります。

dataset_x = []; dataset_y = []

次にファイル名を格納したリストから、再度ファイル名を一つ一つ取得し、CSVファイルとして読み込みます。

for file in files:
    f = open(default_path + "//" + file, "r")
    reader = csv.reader(f)

ちなみにCSVファイルの作成&読み書きの記事はこちらです。

Pythonでcsv、tsvの扱い方 〜ファイルの作成&読み書き〜
csv、tsvとは?csv、tsvとはファイル形式のことで、それぞれComma-Separated Values、Tab-Separated Valueの略になります。日本語でいうと、カンマで分けた値とタブで分けた値といっ...

次にx値、y値を格納する空のリストを作成します。

    x = []; y = []

一行ずつ読み込み、x、yのリストに入れていきます。

    for row in reader:
        x.append(int(row[0]))
        y.append(int(row[1]))
        
    dataset_x.append(x)
    dataset_y.append(y)

一つのファイルが読み終わったら、最初に作ったdataset_x、dataset_yのリストにx、yのリストを格納することで、ファイル毎に分かれたリストとして格納できます。

ここでも最後にdataset_x、dataset_yを表示させ、どう格納されているか確認しておきましょう。

ファイルの読み込みまでをまとめるとこんな感じ。

import csv
import os
from matplotlib import pyplot as plt

file_ext = ".csv"
default_path = os.getcwd()

files = []

for file in os.listdir(default_path):
    if file[-4:] == file_ext:
        files.append(file)
        
print(files)

dataset_x = []; dataset_y = []
        
for file in files:
    f = open(default_path + "//" + file, "r")
    reader = csv.reader(f)
    
    x = []; y = []
    
    for row in reader:
        x.append(int(row[0]))
        y.append(int(row[1]))
        
    dataset_x.append(x)
    dataset_y.append(y)
    
print(dataset_x)
print(dataset_y)

実行結果
['test4.csv', 'test2.csv', 'test3.csv', 'test1.csv']
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
[[2, 3, 5, 7, 11, 13, 17, 19, 23, 29], [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024], [1, 3, 5, 7, 9, 11, 13, 15, 17, 19], [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]]

x値は1から10までが4回、y値はそれぞれのファイルから得られた10個の数字がまとまって格納されています。

スポンサーリンク

データのプロット

おまちかね、データのプロットを行なっていきます。

今回は一つ一つ分かれた4つのグラフを表示していきます。

グラフの表示の仕方によって、コマンドの記述の順番が異なるので、注意してください。

今回の場合はこう記述します。

for data_x, data_y, name in zip(dataset_x, dataset_y, files):
    fig = plt.figure()
    plt.clf()
    
    plt.plot(data_x, data_y)
    
    plt.title(name)
    
    plt.show()

「for data_x, data_y, name in zip(dataset_x, dataset_y, files):」でそれぞれのファイル毎のx、yのデータ、そしてファイル名を一つずつ取得していきます。

次に「fig = plt.figure()」と「plt.clf()」でグラフを表示する準備をします。

そして一つずつ取得したx、yのリストを「plt.plot(data_x, data_y)」でプロットします。

「plt.title(name)」とすることでタイトルにファイル名を表示します。

ちなみに「name[:-4]」とすることで拡張子を省いたファイル名にもできます。

最後に「plt.show()」でグラフを表示するというわけです。

全体をまとめてみるとこんな感じです。

import csv
import os
from matplotlib import pyplot as plt

file_ext = ".csv"
default_path = os.getcwd()

files = []

for file in os.listdir(default_path):
    if file[-4:] == file_ext:
        files.append(file)
        
print(files)

dataset_x = []; dataset_y = []
        
for file in files:
    f = open(default_path + "//" + file, "r")
    reader = csv.reader(f)
    
    x = []; y = []
    
    for row in reader:
        x.append(int(row[0]))
        y.append(int(row[1]))
        
    dataset_x.append(x)
    dataset_y.append(y)
    
print(dataset_x)
print(dataset_y)

for data_x, data_y, name in zip(dataset_x, dataset_y, files):
    fig = plt.figure()
    plt.clf()
    
    plt.plot(data_x, data_y)
    
    plt.title(name)
    
    plt.show()

実行結果
['test4.csv', 'test2.csv', 'test3.csv', 'test1.csv']
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
[[2, 3, 5, 7, 11, 13, 17, 19, 23, 29], [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024], [1, 3, 5, 7, 9, 11, 13, 15, 17, 19], [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]]

こんなもんでいかがでしょうか?

あと文字のサイズや軸名、線の太さなんかは他の記事をご覧くださいませ。

Pythonでグラフ表示 matplotlib 〜タイトル、軸名、凡例の表示〜
タイトルを表示する前回、matplotlibを使って、グラフを表示する方法を解説しました。グラフは表示できたのですが、何とも味気ないグラフになっていましたよね。やはりグラフを表示したら、タイトルやX軸、Y軸...
Pythonでグラフ表示 matplotlib 〜線の太さ、色、点線〜
線の太さを変更する前回、折れ線グラフの全体の見栄えを調整する方法を解説しました。今度は線自体を色々変更して、見やすいグラフにしてみましょう。まずは前回のおさらいです。%matplotlib note...
スポンサーリンク

おまけ〜自動で保存〜

表示されたグラフを一つ一つ保存するのはめんどうなので、自動で保存するようにしましょう。

自動で保存するには下の文を「plt.show()」の前の行に入れます。

    plt.savefig(name[:-4] + ".png")

「plt.savefig」がグラフの保存コマンド、「name[:-4]」はファイル名の拡張子を省いた部分を表し、「”.png”」で画像用の拡張子を追加します。

と言うことでプログラム全体としてはこんな感じ。

import csv
import os
from matplotlib import pyplot as plt

file_ext = ".csv"
default_path = os.getcwd()

files = []

for file in os.listdir(default_path):
    if file[-4:] == file_ext:
        files.append(file)
        
print(files)

dataset_x = []; dataset_y = []
        
for file in files:
    f = open(default_path + "//" + file, "r")
    reader = csv.reader(f)
    
    x = []; y = []
    
    for row in reader:
        x.append(int(row[0]))
        y.append(int(row[1]))
        
    dataset_x.append(x)
    dataset_y.append(y)
    
print(dataset_x)
print(dataset_y)

for data_x, data_y, name in zip(dataset_x, dataset_y, files):
    fig = plt.figure()
    plt.clf()
    
    plt.plot(data_x, data_y)
    
    plt.title(name)
    
    plt.savefig(name[:-4] + ".png")
    
    plt.show()

実行結果は省きます。

ということでjunneyさん、こんなもんでいかがでしょうか?

実際にはさらにデータの加工をしやすいように工夫はしていますが、大枠としては普段使っているプログラムに似通った形で紹介してみました。

プロならもっとスマートにプログラムを組むのかもしれませんが、いかに今後の手間を省き、後で読んでも分かる状況になっているかと思います。

この後もう少しjunneyさんから質問が届きましたので、さらに解説をしてみたいと思います。

Pythonでファイル数、行数、列数を指定してダミーデータのファイルを生成するプログラムを作ってみた
ランダムデータのファイルが欲しい!前にjunney様より「グラフタイトルをファイル名としたい」というご質問を頂き、答えてみました。ただどうやら他にもプログラムが動いていない部分があるようで、再度ご質問を頂きました。...

ということで今回はこんな感じで。

コメント

  1. アバター junney より:

    nori さま

    先程書き込んだのですが、うまくいかなかったので二重になっていたらごめんなさい。
    早速めちゃくちゃわかりやすい、こまやかな説明を本当にありがとうございます。
    すごい助かります。(;_;)
    今、6列4000行のcsvファイルをファイル毎にグラフ化しています。
    pandasを使っているのですが、途中データの格納のあたりがわかってなく、
    結果はグラフが1個しかできずで、、、
    お言葉に甘えて、またまた教えていただきたく、ここに自分がコーディングしたものを書き込もうかと思ったりもしたのですが、オープンになるのでどうなのかなと思っているところです。

  2. Nori Nori より:

    junny様

    いえいえ、お役に立てていたら幸いです。

    さて6列4000行のファイル(しかも複数?)となると確かに手作業ではかなり厳しいですね(^^;)
    そしてプログラミングが力を発揮する絶好の機会だと思います。

    私自身はPandasはあまり使っていないのですが、多少触ったことはあるので、私の勉強がてらでよければ色々試してみます。

    (また内容は記事にさせていただきますが…)

    ただあるデータの解析プログラムとかだと、確かにそのままオープンの場で出してしまうのは良くないでしょう。

    ダミーで全然いいのでファイルの内容(最初の行はヘッダーとか最初の列がデータ番号、つまりこの記事でいうtest1.csvの中身)とか、どういうグラフ(散布図とか棒グラフ)で表示したいのかを教えてもらうことは可能ですか?

    もしそれも厳しいとのことでしたら、ちょっと他の方法を考えてみます。

    ちなみにグラフが1個しかできない場合、私がよく間違えるのはforのインテンドの位置だったりします。

    ではではよろしくお願いします。

  3. アバター junney より:

    こんばんは。
    心強いコメントを早速ありがとうございます。
    もちろん記事にしてください。(^^

    少し載せてみます。
    フォルダから1個ずつ取り出してそれぞれグラフにするのですが、
    途中が変なので、省いてしまいました。
    固有名詞は適当に置き換えています。
    CSVの中身は9行目まで省き、1列目を密度、2~7列の6列がデーター系列
    (仮にA,B,C,D,E,F)としています。
    折れ線です。
    こんな感じです。
    訳わからない内容かもしれませんね。
    すみません。
    よろしくお願いします。

    import os
    import pandas as pd
    import matplotlib.pyplot as plt
    %matplotlib inline

    file_ext = “.csv”
    default_path = os.chdir(“C:/Users/user/Anaconda3/asia/japan”)

    files = []

    for file in os.listdir(default_path):
    if file[-4:] == file_ext:
    files.append(file)

    print(files)

    for file in files:
    df = pd.read_csv(file,
    names=[”,’A’,’B’,’C’,’D’,’E’,’F’],
    index_col=[0],
    skiprows = 9
    )

    ax = df.plot()
    basename_without_ext = os.path.splitext(os.path.basename(file))[0]
    ax.set_title(basename_without_ext)
    ax.set_xlabel(‘location (mm)’, fontsize=10)
    ax.set_ylabel(‘magnetic flux density (μT)’,fontsize=10)
    plt.style.use(‘ggplot’)
    plt.savefig(file[:-4]+’.png’)
    plt.show()

  4. アバター junney より:

    貼り付けたら、インデントがごちゃごちゃになってました。
    重ね重ねすみません。

  5. Nori Nori より:

    junneyさん、こんばんは!

    プログラムありがとうございます。
    実は大体こんな感じかなぁと思って、記事書いちゃいました(^^;
    で、明日ダミーのファイルを作るプログラムの作成方法の記事、水曜日にそこからPandasを使ってグラフを書く方法の記事がアップされます。

    まぁそれはまた見ていただくとして、ぱっと見で私の書いたプログラムのグラフ表示の部分で違うところを挙げてみます。

    補足部分は下に書いてあるので参照してください。

    for f in filename:
    ____df = pd.read_csv(f, index_col = 0) #補足1

    ____df.plot() #補足2
    ____plt.title(f) #補足3

    ____plt.savefig(f[:-4] + “.png”)

    #補足1
    この部分はデータの読み込みなので、違っててもOKです。
    # 補足2
    ax = df.plot()ではなく、df.plot()とした方が後が楽です。
    #補足3
    df.plot()とした場合は、この後はpltのコマンドが使えます(plt.xticksとかplt.xlabelとか)

    df.plot()だけでグラフが表示されるので、もしスタイルを変更するためのplt.style.use(“ggplot”)を入れるなら、df.plot()の前に入れる必要があるようです。
    そしてplt.show()はいらないようです。

    また重要な点としてfor以降は全て一段インテンドされている状態です(インテンドが表現できないようなので____で置き換えています)。
    これで私の環境ではそれぞれのファイルのグラフが表示され、保存されます。

    あとご確認いただきたいことが、default_path =os.chdir(“C:/Users/user/Anaconda3/asia/japan”)とされているので、グラフが“C:/Users/user/Anaconda3/asia/japan”に保存されていないかということです。

    こちらの状況で確認したところ、
    default_path =os.chdir(“C:/Users/user/Anaconda3/asia/japan”)
    でos.chdir(“path”) が実行され、現在いるフォルダが変更されてしまうようです。

    とりあえず気になるところは挙げてみました。

    junneyさんのプログラムが上手く動くよう祈っています!

    • Nori Nori より:

      今、編集ページで見てみたら、そちらではインテンドがどこでされているか確認できました。
      インテンドを____に置き換えるとこうなっていました。

      for file in files:
      ____df = pd.read_csv(file, names=[”,’A’,’B’,’C’,’D’,’E’,’F’], index_col=[0], skiprows = 9)

      ax = df.plot()
      basename_without_ext = os.path.splitext(os.path.basename(file))[0]
      ax.set_title(basename_without_ext)
      ax.set_xlabel(‘location (mm)’, fontsize=10)
      ax.set_ylabel(‘magnetic flux density (μT)’,fontsize=10)
      plt.style.use(‘ggplot’)
      plt.savefig(file[:-4]+’.png’)
      plt.show()

      でもこの状態だとax = df.plot()からplt.show()まではforのループから抜けた後に実行される、つまり一番最後のファイルのみに適応されるため、グラフの表示・保存は一番最後のファイルしかされません。

      ということで、全てのファイルを表示・保存するのであれば、ax = df.plot()からplt.show()までもインテンドを一段下げてみてください。

      つまりこうなります。

      for file in files:
      ____df = pd.read_csv(file, names=[”,’A’,’B’,’C’,’D’,’E’,’F’], index_col=[0], skiprows = 9)

      ____ax = df.plot()
      ____basename_without_ext = os.path.splitext(os.path.basename(file))[0]
      ____ax.set_title(basename_without_ext)
      ____ax.set_xlabel(‘location (mm)’, fontsize=10)
      ____ax.set_ylabel(‘magnetic flux density (μT)’,fontsize=10)
      ____plt.style.use(‘ggplot’)
      ____plt.savefig(file[:-4]+’.png’)
      ____plt.show()

      これで一度試して頂けますでしょうか?
      よろしくお願いいたしますm(_ _)m

  6. アバター junney より:

    Noriさま

    こんにちは
    またまた早速回答していただき、びっくりありがたいです。
    すぐに参考にさせていただいたのですが、お返事が遅くなり申し訳ありません。

    インデントの修正さえしたら、pngファイルの保存まで一応問題なくいきました。
    コメントをすでにいただいていたのに、、、
    でも、Noriさんがその他こまごまアドバイスや説明していただいたのがすごく参考になりました。
    pathに関しても、いろんなところにデータを保管していて、めんどくさい事になってたので
    整理して、色々と解決してすっきりしたーって感じです。
    本当にありがとうございました。
    pandasの記事も見させていただきましたが、めちゃくちゃわかりやすいです。
    先にこれを見ていれば、、、

    後はpath指定のところをGUIにすれば使いやすいかなーと思ってまたまた奮闘しています。

    また相談しにくるかもしれないので、その時はよろしくお願いいたします。

    あっ、3Dプリンターを3、4年前?ぐらいに使ったことがあり、なんかトレイの上にスティックのりを塗ったら、それがあまくてうまくフィラメントが積層せず、後でのぞきに行ったら、素麺が盛り上がったみたいになっててすごいことになっていたのを思い出しました。
    ぷぷっ。
    今はそんな事しないんでしょうね、、、

  7. Nori Nori より:

    junneyさん、こんにちは。

    上手くいったようで良かったです!
    プログラミングは自分では気づかないかけど、他の人がみるとすぐに気づくなんてことは多々あるので、お気になさらずに。

    というよりも、今回のことは本当に私がよくやるミスなので、多分インテンドだろうなぁと気づいたというのが大きいです。

    また何かあれば、お気軽にご連絡下さい!

    ちなみに3Dプリンタは今でもスティックノリ塗りますよ。
    そして塗り方があまくて剥がれることもしばしば(^^;)

    多分ノズルの精度とか、スライスのプログラム、サポートの形状などは進歩していますが、ビルドプレートと造形物の接着に関しては、そんなに進んでいない気はしますね。

    最近はだいぶ価格も下がってきたので、良かったら3Dプリンタも、また試してみてくださいな。

タイトルとURLをコピーしました