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

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

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

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

Python 3.x

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

Python

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

Q&A

解決済

1回答

196閲覧

時刻とデータ長に合わせてグラフの場所と長さを決めたい

beluga00nm

総合スコア12

Matplotlib

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

Python 3.x

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

Python

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

0グッド

1クリップ

投稿2024/04/23 15:29

編集2024/04/23 15:34

実現したいこと

python3のmatplotlibに関する質問です。
pandasのデータフレームが複数用意されており、indexにはdatetime形式の年月日と時刻が入っています。
それぞれのデータフレームの長さや開始日時はすべて異なります。
これらのデータに対して次のようなグラフを作ろうと思っています。

イメージ説明

発生している問題・分からないこと

fig.add_axesを利用してデータ長とデータ開始時刻に合わせてグラフを書いてみたのですが、それぞれの横軸がぴったり合ってくれません(14:00のところなど)。
fig.add_axesがグラフ外の余白など?も含めて長さを決めているからなのかなと思っているのですが、何かいい方法はないでしょうか?

該当のソースコード

python

1fig = plt.figure(figsize = (16,8)) 2year_list = [2021, 2021, 2021, 2021, 2022, 2022, 2022, 2022, 2022, 2022, 2023, 2023, 2023, 2023, 2023] 3ID_list = [17008, 18018, 20028, 20029, 16017, 16019, 16022, 20028, 20029, 22034, 20028, 22033, 22034, 22037, 22038] 4places = [1,2,7,3,3,4,5,4,5,6,6,3,2,1,1] #それぞれのグラフが何段目か 5plt.rcParams["font.size"] = 18 6 7for j, year, ID in zip(places, year_list, ID_list): 8 df2 = load_and_format(year,ID) #データをロードする部分 9 10 graph_left_h = int(str(df2.index[0])[11:13]) #データのinndexのはじめの値から"時"を抜き出す 11 graph_left_m = int(str(df2.index[0])[14:16]) #データのinndexのはじめの値から"分"を抜き出す 12 left = ((graph_left_h-6.5)+(graph_left_m/60))/12 #グラフの左端の場所を決める 13 14 ax = fig.add_axes([left,1 - j*0.13,len(df2)/3600/12,0.08]) 15 ax.scatter(df2.index, df2["data1"]*0.5, color = "red", s = 30) 16 17 ax.set_ylim(0,1) 18 ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) 19 ax.xaxis.set_major_locator(mdates.HourLocator()) 20 ax.tick_params(left=False, labelleft=False) 21 22# ここから一番下の軸を書く部分 23ax_bottom = fig.add_axes([0,0,1,0.01]) 24ax_bottom.plot(pd.date_range("6:30:30","18:30:30", freq='H'),np.ones(13)*10) 25ax_bottom.set_ylim(0,1) 26ax_bottom.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) 27ax_bottom.xaxis.set_major_locator(mdates.HourLocator()) 28ax_bottom.tick_params(left=False, labelleft=False) 29ax_bottom.spines[['left','right','top']].set_visible(False) 30 31plt.show()

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

sharexを使おうかとも思ったのですが、それぞれのデータの年と日付が異なります。
時刻だけshareする方法はないでしょうか。すべてのデータの年月日を書き換えてから軸をシェアするのが最善でしょうか?

補足

Jupyter notebookを使っています。

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

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

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

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

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

guest

回答1

0

ベストアンサー

一番外の Axes を作って、それに対して inset_axes を transform=ax.transData で作ってやるのが簡単だと思います。
matplotlib は時系列の値を float で持っていて、時刻データからそのfloatへの変換は matplotlib.dates.date2num 等でできます。整数部分が日付、小数点以下の部分が時刻の情報になっています。
https://matplotlib.org/stable/api/dates_api.html

一番外のAxesの座標を、小数点部分だけの値で作っておいて、プロットしたいデータの上下限の小数点部分とそろえて inset_axes を切り出してやれば、表示されるプロットもそろうと思います。

以下、質問者さんの実際のデータがよくわからないので、適当にイメージとして作成してみましたので、参考まで。

python

1import pandas as pd 2import matplotlib.pyplot as plt 3import matplotlib.dates as mdates 4 5data = [ 6 [1, pd.date_range('2020-01-01 08:30:00', '2020-01-01 13:00:00', 20)], 7 [1, pd.date_range('2020-01-01 15:10:00', '2020-01-01 18:30:00', 10)], 8 [3, pd.date_range('2021-02-01 12:20:00', '2021-02-01 16:50:00', 15)], 9 [5, pd.date_range('2023-12-31 10:30:00', '2023-12-31 12:40:00', 10)], 10 [5, pd.date_range('2023-12-31 13:20:00', '2023-12-31 14:10:00', 3)], 11] 12 13left0, right0 = '06:00', '19:00' 14 15# Figure と 一番外側の Axes 16fig, ax0 = plt.subplots(figsize=(8, 4)) 17 18# datestr2num で float に変換 → % 1 で小数部分だけにする → 日付の削除 19ax0.set_xlim(mdates.datestr2num(left0) % 1, mdates.datestr2num(right0) % 1) 20ax0.set_ylim(0, 7) 21ax0.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) 22ax0.xaxis.set_major_locator(mdates.HourLocator()) 23ax0.tick_params(left=False, labelleft=False) 24ax0.spines[['left','right','top']].set_visible(False) 25 26for i, s in data: 27 # 最小最大の15min外側をlimitに 28 left, right = min(s) - pd.Timedelta('15min'), max(s) + pd.Timedelta('15min') 29 # ax0 の座標に合わせるため % 1 して日付を削除 30 bb_left, bb_right = mdates.date2num(left) % 1, mdates.date2num(right) % 1 31 # データをプロットする Axes を作成 32 ax = ax0.inset_axes((bb_left, i, bb_right - bb_left, 1), transform=ax0.transData) 33 # ax の中では元の日付のままプロットする 34 ax.set_xlim(left, right) 35 ax.set_ylim(0, 1) 36 ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) 37 ax.xaxis.set_major_locator(mdates.HourLocator()) 38 ax.tick_params(left=False, labelleft=False) 39 ax.plot(s, [0.5] * len(s), 'ro') 40 41plt.show()

イメージ説明

投稿2024/04/24 15:47

bsdfan

総合スコア4578

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

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

beluga00nm

2024/04/24 19:50

無事目的のグラフを描写することができました!inset_axesというものを存じ上げなかったので大変勉強になりました。ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問