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

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

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

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

Python 3.x

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1338閲覧

Matplotlib:時系列グラフでX軸のレイアウトと出力サイズについて

d-hayahsi

総合スコア16

Matplotlib

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

Python 3.x

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2023/03/28 08:23

編集2023/03/29 06:48

実現したいこと・前提

・X軸のレイアウトについて
matplotlibのsubplotを用いて、6行2列(計12個)の時系列グラフを作成しております。
それぞれ時系列グラフなので、X軸には日付が出力されます。
YYYY-MM-ddと表示されるのですが、重なってしまい見づらくなってしまうので改善したいです。

イメージ説明

・出力サイズについて
6行2列のグラフサイズはそれぞれ、figsize = (15, 50)になっています。
それをsavefigでPDF出力し、更にそれを紙(A4)で印刷します。
それが試行錯誤しても良い感じ?に印刷することができません。
具体的には、1列目のY軸ラベルが表示されなくなったり、
一番下に表示される日付が表示されなくなったりしてしまいます。

これらをある程度、綺麗に印刷できるようにご教示頂きたいです。
宜しくお願い致します。

現在のソースコード

Python

1fig = plt.figure(figsize = (15, 50), tight_layout=True) # グラフサイズ(幅、高さ) 2for col in range(df_1.shape[1]): 3 plt.subplot(12, 2, col+1) 4 plt.plot(df_1.iloc[:, col], marker="o", color="lime") 5 # plt.title("No." + str(col)) # 列Noをタイトル 6 plt.ticklabel_format(style="plain", axis="y", scilimits=(0, 0)) # eを使わない表現 7 plt.gca().get_yaxis().set_major_formatter(ticker.FuncFormatter(lambda v,p: f'{int(v):,d}')) # 3桁ごとにカンマで区切る 8 plt.grid() 9 10 # 列毎(各グラフ)の個別設定 11 for i in range(len(columns)): 12 if col == i: 13 plt.title(columns[i]) 14 plt.legend([columns[i]]) 15 16plt.savefig(str_today + "sample.pdf")

試したこと

figsizeの変更、tight_layoutをやめて個別に設定

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

matplotlib 3.6.3

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

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

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

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

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

d-hayahsi

2023/03/28 23:22

ご回答ありがとうございます。 A4サイズで印刷する良い方法はご存じないでしょうか。 宜しくお願い致します。
guest

回答1

0

ベストアンサー

ChatGPTの回答

Pythonでmatplotlibを利用した以下を実現するサンプルコードを教えてください。

  • 折れ線グラフである。
  • X軸は10日連続の時系列データである。
  • Y軸は10個の1~10程度のランダムな数値データである。
  • X軸の軸ラベルの年月日の文字列はお互い重ならないように斜めに傾けて表示したい。

以下がPythonのサンプルコードになります。Matplotlibのpyplotモジュールを使い、X軸のラベルにはtick_params()関数を使い、rotationオプションを指定して斜めに表示させます。

Python

1省略

イメージ説明

X軸ラベルの日付文字列がbottomからはみ出しています。bottomに余裕を持たせてください。

X軸のラベルがはみ出さないようにするには、グラフの下部に余白を設定する必要があります。これは、subplots_adjust()関数を使用して実現できます。以下が修正されたサンプルコードになります。

Python

1import random 2import matplotlib.pyplot as plt 3from datetime import datetime, timedelta 4 5# X軸の日付リストを生成 6dates = [datetime(2023, 3, 20) + timedelta(days=i) for i in range(10)] 7 8# Y軸のランダムな数値リストを生成 9values = [random.randint(1, 10) for _ in range(10)] 10 11# 折れ線グラフを作成 12plt.plot(dates, values) 13 14# X軸のラベルを斜めに表示 15plt.xticks(rotation=45) 16 17# グラフのタイトルと軸ラベルを設定 18plt.title('Random Data') 19plt.xlabel('Date') 20plt.ylabel('Value') 21 22# グラフの下部に余白を持たせる 23plt.subplots_adjust(bottom=1.5) 24 25# グラフを表示 26plt.show()

