簡単な棒グラフを作るフリーのWebサイトを探していても良いものが見つからなかったので、ブラウザ上で無料で使えるPythonの実行環境を用いた棒グラフ作成を行った時のメモ

下手に学術論文用と銘打つと分野で作法の違いがあると思うので、ここで言う論文用とは、明瞭、美麗、シンプルで人を選ばず受け手に必要な情報を分かりやすく伝える配慮をした構成ということでご容赦ください。

大学のレポートや論文で図を作成する際に、口酸っぱく指摘されてきた点を盛り込み、OriginProなどの"有料ソフトと比較しても遜色ない!"を目指して作成したつもりです。


目標:
無料の手軽なPythonの実行環境であるColaboratory上で、データ可視化のためのライブラリである「matplotlib」や「Seaborn」を用いてOriginProなどの定番グラフ作成ソフト並みのクオリティを目標とした、シンプルで明確に情報を伝えられる「棒グラフ」を作図する

前提条件:
Googleアカウントにログイン可能

検証環境:
Google Colaboratory


※ほぼ趣味で書いている本サイト用のメモとして置いているものなので、実際に以下のテンプレートを使う場合はTPOを考え、自己責任でお願いします。



生成できる図の例



↑ クリックで拡大

棒状のグラフといっても
  • 一般的な棒グラフ(barplot,countplot)
  • 度数分布を表すヒストグラム(distplot)
などがありますが、今回はあるx値の時yの値が決まっている一般的な棒グラフを対象としています。ある階級ごとにyの値がきまる度数分布を表すヒストグラムはいつか別途まとめます。

また、X軸の値が決まれば、対応するY軸の値がただ1つ決まるタイプの棒グラフ(上図:下)だけでなく、同じ条件に対して、いくつか比較したい値がある場合、条件ごとに比較するような複数データ区分を持つデータに対して有効な、棒グラフ(上図:上)も生成可能です。



棒グラフ作成テンプレート


細かい要素の解説を挟むより、完成品のテンプレートをまず出します。

以下のコードを丸々Colab環境にコピーして実行すれば、多少環境によって変わることもあるらしいですが、上図の左上のグラフが描画されるはずです。

ライブラリインポート


matplotlibを日本語対応させる
!pip install japanize-matplotlib
必要なライブラリ等のインポート
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib as mpl
from matplotlib.ticker import ScalarFormatter
import matplotlib.ticker
import japanize_matplotlib
import warnings
warnings.filterwarnings('ignore')
import pandas as pd
import numpy as np
import sys
sns.set()  # Seabornのデフォルトスタイル使用
使用している主なライブラリ
  • matplotlib
  • seaborn
  • pandas
  • numpy

データの用意


今回は、適当なデータを手打ちで入力していますが、ColaboratoryはGoogle Driveと連携させてデータを読み込めるので、任意のcsvデータなどをpandasデータフレームに入力するなどして使ってください。

1~3行目のbool値の設定は、複数区分データを対象としたグラフと、1区分データを対象としたグラフの切り替えをしている箇所です(上図でいうところの上と下のグラフ)。その後、この値でコードを条件分岐していますが、必要ない箇所は消してしまったほうが、実行するときには流れが分かりやすいと思います。
# 1区分データ(table)と複数区分データ(division_table)対応の切り替え
division_table = True  # True or Falseで切り替え
table = not division_table
#-----------------------------------------------------------------
# 軸の名前
x_axis_name = "x_軸ラベル"
y_axis_name = "y_軸ラベル"
division_name = "区分名"
# 区分の名前
division_A = "区分A"
division_B = "区分B"
#データ用意(適当)
x_axis_div = ['1,000','2,000','3,000','4,000','1,000','2,000','3,000','4,000']
x_axis = ['1,000','2,000','3,000','4,000','5,000','6,000','7,000','8,000']
y_axis = [58095079,446530510,1546659079,3902563672,291673784,2460268247,8084783624,18908048837]
division = [division_A,division_A,division_A,division_A,division_B,division_B,division_B,division_B]
# 複数区分データ用データフレーム作成
if(division_table == True):
  # 表のサイズ決定
  row_size = 8    # 行
  column_size = 3 # 列
  matrix_size = row_size * column_size  # 行列サイズ
  # データフレーム作成
  df = pd.DataFrame(np.arange(matrix_size).reshape(row_size, column_size))
  df.columns=[x_axis_name, division_name, y_axis_name]  # 列の名前設定
  df.index=list(range(0, row_size, 1))  # 行のインデックス名設定
  df[x_axis_name] = x_axis_div
  df[division_name] = division
  df[y_axis_name] = y_axis
  print(df.head(5))
# 1区分データ用データフレーム策税
if(table == True):
  # 表のサイズ決定
  row_size = 8    # 行
  column_size = 2 # 列
  matrix_size = row_size * column_size  # 行列サイズ
  # データフレーム作成
  df = pd.DataFrame(np.arange(matrix_size).reshape(row_size, column_size))
  df.columns=[x_axis_name, y_axis_name] # 列の名前設定
  df.index=list(range(0, row_size, 1))  # 行のインデックス名設定
  df[x_axis_name] = x_axis
  df[y_axis_name] = y_axis
  print(df.head(5))
