0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

matplotlibを使ったグラフの作成

Last updated at Posted at 2025-01-26

はじめに

matplotlibを使って以下のようなグラフを作成するためのコードをまとめてみました。

説明は少なめですが、何か参考になれば幸いです。

準備

パッケージ

使用するパッケージは以下の通りです。

コード
from datetime import datetime

import pandas as pd

import matplotlib.pyplot as plt
import japanize_matplotlib

from adjustText import adjust_text

データセット

使用するデータセットはKaggleで公開されているSuperstore Sales Datasetです。このデータセットを少し前処理した上で、以下の列に着目してグラフを描画することにします。

# 列名 説明
1 Order_ID 注文ID(ユニーク数:4922)
2 Order_yyyymm 注文日年月(2015年1月-2018年12月)
3 Segment 注文者の業態(Consumer・Corporate・Home Office)
4 Sales 売上

以下ではこのデータフレームがdfという変数に格納されているとします。

数値付き棒グラフ

年月別の売上を棒グラフとして描画し、さらにその数値もグラフ内に表示させるためのコードを紹介します。

数値付き棒グラフのポイント
ax1.text()を使ってテキスト表示させる。
もし文字が重なってしまう場合はadjustTextを使う。

以下のような出力用のデータフレームを作成し、グラフを描画します。

# 列名 説明
1 Order_yyyymm 注文日の年月
2 Sales 売上
コード
# 出力用のデータフレームの作成
df_res = df.groupby('Order_yyyymm')[['Sales']].sum()
df_res = df_res.reset_index()

# グラフの描画
fig = plt.figure(figsize=(15, 7))
# カラーマップの設定
cmap = plt.colormaps.get_cmap('tab10')

# 1つ目の軸
ax1 = fig.add_subplot(111)

# 棒グラフの描画
texts = []
x = df_res.index
y = df_res['Sales']
ax1.bar(x, y, alpha=0.5, color=cmap(0))
for xdata, ydata in zip(x, y):
    texts.append(ax1.text(xdata, ydata, f'${ydata/1000:,.0f}K', ha='center', va='bottom', color=cmap(0)))
adjust_text(texts)

# 軸の設定
ax1.set_xticks(df_res.index)
ax1.set_xticklabels(df_res['Order_yyyymm'], rotation=90)
ax1.set_xlabel('注文日')
ax1.set_ylabel('売上')
# グリッドの表示
ax1.grid(axis='y')
plt.show()

output.png

積み上げ棒グラフ

ここでは年月別に注文者の業態(Segment)毎の売上を積み上げ棒グラフで表示させるコードを紹介します。

積み上げ棒グラフのポイント
ax1.bar()の引数でbottom=を設定すること。

以下のような出力用のデータフレームを作成し、グラフを描画します。

# 列名 説明
1 Order_yyyymm 注文日の年月
2 Consumer Consumerの売上
3 Corporate Corporateの売上
4 Home Office Home Officeの売上
コード
# 出力用のデータフレームの作成
df_res = df.groupby('Order_yyyymm')[['Sales']].sum().rename(columns={'Sales': 'all'})
# セグメント毎に集計
segments = ['Consumer', 'Corporate', 'Home Office']
for seg in segments:
    df_res[seg] = df.loc[df['Segment']==seg, :].groupby('Order_yyyymm')['Sales'].sum()
df_res = df_res.reset_index()

# グラフの描画
fig = plt.figure(figsize=(15, 7))
# カラーマップの設定
cmap = plt.colormaps.get_cmap('tab10')

# 1つ目の軸
ax1 = fig.add_subplot(111)

# 棒グラフの描画
y_cumsum = 0
for i, seg in enumerate(segments):
    x = df_res.index
    y = df_res[seg]
    ax1.bar(x, y, bottom=y_cumsum, alpha=0.5, color=cmap(i), label=seg)
    y_cumsum += y

