【自分メモ】Pythonのデータ可視化モジュール『Matplotlib』逆引きチートシート

前提条件

モジュールのインポート

import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt

# 日本語フォントの設定
mpl.font_manager._rebuild()
plt.rcParams['font.family'] = 'IPAexGothic'

# Jupyter Notebookに描画する
%matplotlib inline

日本語に対応させる

ローカル環境

サーバー環境

ルート直下に.fontsフォルダを作成して、その中に日本語対応のフォントデータ(TTF,OTF)を格納します。

注意
フォルダ名は.fontでもfontsでもありません。.fontsです。

フリーフォントのIPAexGothicを例に紹介します。

ディレクトリ
root/
 ┣ .fonts/
 ┃ ┗ ipaexg.ttf
 ︙
 ┗ index.py(実行するプログラム)
Python
# 日本語フォントの設定
mpl.font_manager._rebuild()
plt.rcParams['font.family'] = 'IPAexGothic'

インターフェースの流儀

名称の確認

図(Figure)

fig, ax = plt.subplots()

# fig : <class 'matplotlib.figure.Figure'>
# ax  : <class 'matplotlib.axes._subplots.AxesSubplot'>

デザイン

逆引き コマンド
アスペクト比を変更する, default (6, 4) fig, ax = plt.subplots(figsize=(6, 6))
解像度を変更する fig, ax = plt.subplots(dpi=144)
背景色を変更する fig, ax = plt.subplots(facecolor='#54565D')

図のアスペクト比を変更する場合、matplotlib.pyplotクラスのsubplotsメソッドに、figsize=(横, 縦)を指定します。

fig, ax = plt.subplots(figsize=(6, 6)) # default: figsize=(6, 4)

図の解像度を変更する場合、matplotlib.pyplotクラスのsubplotsメソッドに、dpi=数値を指定します。

fig, ax = plt.subplots(dpi=144) # default: dpi=72

図の背景色を変更する場合、matplotlib.pyplotクラスのsubplotsメソッドに、facecolor='カラーコード'を指定します。

fig, ax = plt.subplots(facecolor='#54565D') # default: facecolor='#FFFFFF'

Axesも塗りつぶしたい場合は、matplotlib.axes.Axesクラスのset_facecolorメソッドにカラーコードを指定します。

fig, ax = plt.subplots(facecolor='#54565D')

# Axesの背景色をセット
ax.set_facecolor('#54565D')

サブプロット

逆引き コマンド
Axesを縦に複数並べる fig, ax = plt.subplots(nrows=2, tight_layout=True)
Axesを横に複数並べる fig, ax = plt.subplots(ncols=2, tight_layout=True)
Axesを縦横に複数並べる fig, ax = plt.subplots(nrows=2, ncols=2, tight_layout=True)

fig, ax = plt.subplots(
    nrows = 2,
    tight_layout = True # Axes同士が重ならないようにするため
)

fig, ax = plt.subplots(
    ncols = 2,
    tight_layout = True # Axes同士が重ならないようにするため
)

fig, ax = plt.subplots(
    nrows = 2,
    ncols = 2,
    tight_layout = True # Axes同士が重ならないようにするため
)

fig, ax = plt.subplots(
    nrows = 3,
    ncols = 2,
#   tight_layout = True, gridspec_kwのhspace、wspaceを指定する場合、不要
    gridspec_kw = dict(
        height_ratios = [2, 1, 3], # 縦のAxesの比率、2:1:3
        width_ratios = [1, 3],     # 横のAxesの比率、1:3
        hspace = 0.5,              # 縦のAxes間のスペース
        wspace = 0.3               # 横のAxes間のスペース
    )
)

gridspec_kwパラメータにhspaceまたはwspaceを指定する場合、tight_layout=Trueは不要です。好きな方を選びましょう。

from matplotlib.gridspec import GridSpec, GridSpecFromSubplotSpec

fig = plt.figure(figsize=(9, 5), tight_layout=True)