#-----------------------------------------------------------------
# データの読み込みを行いデータフレームを作成する場合
# df = pd.read_csv('data.csv')

グラフの描画


ここが話の本題のメインのテンプレートと呼べる箇所です。
fig = plt.figure(figsize=(10, 8)) # グラフサイズ

sns.set_style('ticks')            # 枠線表示
japanize_matplotlib.japanize()    # 日本語文字化け防止

# 複数区分データ図の描画
if (division_table == True):
  ax1 = sns.barplot(x=x_axis_name, y=y_axis_name, data=df, hue=division_name,
              palette="hls", alpha=0.9, edgecolor="black", ci=None, orient="v")
# 1区分データ図の描画
if (table == True):
  ax1 = sns.barplot(x=x_axis_name, y=y_axis_name, data=df,
              palette="hls", alpha=0.9, edgecolor="black", ci=None, orient="v")

# 基本設定(必要に応じて)
ax1.yaxis.set_major_formatter(plt.FuncFormatter(lambda x,       # Y軸目盛の三桁カンマ設定
                                                loc: "{:,}".format(int(x))))
ax1.yaxis.set_major_formatter(ScalarFormatter(useMathText=True))# Y軸目盛の10のべき乗表記
ax1.set_facecolor('white')  # 背景色
if (division_table == True):
  ax1.legend(fontsize=18, loc="best", facecolor='white',  # 凡例表示
           framealpha=1.0, frameon=True, borderaxespad=1.5)
ax1.set_xlabel(x_axis_name, fontsize=18)  # X軸ラベルの表示
ax1.set_ylabel(y_axis_name, fontsize=18)  # Y軸ラベルの表示
ax1.set_axisbelow(True) # グリッドを後ろに設定
ax1.grid(color='black', linestyle='dotted', linewidth=1.5); #グリッド表示
# ax1.set_ylim(0.00, 19100000000) # y軸範囲指定
ax1.set_title("図1 テンプレート表示例", fontsize=19, loc="center", y=-.17)  # タイトル
# ax1.yaxis.set_major_formatter(plt.FormatStrFormatter('%.3f')) # 小数点以下任意桁まで表示
ax1.tick_params(which='major', labelsize=13) # 軸目盛フォントサイズ
# ax1.set_yscale('log') # 対数グラフ
※削除したり編集したりしてご使用ください。
※環境によって多少動作が変わることがあるそうです。

出力結果:



各設定項目の詳細


ここからは、上記テンプレートに従って詳細な設定項目について見ていきます。

barplotによる棒グラフ描画


Seabornを用いて棒グラフを描画する際には「Barplot」と「Countplot」があります。
  • Barplot:与えられたデータ配列の平均値と誤差範囲をエラーバーとして出力
  • Countplot:データの頻度(個数カウント)を集計して出力
今回はBarplotを用いて棒グラフを描画しています。

コード例:
ax1 = sns.barplot(x=x_axis_name, y=y_axis_name, data=df, hue=division_name,
              palette="hls", alpha=0.9, edgecolor="black", ci=None, orient="v")

設定項目例設定例説明
x”dfの列名"X軸に設定する項目
y"dfの列名"Y軸に設定する項目
datadfプロットするデータセット
hue "dfの列名"データ区分を設定する項目
palette "hls", "Set2", "Paired"...カラーパレット
alpha0~1棒の透明度
edgecolor"black", 0.5棒の縁色
ciNoneエラーバーの表示設定
orient"v", "h"棒グラフの向き


要素表示設定


必要な項目の表示/非表示を切り替える設定項目

グラフの枠線表示


基本的にseabornのデフォルト設定では以下の項目の通りにグラフに枠線がついてなかったりします。
  • darkgrid:背景暗、グリッドあり(デフォルト)
  • dark:背景暗、グリッドなし
  • whitegrid:背景白、グリッドあり
  • white:背景白、グリッドなし
  • ticks:背景白、軸のみグリッドあり
なので、明示的にスタイルを指定してやることでグラフの枠線を表示してやりましょう。

コード例:
sns.set_style('ticks')
これをコードのどこにでも入れれば良いというわけでもなく、場所によっては設定が上書きされたりするので、挿入場所は気を付ける必要があります。


凡例の表示


明示的に凡例の表示を指示します。また、凡例の詳細な設定も同時に行います。

コード例:
ax1.legend(fontsize=18, loc="best", facecolor='white',
           framealpha=1.0, frameon=True, borderaxespad=1.5)

設定項目例設定例説明
fontsize
18フォントのサイズを数値で指定
loc”best”, "upper right", "lower left"凡例の位置の調整
facecolor"white"背景色
framealpha0~1凡例の透過度
frameonTrue / False凡例のフレームのON/OFF
borderaxespad1.5 余白の設定
fancyboxFalseフレームの角
edgecolor"black"凡例の枠色

軸ラベルの表示