イメージ説明

subplotによる複数グラフも考慮して頂けないでしょうか。
宜しくお願い致します。

複数のグラフを表示するには、Matplotlibのsubplot()関数を使用します。以下が、2つのグラフを表示するサンプルコードになります。1つ目のグラフは、上部に表示され、2つ目のグラフは、下部に表示されます。

Python

1省略

イメージ説明

ax1のグラフのX軸ラベルが斜めになっていません。ax2と同じく斜めにしてください。

申し訳ありません。ax1のX軸ラベルも斜めにするために、ax1のX軸の目盛りラベルのテキストを回転する必要があります。以下が修正されたサンプルコードになります。

Python

1省略

イメージ説明

ax1のX軸ラベルがax2のために隠れてしまっています。ax1とax2の間にも余白を持たせてください。

問題解決のために、plt.subplots_adjust関数を利用して余白を調整しましょう。以下が修正されたサンプルコードになります。

Python

1import random 2import matplotlib.pyplot as plt 3from datetime import datetime, timedelta 4 5# X軸の日付リストを生成 6dates = [datetime(2023, 3, 20) + timedelta(days=i) for i in range(10)] 7 8# Y軸のランダムな数値リストを生成 9values1 = [random.randint(1, 10) for _ in range(10)] 10values2 = [random.randint(1, 10) for _ in range(10)] 11 12# 2つのグラフを表示する 13fig, (ax1, ax2) = plt.subplots(2, 1) 14 15# 1つ目のグラフを作成 16ax1.plot(dates, values1) 17ax1.set_title('Random Data 1') 18ax1.set_ylabel('Value 1') 19 20# 1つ目のグラフのX軸ラベルを斜めにする 21for tick in ax1.get_xticklabels(): 22 tick.set_rotation(45) 23 24# 2つ目のグラフを作成 25ax2.plot(dates, values2) 26ax2.set_title('Random Data 2') 27ax2.set_xlabel('Date') 28ax2.set_ylabel('Value 2') 29 30# X軸のラベルを斜めに表示 31plt.xticks(rotation=45) 32 33# グラフの下部と上部に余白を持たせる 34plt.subplots_adjust(hspace=0.5, bottom=0.2, top=0.9) 35 36# グラフを表示 37plt.show()

イメージ説明

惜しい。でもあとは調整すればいいか。

ChatGPTの回答

追加でご回答ありがとうございます。
6行2列(計12個)のグラフをA4一枚に良い感じに印刷する方法はご存じないでしょうか。
宜しくお願い致します。

6行2列の12個のグラフをA4用紙1枚にプリントアウトするには、いくつかのアプローチがあります。ここでは、以下の手順に従って、グリッドを作成してすべてのグラフを1つのFigureにまとめる方法を説明します。

  1. 1つのFigureを作成します。これは、12個のグラフをまとめるための「コンテナ」になります。

  2. Figure内に、6行2列のグリッドを作成します。これにより、12個のサブプロットが作成されます。

  3. それぞれのサブプロットに、グラフをプロットします。このとき、適切な位置にプロットするように調整する必要があります。

  4. ページの余白を設定し、Figureを印刷可能なサイズに設定します。

  5. 最後に、Figureを印刷します。

以下がサンプルコードになります。データはランダムな値を使用しています。

python

1import random 2import matplotlib.pyplot as plt 3 4# 6行2列のグリッドを作成し、すべてのサブプロットを取得する 5fig, axs = plt.subplots(nrows=6, ncols=2, figsize=(8.27, 11.69)) 6 7# 各サブプロットにランダムなデータをプロットする 8for ax in axs.flat: 9 # X軸の日付リストを生成 10 dates = [i for i in range(10)] 11 12 # Y軸のランダムな数値リストを生成 13 values = [random.randint(1, 10) for _ in range(10)] 14 15 # ランダムなデータをプロットする 16 ax.plot(dates, values) 17 ax.set_title('Random Data') 18 ax.set_xlabel('X Label') 19 ax.set_ylabel('Y Label') 20 21# ページの余白を設定する 22plt.tight_layout() 23 24# グラフを印刷する 25plt.show()