gs_master = GridSpec(
    nrows = 8,
    ncols = 12,
    height_ratios = np.ones(8, dtype=int),
    width_ratios = np.ones(12, dtype=int),
#     wspace=2, tight_layoutを
#     hspace=3  指定する場合、不要
)

ax1 = fig.add_subplot(GridSpecFromSubplotSpec(nrows=3, ncols=4, subplot_spec=gs_master[0:3, 0:4])[:, :])
ax2 = fig.add_subplot(GridSpecFromSubplotSpec(nrows=3, ncols=6, subplot_spec=gs_master[0:3, 4:10])[:, :])
ax3 = fig.add_subplot(GridSpecFromSubplotSpec(nrows=8, ncols=2, subplot_spec=gs_master[0:, 10:])[:, :])
ax4 = fig.add_subplot(GridSpecFromSubplotSpec(nrows=2, ncols=4, subplot_spec=gs_master[3:5, 0:4])[:, :])
ax5 = fig.add_subplot(GridSpecFromSubplotSpec(nrows=6, ncols=5, subplot_spec=gs_master[3:, 4:10])[:, :])
ax6 = fig.add_subplot(GridSpecFromSubplotSpec(nrows=3, ncols=2, subplot_spec=gs_master[5:, 0:2])[:, :])
ax7 = fig.add_subplot(GridSpecFromSubplotSpec(nrows=3, ncols=2, subplot_spec=gs_master[5:, 2:4])[:, :])

出力(画像として保存する)

逆引き コマンド
JPEGで保存 plt.savefig(fname='sample.jpg')
PNGで保存 plt.savefig(fname='sample.png')
SVGで保存 plt.savefig(fname='sample.svg')
inline描画と同じスタイルで保存 plt.savefig(fname='sample.svg', bbox_inches='tight')
解像度を変更して保存 plt.savefig(fname='sample.png', dpi=144)
背景色を変更して保存 plt.savefig(fname='sample.png', facecolor='#54565D')
枠線色を変更して保存 plt.savefig(fname='sample.png', edgecolor='#000000')
透過して保存 fig.patch.set_alpha(0)
ax.set_alpha(0)
plt.savefig(fname='sample.png', bbox_inches='tight')
参考 matplotlib.pyplot.savefig.htmlmatplotlib.org

座標軸(Axes)と軸(Axis)

枠線(Spines)

逆引き コマンド
左の枠線を消す ax.spines['left'].set_visible(False)
右の枠線を消す ax.spines['right'].set_visible(False)
上の枠線を消す ax.spines['top'].set_visible(False)
下の枠線を消す ax.spines['bottom'].set_visible(False)
枠線を全て消す spines = ['left', 'right', 'top', 'bottom']
[ax.spines[i].set_visible(False) for i in spines]
左の枠線色を変更 ax.spines['left'].set_color('#F5F5F5')
右の枠線色を変更 ax.spines['right'].set_color('#F5F5F5')
上の枠線色を変更 ax.spines['top'].set_color('#F5F5F5')
下の枠線色を変更 ax.spines['bottom'].set_color('#F5F5F5')
全ての枠線色を変更 spines = ['left', 'right', 'top', 'bottom']
[ax.spines[i].set_color('#F5F5F5') for i in spines]

軸(Axis)

逆引き コマンド
x軸の幅を取得 ax_left, ax_right = ax.get_xlim()
y軸の幅を取得 ax_bottom, ax_top = ax.get_ylim()
x軸の幅を変更 ax.set_xlim(left=0, right=100)
y軸の幅を変更 ax.set_ylim(bottom=100, top=500)
x軸を反転 ax.invert_xaxis()
y軸を反転 ax.invert_yaxis()

目盛り間の幅

