質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Matplotlib

MatplotlibはPythonのおよび、NumPy用のグラフ描画ライブラリです。多くの場合、IPythonと連携して使われます。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

1回答

2103閲覧

Pythonのmatplotlibにてグラフの描画を自動化する。

Danrussia

総合スコア44

Matplotlib

MatplotlibはPythonのおよび、NumPy用のグラフ描画ライブラリです。多くの場合、IPythonと連携して使われます。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

0クリップ

投稿2019/07/23 13:50

最初に

この質問は直接的な解決策が欲しく質問するというよりかは、(自分の問題解決能力向上のため)実現したい課題に対して必要な要素をピックアップして、その要素をどういった方法で解けば良いか、コーディングの方針をお伺いしたいという類の質問です。

実装したい事

Pythonのmatplotlibを使用して下の写真の様なグラフの作成を自動化したいと思っています。

自動化のイメージとしては、for文を使って一気に全てのグラフを描写するのではなく、下記のデータセットのBeanNumber
をコードに打ち込むとそのBeanNumberのグラフが生成されるようなイメージです。

(Pythonでいうと def makefigure (Specific) みたいな感じで関数を作って、(Specific)の部分にBeanNumberを
入れるとグラフが描写される、SQLだとSELECT文で特定のBeanNumeberだけ抜き出す、Excell的にはフィルターをかける、といった感じのすごい曖昧なイメージです。)
イメージ説明

実現に必要な要素

・下記のデータセットの様に複数の"BeanNumber"があるなかで、ひとつの"BeanNumber"のみを選んで、それをグラフで作成する。
・極力手作業を減らすため、下記の「データの書式」のコードの中の「#★」に書いてある"Hoge!"を
"BeanNumber"と対応する"Sumple"に置き換える。

###使用するデータセット(book1.csv)
各サンプル100個づつあります。(B2が100,B3が100,B4が100,,,,,,,,B39が100)

Long axisShort axisGrain thicknessSumpleBeanNumber
0.920.910.73くるみ豆B2
0,900.890.56くるみ豆B2
1.040.970.63くるみ豆B2
...
0.970.920.74五葉黒豆B6
0.970.880.51五葉黒豆B6
...
1.210.950.77濃緑丸豆B39
0.920.850.83濃緑丸豆B39
0.930.900.55濃緑丸豆B39
1.100.960.67濃緑丸豆B39
0.910.850.54濃緑丸豆B39

データの書式

Python3

1import os 2import matplotlib 3import matplotlib.pyplot as plt 4import matplotlib.font_manager as fm 5import pandas as pd 6 7os.chdir("C://Users//For Programming//Documents") 8pd.options.display.max_rows = 5 9df1=pd.read_csv("book1.csv",encoding='shift_jis') 10df1.columns 11 12plt.rcParams['font.family'] = 'IPAPGothic' 13plt.rcParams['axes.linewidth'] = 3.0 14plt.rcParams["font.size"] = 30 15 16fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(40,10)) 17plt.subplots_adjust(wspace=0.3, hspace=0.2) 18 19 20ax1.set_xlabel('長軸(cm)') 21ax1.set_ylabel('個数(個)') 22ax1.set_title("Hoge!の長軸")#★ 23ax1.hist(df1['Long axis'], rwidth=0.7,edgecolor="k",color='#0000CD') 24ax1.set_xticks( [0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2,1.3,1.4] ) 25ax1.set_yticks( [5,10,15,20,25,30] ) 26 27 28 29ax2.set_xlabel('短軸(cm)') 30ax2.set_ylabel('個数(個)') 31ax2.set_title("Hoge!の短軸")#★ 32ax2.hist(df1['Short axis'], rwidth=0.7,edgecolor="k",color='#0000CD') 33ax2.set_xticks( [0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2,1.3,1.4]) 34ax2.set_yticks( [5,10,15,20,25,30] ) 35 36 37ax3.set_xlabel('粒厚(cm)') 38ax3.set_ylabel('個数(個)') 39ax3.set_title("Hoge!の粒厚")#★ 40ax3.hist(df1['Grain thickness'],rwidth=0.7,edgecolor="k",color='#0000CD') 41ax3.set_xticks( [0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2,1.3,1.4]) 42ax3.set_yticks( [5,10,15,20,25,30] ) 43 44plt.savefig('Hoge!.jpg')#★ 45

補足情報(FW/ツールのバージョンなど)

Anaconda
Python
Pycharm
お忙しいとは思いますが、よろしくお願いいたします。
情報に不足がありましたら、ご指摘お願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiitoi

2019/07/23 13:54

どこかのアップローダーに csv ファイルをアップロードしていただくことはできますか?
Danrussia

2019/07/23 14:00

Googleドライブのリンクをお送りする形になるかと思います。
tiitoi

2019/07/23 14:16

動作確認はしてないですが、回答を書きました。 もし動かないまたは意図と違いましたら教えてください。
tiitoi

2019/07/23 15:03

データをアップロードしていただきありがとうございます。 回答のコードを実行した結果、添付画像のようになりました。 このような意図であっていますでしょうか。
guest

回答1

0

ベストアンサー

Data Frame で例えば、BeanNumber が B2 だけの行を抽出したい場合は df[df["BeanNumber"] == "B2"] でできます。
抽出したあと "Sumple" 列を参照して豆の名前を取得して、グラフのタイトル部分に f-string で埋め込めばいいかと思います。

サンプルコード

入力 CSV

csv

1Long axis,Short axis,Grain thickness,Sumple,BeanNumber 20.92,0.91,0.73,くるみ豆,B2 30.90,0.89,0.56,くるみ豆,B2 41.04,0.97,0.63,くるみ豆,B2 50.92,0.91,0.73,黒豆,B1 60.90,0.89,0.56,黒豆,B1 71.04,0.97,0.63,黒豆,B1

