【初心者向け】基礎&実践プログラミング

初心者がつまづきやすいところ、最短で実力が身につく方法をお伝えします。

【Python】箱ひげ図の作り方

目的

  • Pythonを使って箱ひげ図(BoxPlot)を作成

1つの図に3群の結果をプロット

データ準備

行に各被験者、列にIDと各被験者のlabel、さらに各定量値が来るようにデータをまとめる。以下のデータは、その一部である。

この例では、以下のデータを「dataset.csv」として保存。

ID label AD ADfwe MD MDfwe RD RDfwe AK MK RK ICVF ISO AVF FA fafwe freewater MVF gratio OD T1 T2 R1 R2 PD
Sub001 0 1.139126 1.084 0.767302 0.602 0.566298 0.362 0.415519 0.570861 0.791092 0.590076 0.082388 0.377932 0.438481 0.614848 0.156918 0.288708 0.754112 0.191405 810.747168 79.703771 1.280526 12.822576 66.656261
Sub002 0 1.133603 1.082 0.77083 0.605 0.57187 0.366 0.416198 0.570608 0.787359 0.586764 0.081708 0.383601 0.433305 0.608671 0.157489 0.274517 0.767147 0.194536 857.855883 83.185407 1.244505 12.618935 67.648979
Sub003 0 1.156806 1.015 0.771779 0.611 0.579677 0.409 0.419005 0.575068 0.785805 0.609524 0.086635 0.374028 0.423782 0.531318 0.17062 0.31571 0.737025 0.198631 770.392887 75.561827 1.336872 13.477936 64.960388

ソースコード

- 各定量値について、各被験者ごとにプロット

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import os


def set_plot_config_save(ax, dataname, plottype):
    # config
    # ax.set_title(dataname)
    plt.gca().spines['right'].set_visible(False)
    plt.gca().spines['top'].set_visible(False)
    ax.set(xlabel='', ylabel=dataname)

    # save figure
    if not os.path.isdir('result_figure/' + plottype):
        os.makedirs('result_figure/' + plottype)
    plt.savefig('result_figure/' + plottype +
                '/HCvsMSvsNMO_' + dataname + '.png')
    plt.close()


def plot_result(all_df, dataname):
    # change label int to str
    all_df = all_df.replace({'label': {0: 'HC', 1: 'MS', 2: 'NMO'}})

    # plot 1 (boxplot)
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    sns.boxplot(x='label', y=dataname, data=all_df,
                showfliers=False, palette="Set1")
    set_plot_config_save(ax, dataname, 'boxplot')

    # plot 2 (boxplot with dot)
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    sns.boxplot(x='label', y=dataname, data=all_df,
                showfliers=False, palette="Set1")
    sns.stripplot(x='label', y=dataname, data=all_df, size=4,
                  dodge=True, jitter=True, color='black')
    set_plot_config_save(ax, dataname, 'boxplot_dot')

    # plot 3 (violinplot)
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    sns.violinplot(x='label', y=dataname, data=all_df,
                   showfliers=False, palette="Set1", split=True)
    set_plot_config_save(ax, dataname, 'violinplot')


# import file
all_df = pd.read_csv('dataset.csv')
# plot results
datanames = ['AD', 'ADfwe', 'MD', 'MDfwe', 'RD', 'RDfwe', 'AK', 'MK', 'RK', 'ICVF', 'ISO',
             'AVF', 'FA', 'fafwe', 'freewater', 'MVF', 'gratio', 'OD', 'T1', 'T2', 'R1', 'R2', 'PD']
for map in datanames:
    print("Plotting {}...".format(map))
    plot_result(all_df, map)

結果確認