このコードを実行すると、以下のようにA4サイズの用紙に12個のグラフが印刷されます。

Sample Line Graph with Matplotlib (Multiple Subplots on One Page)

この方法は、サブプロットの数が多くなる場合でも拡張性があり、用紙のサイズを変更するだけでさまざまなページレイアウトを簡単に実現できます。

ChatGPTの回答

更に追加でご回答ありがとうございます。
送って頂いたコードを実行すると、確かにA4一枚に良い感じにプロットされます。
しかし、私が折れ線グラフにしたいデータは、千万・億単位であり桁数が増えているにも関わらず千・百万単位では表示しておりません。
上記のことが原因か分かりませんが、figsizeを同じ値にしてもグラフが小さく表示されてしまいます。
データの桁数が多く、Y軸の値の桁数が増えてしまう場合でも、A4サイズで良い感じに印刷は可能でしょうか。
宜しくお願い致します。

大きな数値を持つグラフを描画する場合、その値が大きいとY軸のラベルの表示スペースが不足してしまい、グラフが小さく表示される可能性があります。この場合、Y軸のラベルの表示スペースを増やすことが必要です。

以下は、Y軸のラベルのスペースを調整する方法です。

python

1import matplotlib.pyplot as plt 2import numpy as np 3 4# データの生成 5x = np.arange(10) 6y = np.random.randint(1, 1000000000, 10) 7 8# グラフの描画 9fig, axs = plt.subplots(6, 2, figsize=(8, 10), constrained_layout=True) 10for i, ax in enumerate(axs.ravel()): 11 ax.plot(x, y) 12 ax.set_title(f'Graph {i+1}') 13 ax.ticklabel_format(axis='y', style='sci', scilimits=(0,0)) # Y軸のラベルを指数表記にする 14 ax.yaxis.get_offset_text().set_fontsize(8) # Y軸のオフセット部分のフォントサイズを設定する 15 ax.tick_params(axis='both', labelsize=8) # 軸ラベルのフォントサイズを設定する 16plt.show()

このコードでは、Y軸のラベルを指数表記にして、Y軸のオフセット部分のフォントサイズを小さくしています。また、軸ラベルのフォントサイズも小さくしています。
このように調整することで、大きな数値を持つグラフでも適切に表示することができます。ただし、グラフが小さくなりすぎてしまう場合は、図のサイズを大きくする必要があります。

何度も回答ありがとうございます。
Y軸の目盛を指数表記せずにA4一枚にプロットすることは可能でしょうか。
宜しくお願い致します。

はい、Y軸の目盛を指数表記せずにA4一枚にプロットすることは可能です。

以下のサンプルコードでは、Y軸の目盛を指数表記せずに、軸のラベルには指数表記を用いるように設定しています。また、グラフのサイズを大きく設定することで、Y軸の値が多くなっても十分なスペースを確保しています。

Python

1import matplotlib.pyplot as plt 2import numpy as np 3 4# 10日分の時系列データを作成 5dates = np.arange('2022-01-01', '2022-01-11', dtype='datetime64[D]') 6 7# 10個の1〜10程度のランダムな数値データを作成 8data1 = np.random.randint(1, 11, size=10) * 10**7 9data2 = np.random.randint(1, 11, size=10) * 10**9 10 11# グラフのサイズを設定 12fig, axs = plt.subplots(nrows=2, ncols=3, figsize=(16, 12)) 13 14# 各グラフを作成 15axs[0, 0].plot(dates, data1) 16axs[0, 0].set_title('subplot 1') 17axs[0, 0].ticklabel_format(style='plain', axis='y') # Y軸の目盛を指数表記せずに表示 18axs[0, 0].set_ylabel('数値 [$10^7$]', rotation='horizontal', labelpad=40) 19 20axs[0, 1].plot(dates, data2) 21axs[0, 1].set_title('subplot 2') 22axs[0, 1].ticklabel_format(style='plain', axis='y') # Y軸の目盛を指数表記せずに表示 23axs[0, 1].set_ylabel('数値 [$10^9$]', rotation='horizontal', labelpad=40) 24 25axs[0, 2].plot(dates, data1) 26axs[0, 2].set_title('subplot 3') 27axs[0, 2].ticklabel_format(style='plain', axis='y') # Y軸の目盛を指数表記せずに表示 28axs[0, 2].set_ylabel('数値 [$10^7$]', rotation='horizontal', labelpad=40) 29 30axs[1, 0].plot(dates, data2) 31axs[1, 0].set_title('subplot 4') 32axs[1, 0].ticklabel_format(style='plain', axis='y') # Y軸の目盛を指数表記せずに表示 33axs[1, 0].set_xlabel('年月日') 34axs[1, 0].set_ylabel('数値 [$10^9$]', rotation='horizontal', labelpad=40) 35 36axs[1, 1].plot(dates, data1) 37axs[1, 1].set_title('subplot 5') 38axs[1, 1].ticklabel_format(style='plain', 39以下略