python

1import os 2import matplotlib 3import matplotlib.pyplot as plt 4import pandas as pd 5 6os.chdir("C://Users//For Programming//Documents") 7pd.options.display.max_rows = 5 8 9plt.rcParams["font.family"] = "IPAPGothic" 10plt.rcParams["axes.linewidth"] = 3.0 11plt.rcParams["font.size"] = 30 12 13def plot(data, bean_number): 14 # 変更箇所1 15 # 列 BeanNumber の値が bean_number の行だけ抽出する。 16 df = data[data["BeanNumber"] == bean_number] 17 if df.empty: 18 print(f"bean number {bean_number} does not exist in the data frame.") 19 return 20 bean_name = df.iloc[0]["Sumple"] 21 # ------------------------------------- 22 23 fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(40, 10)) 24 plt.subplots_adjust(wspace=0.3, hspace=0.2) 25 26 ax1.set_xlabel("長軸(cm)") 27 ax1.set_ylabel("個数(個)") 28 ax1.set_title(f"{bean_name} の長軸") # 変更箇所2 29 ax1.hist(df["Long axis"], rwidth=0.7, edgecolor="k", color="#0000CD") 30 ax1.set_xticks([0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4]) 31 ax1.set_yticks([5, 10, 15, 20, 25, 30]) 32 33 ax2.set_xlabel("短軸(cm)") 34 ax2.set_ylabel("個数(個)") 35 ax2.set_title(f"{bean_name} の短軸") # 変更箇所3 36 ax2.hist(df["Short axis"], rwidth=0.7, edgecolor="k", color="#0000CD") 37 ax2.set_xticks([0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4]) 38 ax2.set_yticks([5, 10, 15, 20, 25, 30]) 39 40 ax3.set_xlabel("粒厚(cm)") 41 ax3.set_ylabel("個数(個)") 42 ax3.set_title(f"{bean_name} の粒厚") # 変更箇所4 43 ax3.hist(df["Grain thickness"], rwidth=0.7, edgecolor="k", color="#0000CD") 44 ax3.set_xticks([0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4]) 45 ax3.set_yticks([5, 10, 15, 20, 25, 30]) 46 47 plt.savefig(f"bean_number_{bean_number}.png") # 変更箇所5 48 49 50df = pd.read_csv("book1.csv", encoding="shift_jis") 51plot(df, bean_number="B2")

イメージ説明

bean_number をコードに直接書く代わりにコマンドライン引数で渡したい場合は argparse モジュールをお使いください。

追記

フォーマット済み文字列リテラル自体初めて見たので、(自分のキャパの問題で)まだ完全に理解しきれていませんが、少し自分の方で調べてみます。

Python 3.6 以降で利用できる言語機能です。
変数を文字列の中に埋め込むやり方は以下の3つがあります。(上から古い順)
f-string はわりと最近追加された機能なので、ネット上のコードは format() を使っているものが多いですが、シンプルにかけるので気に入っています。

python

1val = 123 2 3# Python 2 4s = 'val == %d' % val 5print(s) # val == 123 6 7# format() (Python 3 以降) 8s = 'val == {}'.format(val) 9print(s) # val == 123 10 11# f-string (Python 3.6 以降) 12s = f'val == {val}' 13print(s) # val == 123

Python的にはどの文法用法なのか教えて頂けませんか?

以下の例で説明すると、

  1. df["Col1"] で Col1 列を Series オブジェクト (1次元配列) で取得する。
  2. df["Col1"] == "A" で値が "A" のインデックスは True、そうでないインデックスは False のブール型の Series オブジェクトが返る。
  3. DataFrame の [] にブール型の Series オブジェクトを渡すことで、値が True のインデックスの行だけを抽出できる。

numpy のブールインデックスと似た機能です。

NumPy配列のブールインデックス参照

実装上の話をすると、Python では自作のクラスで、[]== などの演算子をオーバーライドできるので、このような仕組みを実現できています。

python

1import pandas as pd 2 3df = pd.DataFrame({'Col1': ['A', 'A', 'B', 'C'], 4 'Col2': [31, 2, 3, 4]}) 5print(df) 6# Col1 Col2 7# 0 A 31 8# 1 A 2 9# 2 B 3 10# 3 C 4 11 12mask = df["Col1"] == "A" 13print(mask) 14# 0 True 15# 1 True 16# 2 False 17# 3 False 18# Name: Col1, dtype: bool 19 20df2 = df[mask] 21print(df2) 22# Col1 Col2 23# 0 A 31 24# 1 A 2

投稿2019/07/23 14:15

編集2019/07/23 15:41
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Danrussia

2019/07/23 15:13

凄い迅速な対応ありがとうございます。 フォーマット済み文字列リテラル自体初めて見たので、(自分のキャパの問題で)まだ完全に理解しきれていませんが、少し自分の方で調べてみます。 あともし可能であればお願いしたいのですが、ここで使われている["Hoge"]==Hoge]というのは Python的にはどの文法用法なのか教えて頂けませんか? # 列 BeanNumber の値が bean_number の行だけ抽出する。 df = data[data["BeanNumber"] == bean_number]
tiitoi

2019/07/23 15:36 編集

追記しました。 Python 言語に備わった機能というわけではなく、ブーリアンインデックスという pandas の機能です。
Danrussia

2019/07/24 03:21

「ブーリアンインデックス」について内部動作も含めて教えて頂き本当にありがとうございます。今ままで本当に漠然としか理解していなかったので、体系たって教えて頂いたおかげで理解できました。 def文の最後のilocを使用して、Sumpleを習得する方法は本当に自分の思いつく範囲外の事で、助かりました。 この度は本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問