無料のオンライン棒グラフ作成サイト等では、探した限りなぜかすべての軸にラベルの付けられないものばかりでしたが、各軸のラベルも必須項目でしょう。以下でX軸とY軸それぞれに任意のラベルを設定します。

コード例:
ax1.set_xlabel(x_axis_name, fontsize=18)
ax1.set_ylabel(y_axis_name, fontsize=18)

設定項目例設定例説明
第1引数"軸の名前"軸の名前を明示的に入力
fontsize18フォントサイズを数値で指定

グリッドの表示


グリッド(目盛線)を表示させると同時に、詳細な設定を行います。

コード例:
ax1.grid(color='black', linestyle='dotted', linewidth=1.5)

設定項目例設定例説明
color'black'グリッドの色
linestyle'dotted', 'solid', '-' 線の種類
linewidth1.5線の太さを数値で指定

グリッドを後ろに移動


なぜか上記でグリッドを表示させるとグリッドが凡例の上や、棒グラフの上に表示され、邪魔だったのでグラフ中の最背面にグリッドを移動させます。

コード例:
ax1.set_axisbelow(True)

グラフタイトル表示


後から文書中で表記するため、図にタイトルを入れ込みたくない方もいると思うので、タイトルがいらない場合は、この項目を削除してください。

コード例:
ax1.set_title("図1 テンプレート表示例", fontsize=19, loc="center", y=-.17)

設定項目例設定例説明
第1引数"図 ○○○○"任意のグラフタイトル入力
fontsize19フォントサイズを数値で指定
loc"center", "right"タイトルの左右位置指定
y-.17タイトルの上下位置指定


要素サイズ調整


各項目や要素のサイズ的な見栄えを整える設定項目

グラフサイズ


グラフそのものの大きさの設定

コード例:
fig = plt.figure(figsize=(10, 8))

軸ラベル目盛数値フォントサイズ


軸の数値のフォントサイズを設定する。

コード例:
ax1.tick_params(which='major', labelsize=13)

設定項目例設定例説明
which'major','minor'主目盛り/補助目盛りの選択
labelsize13軸ラベルのサイズを数値で設定


微調整項目


その他、あると何かと便利な設定項目

日本語表記の対応


なにもしないと環境で扱っているフォントの都合上、日本語は四角に文字化けを起こすので日本語で軸ラベルや凡例、タイトルを入れたいような場合、matplotlibを日本語に対応させる必要がある。

import:
!pip install japanize-matplotlib
コード例:
import japanize_matplotlib
japanize_matplotlib.japanize()
上記をグラフ描画の前に設定する。位置によっては、設定を上書きされたりするので使用には気を付ける必要がある。

軸ラベルメモリ数値の3桁カンマ表記


数値は千の位(3桁)でカンマによって区切られていたほうが、数値の視認性が良いので明示的に3桁でカンマが入るよう設定します。

コード例:
ax1.yaxis.set_major_formatter(plt.FuncFormatter(lambda x,
                                                loc: "{:,}".format(int(x))))

目盛数値の10のべき乗表記


軸の目盛に桁数の長すぎる数値が使われていると、非常にデザイン性と判読性の点で問題となります。デフォルトで使われる「le10」表記でもいいのですが、分かりにくいので「10^n」表記に変えます。

コード例:
ax1.yaxis.set_major_formatter(ScalarFormatter(useMathText=True))

背景色


Seabornのスタイルを設定したのでいらない気もしますが、任意の色に変えることも可能になるように、一応明示的に指定しておきます。

コード例:
ax1.set_facecolor('white')

軸目盛の任意小数点桁表記


小数点以下の任意の桁数まで表示する設定。以下は小数点以下3桁まで表示する。

コード例:
ax1.yaxis.set_major_formatter(plt.FormatStrFormatter('%.3f'))

軸目盛の範囲


設定された軸の範囲でグラフを表示したい場合の設定。最小値と最大値を設定する。

コード例:
ax1.set_ylim(0, 1000)
第3引数に目盛の幅を設定できる。

片対数グラフ化


今回の例に挙げているグラフのように、最大値と最小値との間で差が大きく、小さな値付近のデータの変化や差が潰れて見えにくい場合、片対数グラフに切り替えることで小さな値付近での値の変化が見やすくなる。

軸を対数にするには、以下の設定を施します。対数グラフにすると原点0は表示されなくなります。

コード例:
ax1.set_yscale('log')

補足


実装したかったのですがめんどくさくなったテンプレートが複雑になりそうだったため、あきらめた機能について、識者の方の記事を参考として載せておきます。

波線で軸破断:
https://qiita.com/code0327/items/820cc9e239736ed33fdd

2軸グラフ等は、また別途記事にまとめます。




参考:
https://seaborn.pydata.org/index.html
https://qiita.com/Fortinbras/items/50500423888ef21429be
https://qiita.com/skotaro/items/7fee4dd35c6d42e0ebae
https://qiita.com/quyasys/items/c144623fb709fd83259e

以上、お疲れさまでした。

このエントリーをはてなブックマークに追加
コメントを閉じる

コメント

コメントフォーム
記事の評価
  • リセット
  • リセット