逆引き コマンド
x軸を任意の等間隔目盛りに変更 ax.xaxis.set_major_locator(mpl.ticker.LinearLocator(3))
x軸を任意の倍数目盛りに変更 ax.xaxis.set_major_locator(mpl.ticker.MultipleLocator(100))
y軸を任意の等間隔目盛りに変更 ax.yaxis.set_major_locator(mpl.ticker.LinearLocator(3))
y軸を任意の倍数目盛りに変更 ax.yaxis.set_major_locator(mpl.ticker.MultipleLocator(100))

目盛りラベルの書式

目盛り/目盛りラベルの装飾

逆引き コマンド
x軸だけに適用 ax.tick_params(axis='x')
y軸だけに適用 ax.tick_params(axis='y')
両軸に適用(default) ax.tick_params(axis='both')
大目盛りだけに適用(default) ax.tick_params(which='major')
小目盛りだけに適用 ax.tick_params(which='minor')
大小の目盛りに適用 ax.tick_params(which='both')
目盛りを消す ax.tick_params(left=False, bottom=False, top=False)
目盛りラベルを消す ax.tick_params(labelleft=False, labelbottom=False)
目盛りの色を変更 ax.tick_params(color='#BDBDBD')
目盛りラベルの色を変更 ax.tick_params(labelcolor='#BDBDBD')
目盛りと目盛りラベルの色を変更 ax.tick_params(colors='#BDBDBD')
目盛りと目盛りラベルの感覚を変更 ax.tick_params(pad=10)
目盛りの長さを変更 ax.tick_params(length=6)
目盛りの幅を変更 ax.tick_params(width=1)
目盛りラベルの大きさを変更 ax.tick_params(labelsize=15)
目盛りラベルの傾きを変更 ax.tick_params(labelrotation=0)

テキストと注釈

タイトル

逆引き コマンド
図のタイトル fig.suptitle(t='タイトル')
座標軸のタイトル ax.set_title(label='タイトル', loc='center', pad=None)
x軸のタイトル ax.set_xlabel(xlabel='x軸のタイトル', labelpad=None)
y軸のタイトル ax.set_ylabel(ylabel='y軸のタイトル', labelpad=None)
タイトルの装飾(共通のパラメータ)
逆引き コマンド
文字の大きさ fontsize=15
文字色 color='#676767'
背景色 backgroundcolor='#1275B8'
透過率(0~1) alpha=0.7
回転 rotation=0
行間の幅 linespacing=0
文字揃え(水平方向) ha='center', {'left', 'right'}
文字揃え(垂直方向) va='center', {'top', 'bottom', 'baseline', 'center_baseline'}
重なり順 zorder=100

凡例

座標軸にテキスト

指定領域の塗りつぶし

補助線

図形

グラフ

時系列グラフ

下準備として、こんな感じのpandas.DataFrameを作成します。

df = pd.DataFrame(
    data = {
        'A': [464, 332, 447, 473, 376, 418, 328, 392, 327],
        'B': [409, 462, 540, 375, 412, 475, 425, 518, 526],
        'C': [306, 345, 368, 303, 485, 518, 504, 576, 401]
    },
    index = ['2019-07', '2019-08', '2019-09', '2019-10', '2019-11', '2019-12', '2020-01', '2020-02', '2020-03']
)
print(df)
#            A    B    C
# 2019-07  464  409  306
# 2019-08  332  462  345
# 2019-09  447  540  368
# 2019-10  473  375  303
# 2019-11  376  412  485
# 2019-12  418  475  518
# 2020-01  328  425  504
# 2020-02  392  518  576
# 2020-03  327  526  401

インデックスのデータの型がDataTimeになっていなければ、pandas.DataFrameto_datetimeメソッドを使用して、インデックスをDataTime型に変更させます。

df.index = pd.to_datetime(df.index)
print(df.index)
# DatetimeIndex(['2019-07-01', '2019-08-01', '2019-09-01', '2019-10-01',
#                '2019-11-01', '2019-12-01', '2020-01-01', '2020-02-01',
#                '2020-03-01'],
#               dtype='datetime64[ns]', freq=None)

fig, ax = plt.subplots()