# 軸の設定
ax1.set_xticks(df_res.index)
ax1.set_xticklabels(df_res['Order_yyyymm'], rotation=90)
ax1.set_xlabel('注文日')
ax1.set_ylabel('売上[$]')
# 凡例の表示
ax1.legend()
# グリッドの表示
ax1.grid(axis='y')
plt.show()
output.png

このコードを少し調整することで、以下のように割合に直したグラフを作成することもできます。

コード
df = df_data.copy()

# 出力用のデータフレームの作成
df_res = df.groupby('Order_yyyymm')[['Sales']].sum().rename(columns={'Sales': 'all'})
# セグメント毎に集計
segments = ['Consumer', 'Corporate', 'Home Office']
for seg in segments:
    df_res[seg] = df.loc[df['Segment']==seg, :].groupby('Order_yyyymm')['Sales'].sum()
    df_res[f'{seg}_rate'] = df_res[seg] / df_res['all']
df_res = df_res.reset_index()

# グラフの描画
fig = plt.figure(figsize=(15, 7))
# カラーマップの設定
cmap = plt.colormaps.get_cmap('tab10')

# 1つ目の軸
ax1 = fig.add_subplot(111)

# 棒グラフの描画
y_cumsum = 0
for i, seg in enumerate(segments):
    x = df_res.index
    y = df_res[f'{seg}_rate'] * 100
    ax1.bar(x, y, bottom=y_cumsum, alpha=0.5, color=cmap(i), label=seg)
    y_cumsum += y

# 軸の設定
ax1.set_xticks(df_res.index)
ax1.set_xticklabels(df_res['Order_yyyymm'], rotation=90)
ax1.set_xlabel('注文日')
ax1.set_ylabel('売上割合[%]')
# 凡例の表示
ax1.legend()
# グリッドの表示
ax1.grid(axis='y')
plt.show()

output.png

横並び棒グラフ

上で描画した積み上げ棒グラフを横並びにしたバージョンを表示させるコードを紹介します。

横並び棒グラフのポイント
ax1.bar()の引数でwidth=を設定すること。

コード
# 出力用のデータフレームの作成
df_res = df.groupby('Order_yyyymm')[['Sales']].sum().rename(columns={'Sales': 'all'})
# セグメント毎に集計
segments = ['Consumer', 'Corporate', 'Home Office']
for seg in segments:
    df_res[seg] = df.loc[df['Segment']==seg, :].groupby('Order_yyyymm')['Sales'].sum()
df_res = df_res.reset_index()

# グラフの描画
fig = plt.figure(figsize=(15, 7))
# カラーマップの設定
cmap = plt.colormaps.get_cmap('tab10')

# 1つ目の軸
ax1 = fig.add_subplot(111)

# 棒グラフの描画
width = 0.9 / len(segments)
for i, seg in enumerate(segments):
    x = df_res.index
    y = df_res[seg]
    ax1.bar(x+(-0.5+i)*width, y, width=width, alpha=0.5, color=cmap(i), label=seg)

# 軸の設定
ax1.set_xticks(df_res.index)
ax1.set_xticklabels(df_res['Order_yyyymm'], rotation=90)
ax1.set_xlabel('注文日')
ax1.set_ylabel('売上[$]')
# 凡例の表示
ax1.legend()
# グリッドの表示
ax1.grid(axis='y')
plt.show()

output.png

2軸グラフ

これまでは注文者の業態(Segment)毎の売上に着目していましたが、それと同時に業態毎の1注文当たりの単価が気になる場合もあると思います。そこで売上を棒グラフ、単価を折れ線グラフで描画するコードを紹介します。

2軸グラフのポイント
ax2=ax1.twinx()で2軸目の設定をする。

以下のような出力用のデータフレームを作成し、グラフを描画します。