for plottype in 'boxplot' 'boxplot_dot' 'violinplot';do
    montage result_figure/${plottype}/*png -geometry 640x480 -tile 5x5 result_figure/${plottype}/${plottype}_tile.jpg
done
Boxplot

f:id:AIProgrammer:20201113132557j:plain

Boxplot_with_dot

f:id:AIProgrammer:20201113132618j:plain

Violinplot

f:id:AIProgrammer:20201113132636j:plain

1つの図に3群の結果を各領域ごとにプロット

データ準備

行に各被験者、列にIDと各被験者のlabel、さらに各領域の各定量値が来るようにデータをまとめる。以下のデータは、その一部であり、1つの定量値に対して3領域分の計測値がある。

ID label ICVF_vSN ICVF_lSN ICVF_mSN ISOVF_vSN ISOVF_lSN ISOVF_mSN ODI_vSN ODI_lSN ODI_mSN FW_1000_vSN FW_1000_lSN FW_1000_mSN FW_10002000_vSN FW_10002000_lSN FW_10002000_mSN
Sub001 0 0.74727 0.740142 0.719879 0.172856 0.20309 0.18001 0.248277 0.087609 0.329636 0.312351 0.273095 0.300793 0.27786 0.205887 0.274283
Sub002 0 0.725333 0.751942 0.769737 0.157023 0.222715 0.201932 0.30647 0.172115 0.304513 0.330445 0.237088 0.293767 0.239366 0.281042 0.253842
Sub003 0 0.794968 0.695998 0.761458 0.220207 0.235809 0.213143 0.28446 0.145531 0.294445 0.285126 0.180409 0.27599 0.274388 0.263941 0.259132

ソースコード

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import os


def set_plot_config_save(ax, dataname, plottype):
    # config
    # ax.set_title(dataname)
    plt.gca().spines['right'].set_visible(False)
    plt.gca().spines['top'].set_visible(False)
    ax.set(xlabel='', ylabel=dataname)

    # save figure
    if not os.path.isdir('result_figure/' + plottype):
        os.makedirs('result_figure/' + plottype)
    plt.savefig('result_figure/' + plottype +
                '/HCvsMSvsNMO_' + dataname + '.png')
    plt.close()


def plot_result(all_df, dataname):
    # change label int to str
    all_df = all_df.replace({'label': {0: 'HC', 1: 'MS', 2: 'NMO'}})

    # plot 1 (boxplot)
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    sns.boxplot(x='label', y=dataname, data=all_df,
                showfliers=False, palette="Set1")
    set_plot_config_save(ax, dataname, 'boxplot')

    # plot 2 (boxplot with dot)
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    sns.boxplot(x='label', y=dataname, data=all_df,
                showfliers=False, palette="Set1")
    sns.stripplot(x='label', y=dataname, data=all_df, size=4,
                  dodge=True, jitter=True, color='black')
    set_plot_config_save(ax, dataname, 'boxplot_dot')

    # plot 3 (violinplot)
    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)
    sns.violinplot(x='label', y=dataname, data=all_df,
                   showfliers=False, palette="Set1", split=True)
    set_plot_config_save(ax, dataname, 'violinplot')


# import file
all_df = pd.read_csv('dataset.csv')
# plot results
datanames = ['AD', 'ADfwe', 'MD', 'MDfwe', 'RD', 'RDfwe', 'AK', 'MK', 'RK', 'ICVF', 'ISO',
             'AVF', 'FA', 'fafwe', 'freewater', 'MVF', 'gratio', 'OD', 'T1', 'T2', 'R1', 'R2', 'PD']
for map in datanames:
    print("Plotting {}...".format(map))
    plot_result(all_df, map)

結果

f:id:AIProgrammer:20201113133114j:plain

1つの図に3つの変数に対して4群の結果を3パターンプロット

データ準備

行に各被験者、列にIDと各被験者のlabel、さらに各定量値が来るようにデータをまとめる。以下のデータは、その一部である。

この例では、以下のデータを「dataset.csv」として保存。

ID SD05_lSN SD05_mSN SD05_vSN SD10_lSN SD10_mSN SD10_vSN SD15_lSN SD15_mSN SD15_vSN label
Sub001 260 553 253 136 448 154 74 269 43 1
Sub002 224 666 145 148 566 109 53 315 55 2
Sub003 344 422 324 218 303 273 53 130 186 3
Sub004 121 536 357 0 108 52 0 0 0 4

ソースコード

各定量値について、各被験者ごとにプロット

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns


def plot_result(all_df, dataname):
    # define subjects
    HC_df = all_df[all_df['label'] == 1]
    wICD_df = all_df[all_df['label'] == 2]
    wPDD_df = all_df[all_df['label'] == 3]
    woICDPDD_df = all_df[all_df['label'] == 4]

    # each dataframe
    HC_df_tg = pd.DataFrame({
        'lSNc': HC_df[dataname + '_lSN'],
        'vSNc': HC_df[dataname + '_vSN'],
        'mSNc': HC_df[dataname + '_mSN']
    })
    wICD_df_tg = pd.DataFrame({
        'lSNc': wICD_df[dataname + '_lSN'],
        'vSNc': wICD_df[dataname + '_vSN'],
        'mSNc': wICD_df[dataname + '_mSN']
    })
    wPDD_df_tg = pd.DataFrame({
        'lSNc': wPDD_df[dataname + '_lSN'],
        'vSNc': wPDD_df[dataname + '_vSN'],
        'mSNc': wPDD_df[dataname + '_mSN']
    })
    woICDPDD_df_tg = pd.DataFrame({
        'lSNc': woICDPDD_df[dataname + '_lSN'],
        'vSNc': woICDPDD_df[dataname + '_vSN'],
        'mSNc': woICDPDD_df[dataname + '_mSN']
    })


    # melt
    HC_df_tg_melt = pd.melt(HC_df_tg)
    wICD_df_tg_melt = pd.melt(wICD_df_tg)
    wPDD_df_tg_melt = pd.melt(wPDD_df_tg)
    woICDPDD_df_tg_melt = pd.melt(woICDPDD_df_tg)
    # add label
    HC_df_tg_melt['map'] = 'HC'
    wICD_df_tg_melt['map'] = 'wICD'
    wPDD_df_tg_melt['map'] = 'wPDD'
    woICDPDD_df_tg_melt['map'] = 'woICD-PDD'
    cat_df = pd.concat(
        [HC_df_tg_melt, wICD_df_tg_melt, wPDD_df_tg_melt, woICDPDD_df_tg_melt], axis=0)

    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1)

    # plot 1 (errorbar ?)
    # sns.barplot(x='variable', y='value', data=cat_df,
    #             hue='map', ci='sd', capsize=0.1, errwidth=1.5)

    # plot 2 (stripplot ?)
    # sns.barplot(x='variable', y='value', data=cat_df, hue='map', ci=None)
    # sns.stripplot(x='variable', y='value', data=cat_df, size=5, hue='map', dodge=True, jitter=True, linewidth=1, edgecolor='black')

    # plot 3 (boxplot)
    sns.boxplot(x='variable', y='value', data=cat_df,
                showfliers=False, hue='map', palette="Set1")
    # sns.stripplot(x='variable', y='value', data=cat_df, size=2, hue='map', dodge=True, jitter=True, color='black')

    # plot 4 (violinplt)
    # sns.violinplot(x='variable', y='value', data=cat_df, showfliers=False, hue='map', palette="Set1", split=True)

    # ylim=(0, 1)
    # ax.set(xlabel='', ylabel='', ylim=(0, 1))
    plt.gca().spines['right'].set_visible(False)
    plt.gca().spines['top'].set_visible(False)
    ax.set(xlabel='', ylabel=dataname)
    handles, labels = ax.get_legend_handles_labels()
    ax.legend(handles[0:4], labels[0:4])
    # ax.get_legend().remove()
    # ax.set_title(dataname)
    plt.savefig('ICD_' + dataname + '.png')
    # plt.show()


# import file
all_df = pd.read_csv('dataset.csv')

# plot results
datanames = ['SD05', 'SD10', 'SD15']
for map in datanames:
    plot_result(all_df, map)

結果

f:id:AIProgrammer:20201112121109p:plain



頑張れ!喝!!の代わりにB!ブックマークを押していただけるとただただうれしいです(^^)! ↓