x = df.index # x軸の値
y = df['A']  # y軸の値

# 時系列グラフをプロットする
ax.plot(x, y)

fig, ax = plt.subplots()

x = df.index

# 時系列グラフをまとめてプロットする
for _, item in enumerate(df.columns):
    ax.plot(x, df[item])

fig, ax = plt.subplots()

x = df.index

for _, item in enumerate(df.columns):
    ax.plot(x, df[item], linewidth=3)

fig, ax = plt.subplots()

x = df.index

for _, item in enumerate(df.columns):
    ax.plot(x, df[item], color='#BDBDBD')

from datetime import timedelta

fig, ax = plt.subplots()

x = df.index

for i, item in enumerate(df.columns):
    ax.plot(x, df[item])
    
    # グラフの右側にラベル(凡例)を表示する
    ax.text(
        x = x.max() + timedelta(days=3),
        y = df[item][-1],
        s = item,
        va = 'center'
    )

fig, ax = plt.subplots()

x = df.index



# カラム名で条件分岐して、カラーコードをセットする
color_dict = {i:'#6BCAB6' if i=='B' else '#BDBDBD' for i in df.columns}

# リスト内包表記で値に応じたカラーコードの順番に並び替えたリストを得る
colors = [color_dict[i] for i in color_dict]

for i, item in enumerate(df.columns):
    ax.plot(x, df[item], color=colors[i])
    
    # グラフの右側にラベル(凡例)を表示する
    ax.text(
        x = x.max() + timedelta(days=3),
        y = df[item][-1],
        s = item,
        va = 'center',
        color = colors[i] # 凡例とグラフの色を合わせる
    )

fig, ax = plt.subplots()

x = df.index

for _, item in enumerate(df.columns):
    ax.plot(x, df[item])
    
# x軸のtick labelを月だけにする('%-m'は0埋めなしの月表記)
ax.xaxis.set_major_formatter(mpl.dates.DateFormatter('%-m'))

fig, ax = plt.subplots()

x = df.index

for _, item in enumerate(df.columns):
    ax.plot(x, df[item])
    
# x軸のtick labelを月だけにする('%-m'は0埋めなしの月表記)
ax.xaxis.set_major_formatter(mpl.dates.DateFormatter('%-m'))

# y軸の幅を取得する
ax_bottom, ax_top = ax.get_ylim()

# x軸に垂直に引く、線の長さを調整する
# figsizeによって微調整が必要
y_coord_start = ax_bottom - (ax_top - ax_bottom)/10  # 始点
y_coord_end = ((ax_top - ax_bottom)/200) + ax_bottom # 終点(x軸と接している方)

# major tickのpositionを取得するために必要
fig.canvas.draw()

# 各年の最初の月の下に年(yyyy)を表示する
for index, (key, gr) in enumerate(df.groupby(x.year)):
    
    # 最初の月のインデックスを取得する
    i = np.where(x == gr.index[0])[0][0]
    
    # 座標を取得する
    pos = ax.get_xmajorticklabels()[i].get_position()
    
    # x軸の外側に垂直に線を引くx座標を調整する
    # 大体、pos[0]-15でいけるけど、一番最初だけ微調整が必要
    x_coord = pos[0]-6 if index==0 else pos[0]-15

    # 線と年を描画する
    ax.annotate(
        s='        {}'.format(key),        # 年
        xy=(x_coord, y_coord_end),         # 終点の位置
        xytext = (x_coord, y_coord_start), # 始点の位置
        color='dimgray',
        ha='center',
        va='top',
        arrowprops= {'arrowstyle':'-', 'color':'dimgray'}
    )

fig, ax = plt.subplots()

x = df.index

for _, item in enumerate(df.columns):
    ax.plot(x, df[item])

# y軸の目盛りを250から600までに設定し、100の倍数ずつ表示する
ax.set_ylim(250, 600)
ax.yaxis.set_major_locator(mpl.ticker.MultipleLocator(100))