ChatGPTの回答

何度もご回答ありがとうございます。
これまでの追加情報を整理・追加の要望を書き留めると下記のようになります。
・6行2列の折れ線グラフをA41枚にプロット。
・X軸には、日付(YYYY-MM)が入るが、日付同士が干渉しないように表示させる。
・Y軸には7桁、又は8桁の数値を指数表記せずに表示。又は、千円単位や十万単位で表示させる。
以上です。
これらのことをChatGPTにてコードを作成してもらうことは可能でしょうか。
宜しくお願い致します。

以下が要望に沿ったサンプルコードになります。主に、Y軸目盛のフォーマットを変更することで、指数表記を避けることができます。また、X軸ラベルが重ならないように回転させること、グラフのサイズや余白を調整することにより、6行2列の折れ線グラフをA4 1枚にプロットすることができます。なお、Y軸の単位を適切に設定する必要があります。

python

1import matplotlib.pyplot as plt 2import numpy as np 3import pandas as pd 4from matplotlib.ticker import FuncFormatter 5 6# サンプルデータ 7date_rng = pd.date_range(start='1/01/2022', end='6/30/2022', freq='D') 8data = pd.DataFrame(np.random.randint(1, 100000000, size=(len(date_rng), 12)), columns=[f"col_{i+1}" for i in range(12)]) 9data.set_index(date_rng, inplace=True) 10 11# グラフのフォーマット設定 12plt.rcParams['font.family'] = 'sans-serif' 13plt.rcParams['font.sans-serif'] = ['Arial'] 14plt.rcParams.update({'font.size': 8}) 15 16# グラフのサイズ設定 17fig, axs = plt.subplots(6, 2, figsize=(8.27, 11.69), constrained_layout=True) 18 19# X軸ラベルの回転角度設定 20plt.xticks(rotation=45, ha='right') 21 22# Y軸目盛のフォーマット設定 23def millions_formatter(x, pos): 24 return '{:,.0f}M'.format(x/1000000) 25 26def billions_formatter(x, pos): 27 return '{:,.0f}B'.format(x/1000000000) 28 29# グラフのプロット 30for i, col in enumerate(data.columns): 31 row = i // 2 32 col = i % 2 33 ax = axs[row, col] 34 ax.plot(data.index, data[col], color='blue') 35 ax.yaxis.set_major_formatter(FuncFormatter(millions_formatter)) # 適宜、billions_formatterに変更 36 ax.set_title(col, fontsize=8) 37 ax.tick_params(axis='both', which='major', labelsize=6) 38 ax.set_xlabel('Date', fontsize=8) 39 ax.set_ylabel('Y axis', fontsize=8) 40 41plt.show()

このコードを実行すると、6行2列の折れ線グラフがA4サイズの1枚に収まるようにプロットされます。X軸ラベルの表示も重ならないように回転しています。また、Y軸目盛は、指数表記を避けるために、適切な単位で表示されています。

投稿2023/03/28 08:42

編集2023/04/11 08:31
can110

総合スコア38266

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

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

d-hayahsi

2023/03/28 08:45

ご回答ありがとうございます。 subplotによる複数グラフも考慮して頂けないでしょうか。 宜しくお願い致します。
d-hayahsi