# 列名 説明
1 Order_yyyymm 注文日の年月
2 Consumer_Sales Consumerの売上
3 Corporate_Sales Corporateの売上
4 Home Office_Sales Home Officeの売上
5 Consumer_Unit_Price Consumerの単価
6 Corporate_Unit_Price Corporateの単価
7 Home Office_Unit_Price Home Officeの単価
コード
# 出力用のデータフレームの作成
df_res = df.groupby('Order_yyyymm')[['Sales']].sum().rename(columns={'Sales': 'all_Sales'})
# セグメント毎に売上を集計
segments = ['Consumer', 'Corporate', 'Home Office']
for seg in segments:
    df_res[f'{seg}_Sales'] = df.loc[df['Segment']==seg, :].groupby('Order_yyyymm')['Sales'].sum()
# セグメント毎に単価を集計
df_temp = df.groupby(['Order_yyyymm', 'Order_ID', 'Segment'])[['Sales']].sum()
df_temp = df_temp.reset_index()
for seg in segments:
    df_res[f'{seg}_Unit_Price'] = df_temp.loc[df_temp['Segment']==seg, :].groupby('Order_yyyymm')['Sales'].mean()

df_res = df_res.reset_index()

# グラフの描画
fig = plt.figure(figsize=(15, 7))
# カラーマップの設定
cmap = plt.colormaps.get_cmap('tab10')

# 1つ目の軸
ax1 = fig.add_subplot(111)

# 棒グラフの描画
y_cumsum = 0
for i, seg in enumerate(segments):
    x = df_res.index
    y = df_res[f'{seg}_Sales']
    ax1.bar(x, y, bottom=y_cumsum, alpha=0.5, color=cmap(i), label=seg)
    y_cumsum += y

# 2つの目の軸
ax2 = ax1.twinx()

# 折れ線グラフの描画
for i, seg in enumerate(segments):
    x = df_res.index
    y = df_res[f'{seg}_Unit_Price']
    ax2.plot(x, y, alpha=1, color=cmap(i))

# 軸の設定
ax1.set_xticks(df_res.index)
ax1.set_xticklabels(df_res['Order_yyyymm'], rotation=90)
ax1.set_xlabel('注文日')
ax1.set_ylabel('売上[$]')
ax2.set_ylabel('単価[$]')
# 凡例の表示
ax1.legend()
# グリッドの表示
ax1.grid(axis='y')
plt.show()

output.png

パレート図

2軸グラフの応用として、州毎の売り上げについてのパレート図を描画するコードを紹介します。

コード
# 出力用のデータフレームの作成
df_res = df.groupby('State')[['Sales']].sum()
df_res = df_res.reset_index()
df_res = df_res.sort_values('Sales', ascending=False)
df_res = df_res.reset_index()
df_res['Sales_rate'] = df_res['Sales'] / df_res['Sales'].sum()
df_res['Sales_rate_cumsum'] = df_res['Sales_rate'].cumsum()
df_res = df_res.iloc[:40, :]

# グラフの描画
fig = plt.figure(figsize=(20, 7))
# カラーマップの設定
cmap = plt.colormaps.get_cmap('tab10')

texts = []

# 1つ目の軸
ax1 = fig.add_subplot(111)

# 棒グラフの描画
x = df_res.index
y = df_res['Sales']
ax1.bar(x, y, alpha=0.5, color=cmap(0))
for xdata, ydata in zip(x, y):
    ax1.text(xdata, ydata, f'${ydata/1000:.0f}K', ha='center', va='bottom', color=cmap(0))

# 2つの目の軸
ax2 = ax1.twinx()

# 折れ線グラフの描画
x = df_res.index
y = df_res['Sales_rate_cumsum'] * 100
ax2.plot(x, y, marker='.', alpha=1, color=cmap(1))

# 軸の設定
ax1.set_xticks(df_res.index)
ax1.set_xticklabels(df_res['State'], rotation=90)
ax1.set_xlabel('')
ax1.set_ylabel('売上[$]')
ax2.set_ylabel('売上割合')
ax2.set_ylim(0, 100)
# グリッドの表示
ax2.grid(axis='y')
plt.show()

output.png

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?