TICK_COLOR = '#BDBDBD'       # グレー
CHART_MAIN_COLOR = '#6BCAB6' # 緑
CHART_SUB_COLOR = '#BDBDBD'  # グレー

from datetime import timedelta

"""
データフレーム
"""
df = pd.DataFrame(
    data = {
        'A': [464, 332, 447, 473, 376, 418, 328, 392, 327],
        'B': [409, 462, 540, 375, 412, 475, 425, 518, 526],
        'C': [306, 345, 368, 303, 485, 518, 504, 576, 401]
    },
    index = ['2019-07', '2019-08', '2019-09', '2019-10', '2019-11', '2019-12', '2020-01', '2020-02', '2020-03']
)

# インデックスを時系列データにキャストする
df.index = pd.to_datetime(df.index)


"""
時系列グラフをプロットする図を定義する
"""
fig, ax = plt.subplots(figsize=(6, 4), dpi=144)


"""
時系列グラフとしてプロットするデータ
"""
x = df.index


"""
カラーコードの設定
"""
# カラム名で条件分岐して、カラーコードの辞書(Key:カラム名、Value:カラーコード)を作成する
color_dict = {i:CHART_MAIN_COLOR if i=='B' else CHART_SUB_COLOR for i in df.columns}

# リスト内包表記で値に応じたカラーコードの順番に並び替えたリストを得る
colors = [color_dict[i] for i in color_dict]


"""
時系列グラフの重なり順の設定
"""
# カラム名で条件分岐して、重なり順の辞書(Key:カラム名、Value:重なり順)を作成する
# 数字が大きいほど上に描画される
zorder_dict = {i:2 if i=='B' else 1 for i in df.columns}

# リスト内包表記で値に応じた重なり順の順番に並び替えたリストを得る
zorders = [zorder_dict[i] for i in zorder_dict]


"""
時系列グラフをプロットする
"""
for i, item in enumerate(df.columns):
    ax.plot(x, df[item], linewidth=3, color=colors[i], zorder=zorders[i])
    
    # グラフの右側にラベル(凡例)を表示する
    ax.text(
        x = x.max() + timedelta(days=3),
        y = df[item][-1],
        s = item,
        fontsize = 12,
        va = 'center',
        color = colors[i] # 凡例とグラフの色を合わせる
    )


"""
フレームの設定
"""
# 枠線を消す
[ax.spines[side].set_visible(False) for side in ['left', 'right', 'top']]

# 枠線の色を変更する
ax.spines['bottom'].set_color(TICK_COLOR)    
    
# 目盛りラベルと目盛りの色を変更する
ax.tick_params(colors=TICK_COLOR)


"""
y軸の設定
"""
# Y軸の目盛りを消す
ax.tick_params(left=False)

# y軸の目盛りを250から600までに設定し、100の倍数ずつ表示する
ax.set_ylim(250, 600)
ax.yaxis.set_major_locator(mpl.ticker.MultipleLocator(100))

# y軸にグリッド線を表示する
ax.grid(axis='y', ls='--', lw=0.5, color=TICK_COLOR)    


"""
x軸の設定
"""
# x軸のtick labelを月だけにする('%-m'は0埋めなしの月表記)
ax.xaxis.set_major_formatter(mpl.dates.DateFormatter('%-m'))

# y軸の幅を取得する
ax_bottom, ax_top = ax.get_ylim()

# x軸に垂直に引く、線の長さを調整する
# figsizeによって微調整が必要
y_coord_start = ax_bottom - (ax_top - ax_bottom)/10  # 始点
y_coord_end = ((ax_top - ax_bottom)/150) + ax_bottom # 終点(x軸と接している方)

# major tickのpositionを取得するために必要
fig.canvas.draw()