2023/03/29 05:44

追加でご回答ありがとうございます。 6行2列(計12個)のグラフをA4一枚に良い感じに印刷する方法はご存じないでしょうか。 宜しくお願い致します。
d-hayahsi

2023/03/31 08:24

更に追加でご回答ありがとうございます。 送って頂いたコードを実行すると、確かにA4一枚に良い感じにプロットされます。 しかし、私が折れ線グラフにしたいデータは、千万・億単位であり桁数が増えているにも関わらず千・百万単位では 表示しておりません。 上記のことが原因か分かりませんが、figsizeを同じ値にしてもグラフが小さく表示されてしまいます。 データの桁数が多く、Y軸の値の桁数が増えてしまう場合でも、A4サイズで良い感じに印刷は可能でしょうか。 宜しくお願い致します。
d-hayahsi

2023/04/04 06:26

何度も回答ありがとうございます。 Y軸の目盛を指数表記せずにA4一枚にプロットすることは可能でしょうか。 宜しくお願い致します。
d-hayahsi

2023/04/07 06:46

何度もご回答ありがとうございます。 これまでの追加情報を整理・追加の要望を書き留めると下記のようになります。 ・6行2列の折れ線グラフをA41枚にプロット。 ・X軸には、日付(YYYY-MM)が入るが、日付同士が干渉しないように表示させる。 ・Y軸には7桁、又は8桁の数値を指数表記せずに表示。又は、千円単位や十万単位で表示させる。 以上です。 これらのことをChatGPTにてコードを作成してもらうことは可能でしょうか。 宜しくお願い致します。
d-hayahsi

2023/04/12 00:36

ご回答ありがとうございます。 下記のようなエラーが発生していしまい、色々試してみたのですが解決できないのでご教示頂けないでしょうか。 宜しくお願い致します。 --------------------------------------------------------------------------- KeyError Traceback (most recent call last) File ~\AppData\Local\miniconda3\lib\site-packages\pandas\core\indexes\base.py:3803, in Index.get_loc(self, key, method, tolerance) 3802 try: -> 3803 return self._engine.get_loc(casted_key) 3804 except KeyError as err: File ~\AppData\Local\miniconda3\lib\site-packages\pandas\_libs\index.pyx:138, in pandas._libs.index.IndexEngine.get_loc() File ~\AppData\Local\miniconda3\lib\site-packages\pandas\_libs\index.pyx:165, in pandas._libs.index.IndexEngine.get_loc() File pandas\_libs\hashtable_class_helper.pxi:5745, in pandas._libs.hashtable.PyObjectHashTable.get_item() File pandas\_libs\hashtable_class_helper.pxi:5753, in pandas._libs.hashtable.PyObjectHashTable.get_item() KeyError: 0 The above exception was the direct cause of the following exception: KeyError Traceback (most recent call last) Cell In[2], line 34 32 col = i % 2 33 ax = axs[row, col] ---> 34 ax.plot(data.index, data[col], color='blue') 35 ax.yaxis.set_major_formatter(FuncFormatter(millions_formatter)) # 適宜、billions_formatterに変更 36 ax.set_title(col, fontsize=8) File ~\AppData\Local\miniconda3\lib\site-packages\pandas\core\frame.py:3805, in DataFrame.__getitem__(self, key) 3803 if self.columns.nlevels > 1: 3804 return self._getitem_multilevel(key) -> 3805 indexer = self.columns.get_loc(key) 3806 if is_integer(indexer): 3807 indexer = [indexer] File ~\AppData\Local\miniconda3\lib\site-packages\pandas\core\indexes\base.py:3805, in Index.get_loc(self, key, method, tolerance) 3803 return self._engine.get_loc(casted_key) 3804 except KeyError as err: -> 3805 raise KeyError(key) from err 3806 except TypeError: 3807 # If we have a listlike key, _check_indexing_error will raise 3808 # InvalidIndexError. Otherwise we fall through and re-raise 3809 # the TypeError. 3810 self._check_indexing_error(key) KeyError: 0
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問