# 各年の最初の月の下に年(yyyy)を表示する
for index, (key, gr) in enumerate(df.groupby(x.year)):
    
    # 最初の月のインデックスを取得する
    i = np.where(x == gr.index[0])[0][0]
    
    # 座標を取得する
    pos = ax.get_xmajorticklabels()[i].get_position()
    
    # x軸の外側に垂直に線を引くx座標を調整する
    # 大体、pos[0]-15でいけるけど、一番最初だけ微調整が必要
    x_coord = pos[0]-6 if index==0 else pos[0]-15

    # 線と年を描画する
    ax.annotate(
        s='        {}'.format(key),        # 年
        xy=(x_coord, y_coord_end),         # 終点の位置
        xytext = (x_coord, y_coord_start), # 始点の位置
        color=TICK_COLOR,
        ha='center',
        va='top',
        arrowprops= {'arrowstyle': '-', 'color': TICK_COLOR, 'lw': 0.5}
    ) 

横棒グラフ

下準備として、こんな感じのpandas.DataFrameを作成します。

df = pd.DataFrame(
    data = {'販売個数': [314, 365, 396, 436, 409, 424, 377]},
    index = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
)
print(df)
#    販売個数
# A   314
# B   365
# C   396
# D   436
# E   409
# F   424
# G   377

fig, ax = plt.subplots()

x = df['販売個数'] # x軸の値
y = df.index      # y軸の値

# 横棒グラフをプロットする
ax.barh(y=y, width=x)

# 販売個数カラムで降順ソート
df = df.sort_values(by=['販売個数'], ascending=False)
#    販売個数
# D   436
# F   424
# E   409
# C   396
# G   377
# B   365
# A   314

fig, ax = plt.subplots()

x = df['販売個数']
y = df.index

ax.barh(y=y, width=x)

# y軸を反転させる(配列の最初から描画されるため)
ax.invert_yaxis()

fig, ax = plt.subplots()

x = df['販売個数']
y = df.index

# colorパラメータにカラーコードを指定する
ax.barh(y=y, width=x, color='#6BCAB6')

fig, ax = plt.subplots()

x = df['販売個数']
y = df.index

# インデックス毎に任意のカラーコードを指定する
color_dict = {
    'A': '#BDBDBD',
    'B': '#15607A', # 青
    'C': '#BDBDBD',
    'D': '#BDBDBD',
    'E': '#6BCAB6', # 緑
    'F': '#BDBDBD',
    'G': '#BDBDBD'
}

# リスト内包表記で値に応じたカラーコードの順番に並び替えたリストを得る
colors = [color_dict[i] for i in color_dict]

# colorパラメータにカラーコードの配列を指定
ax.barh(y=y, width=x, color=colors)

辞書内包表記を使えば、条件に応じた動的な辞書も作成できます

どっちも同じ
# 辞書内包表記
color_dict = {i:'#15607A' if i=='B' else '#6BCAB6' if i=='E' else '#BDBDBD' for i in df.index}

# 普通の辞書の作成方法
color_dict = {
    'A': '#BDBDBD',
    'B': '#15607A', # 青
    'C': '#BDBDBD',
    'D': '#BDBDBD',
    'E': '#6BCAB6', # 緑
    'F': '#BDBDBD',
    'G': '#BDBDBD'
}

420を超えていれば緑色でプロット。350未満なら赤色でプロット。

fig, ax = plt.subplots()

x = df['販売個数']
y = df.index

ax.barh(y=y, width=x)

# 条件分岐で実際の値ごとにカラーコードを設定し、横棒グラフの色を変更する
# Good : 緑、 Bad : 赤
color_dict = {i:'#C71D1D' if i<350 else '#6BCAB6' if i>420 else '#BDBDBD' for i in x}

colors = [color_dict[i] for i in color_dict]
ax.barh(y=y, width=x, color=colors)

fig, ax = plt.subplots()

x = df['販売個数']
y = df.index

ax.barh(y=y, width=x)

# 水平方向の最大値を得る
hmax = x.max()

# 実際の値を表示する
for i, value in enumerate(x):
    ax.text(
        x = value + hmax*0.01,    # x座標。バーからちょっと離れたところに表示させる
        y = i,                    # y座標
        s = '{:,}'.format(value), # 表示する値。数値の場合、3桁区切りにしたほうが親切
        va = 'center',            # 垂直方向の整列
        ha = 'left'               # 水平方向の整列。内側に実際の値を表示したい場合は、rightにする
    )

fig, ax = plt.subplots()

x = df['販売個数']
y = df.index

ax.barh(y=y, width=x)

# 合計値を得る
total = x.sum()

hmax = x.max()
for i, value in enumerate(x):
    ax.text(
        x = value + hmax*0.01,             # x座標。バーからちょっと離れたところに表示させる
        y = i,                             # y座標
        s = '{:,.2%}'.format(value/total), # 表示する値。少数第2位のパーセンテージ表記
        va = 'center',                     # 垂直方向の整列
        ha = 'left'                        # 水平方向の整列。内側に実際の値を表示したい場合は、rightにする
    )

TICK_COLOR = '#BDBDBD'         # グレー
CHART_GOOD_COLOR = '#6BCAB6'   # 緑
CHART_BAD_COLOR = '#C71D1D'    # 赤
CHART_NORMAL_COLOR = '#BDBDBD' # グレー


"""
データフレーム
"""
df = pd.DataFrame(
    data = {'販売個数': [314, 365, 396, 436, 409, 424, 377]},
    index = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
)


"""
横棒グラフをプロットする図を定義する
"""
fig, ax = plt.subplots(figsize=(6, 4), dpi=144)


"""
横棒グラフとしてプロットするデータ
"""
x = df['販売個数'] # x軸の値
y = df.index      # y軸の値


"""
横棒グラフの色の設定
"""
# 条件分岐で実際の値ごとにカラーコードを設定し、横棒グラフの色を変更する
# Good : 緑、 Bad : 赤
color_dict = {i:CHART_BAD_COLOR if i<350 else CHART_GOOD_COLOR if i>420 else CHART_NORMAL_COLOR for i in x}

# リスト内包表記で値に応じたカラーコードの順番に並び替えたリストを得る
colors = [color_dict[i] for i in color_dict]


"""
横棒グラフをプロットする
"""
ax.barh(y=y, width=x, color=colors, height=0.75)


"""
フレームの設定
"""
# タイトルを付ける
fig.suptitle(t='製品D,Fは目標達成!!製品Aは未到達', color='#666666')

# サブタイトルを付ける
ax.set_title(label='製品毎の販売個数比較', loc='center', pad=None, color='#BDBDBD', size='small')

# 枠線を消す
[ax.spines[side].set_visible(False) for side in ['left', 'right', 'top', 'bottom']]

# 目盛り、目盛りラベルを消す
ax.tick_params(labelbottom=False, bottom=False, left=False)

# y軸を反転させる(配列の最初から描画されるため)
ax.invert_yaxis()


"""
y軸の設定
"""
# y軸ラベルを水平方向でセンター寄せする
for tick in ax.yaxis.get_major_ticks():
    tick.label1.set_horizontalalignment('center')

# 横棒グラフとラベルの距離を調整する
ax.tick_params(axis='y', pad=4)

# 目盛りラベルを装飾する
ax.tick_params(axis='y', labelcolor=TICK_COLOR, labelsize='small')


"""
実際の数値を横棒グラフの右に表示させる
"""
hmax = x.max()
for i, value in enumerate(x):
    ax.text(
        x = value + hmax*0.01,    # x座標。バーからちょっと離れたところに表示させる
        y = i,                    # y座標
        s = '{:,}'.format(value), # 表示する値。
        va = 'center',            # 垂直方向の整列
        ha = 'left',              # 水平方向の整列。内側に実際の値を表示したい場合は、rightにする
        size = 'small',           # 文字のサイズ
        color = colors[i]         # 文字の色をグラフと同じにする
    )

積上げ横棒グラフ

100%積上げ横棒グラフ