🏄‍♂️

psychrochartを使ってPythonで湿り空気線図を書く

2021/12/01に公開

この記事は建築環境/設備 Advent Calendar 2021の1日目の記事です。

湿り空気線図の描画に関してはいろいろなツールがあるとは思いますが、Pythonで描画するpsychrochartというライブラリを紹介してみたいと思います。痒い所はあるのですが基本的なことはできると思います。

この記事のコードはGoogle Colabで動作確認をしています。こちらを参照してください。Open In Colabボタンを押せばGoogle Colabが開くと思います(Google ColabにはGoogleアカウントが必要です)。

1. psychrochartについて

psychrochartはMITライセンスで公開されている湿り空気線図描画用のライブラリで、内部でmatplotlibを使って描画しています。このライブラリはドキュメントが充実しているとはいえず、基本的にはサンプルノートブックやソースコードを読んで頑張る事になります。

2. psychrochartのインストール

インストールはpipで簡単にできます。

!pip install psychrochart

インストールが出来たら試しに湿り空気線図を書いてみましょう。

from psychrochart import PsychroChart

chart_default = PsychroChart('default')
ax = chart_default.plot()
ax.get_figure()

以下のような図が書けていれば良いです。

なお、'default'と指定した部分は以下が指定できます。この後説明しますが、自分で設定をカスタマイズして入力することもできます。

  • 'default'
  • 'ashrae'
  • 'interior'
  • 'minimal'
  • 'ashrae_ip'

'ashrae_ip'は単位系がSIでなくIP用であり単位変換のバグがありエラーが出て実行できないと思うので注意してください。。

3. ベースとなる湿り空気線図のスタイルの設定

湿り空気線図にデータをプロットしていく前に、ベースとなる図のスタイルの設定方法について説明します。ベースとなる湿り空気線図のスタイルにこだわりがなければ'ashrae'の設定(白黒の図)をそのまま使えばよいと思います。

スタイルデータの読み込みにはload_configという関数を使います。引数にはjsonファイルのパスかdictのデータを取るのですが、'default''ashrae''interior''minimal''ashrae_ip'のどれかを指定した場合にはライブラリ付属のjsonファイルを読み込んでくれます。

'default'のデータにおそらく全ての設定項目が書かれているので、読み込んでそれを編集してみます。読み込んだデータ(config_style)は設定項目のdictになっており、これからこのdictを編集して設定を変更していきます。

from psychrochart import load_config
config_style = load_config('default')

3.1 線と塗りつぶし領域の表示の有無の設定

まずは湿り空気線図の線と塗りつぶし領域の表示の有無を指定します。試しに比容積と湿球温度の線だけ描画してみます。

config_style['chart_params']['with_constant_dry_temp'] = False  # 乾球温度
config_style['chart_params']['with_constant_h'] = False         # 比エンタルピー
config_style['chart_params']['with_constant_humidity'] = False  # 絶対湿度
config_style['chart_params']['with_constant_rh'] = False        # 相対湿度
config_style['chart_params']['with_constant_v'] = True          # 比容積
config_style['chart_params']['with_constant_wet_temp'] = True   # 湿球温度
config_style['chart_params']['with_zones'] = False              # 塗りつぶし領域

chart = PsychroChart(config_style)
ax = chart.plot()
ax.get_figure()

確認したら設定を元に戻しておきましょう。

3.2 線の色と線種と線の太さの設定

次に線の色と線種と線の太さの設定です。psychrochartでは基本的にmatplotlibの設定方法が使えるので、ここで紹介する以外の入力方法でも設定できます。

  • 色は[R, G, B]でそれぞれ0.0-1.0の範囲の値を設定します。4つ目の要素として0.0-1.0の範囲の透過度を設定する事もできこの場合は0に近い値が透明度が高くなります。
  • 線種は連続線'-'、破線'--'、点線':'、一点鎖線'-.'の種類があります。
  • 線の太さは値が大きいほど太くなります。

以下は乾球温度の線の設定の例です。

config_style['constant_dry_temp']['color'] = [0.0, 0.0, 0.0]  # 線の色
config_style['constant_dry_temp']['linestyle'] = '-'          # 線種
config_style['constant_dry_temp']['linewidth'] = 0.5          # 線の太さ

描画できる線の種類は以下の通りです。

  • constant_dry_temp:乾球温度
  • constant_h:比エンタルピー
  • constant_humidity:絶対湿度
  • constant_rh:相対湿度
  • constant_v:比容積
  • constant_wet_temp:湿球温度
  • saturation:飽和曲線(湿度100%の線)

実用性はないですが、乾球温度を赤い太線、絶対湿度を青い太線にした例です。

確認したら設定を元に戻しておきましょう。

3.3 描画する線と数値の間隔の設定

以下のように、線をプロットする値や、線の数値ラベルをどこに表示するかなどを設定できます。

# 全体
# グラフの左右の端を乾球温度の範囲で指定
config_style['limits']['range_temp_c'] = [0, 50]            
# グラフの上下の端を絶対湿度の範囲で指定
config_style['limits']['range_humidity_g_kg'] = [0, 40]     

# 乾球温度
# 線の間隔
config_style['chart_params']['constant_temp_step'] = 1          
# 数値の間隔
config_style['chart_params']['constant_temp_label_step'] = 5    

# 比エンタルピー
# 線の両端の値
config_style['chart_params']['range_h'] = [5, 155]                              
# 線の間隔
config_style['chart_params']['constant_h_step'] = 5                             
# 表示する数値
config_style['chart_params']['constant_h_labels'] = [5, 25, 50, 75, 100, 125]   
# 数値の位置(0で左寄せ、1で右寄せ)
config_style['chart_params']['constant_h_labels_loc'] = 1.0                     

# 絶対湿度
# 線の間隔
config_style['chart_params']['constant_humid_step'] = 1                     
# 数値の間隔
config_style['chart_params']['constant_humid_label_step'] = 2               
# 上下端の数値を表示するか
config_style['chart_params']['constant_humid_label_include_limits'] = True  

# 相対湿度
# 線の値
config_style['chart_params']['constant_rh_curves'] = [10, 20, 30, 40, 45, 50, 55, 60, 70, 80, 90]   
# 表示する数値
config_style['chart_params']['constant_rh_labels'] = [20, 30, 40, 50, 60, 70, 80] 
# 数値の位置(0で左寄せ、1で右寄せ)                  
config_style['chart_params']['constant_rh_labels_loc'] = 0.85                     

# 比容積
# 線の両端の値
config_style['chart_params']['range_vol_m3_kg'] = [0.78, 0.98]          
# 線の間隔
config_style['chart_params']['constant_v_step'] = 0.02                  
# 表示する数値
config_style['chart_params']['constant_v_labels'] = [0.8, 0.9, 0.96]    
# 数値の位置(0で左寄せ、1で右寄せ)
config_style['chart_params']['constant_v_labels_loc'] = 1.0             

# 湿球温度
# 線の両端の値
config_style['chart_params']['range_wet_temp'] = [-10, 40]                   
# 線の間隔
config_style['chart_params']['constant_wet_temp_step'] = 5                         
# 表示する数値
config_style['chart_params']['constant_wet_temp_labels'] = [0, 5, 10, 15, 20, 25, 30, 35]   
# 数値の位置(0で左寄せ、1で右寄せ)
config_style['chart_params']['constant_wet_temp_labels_loc'] = 0.05               

3.4 図の大きさ、タイトルや軸の設定

まず、日本語表記のためにjapanize-matplotlibをインストールします。これを使わなくてもmatplotlibで日本語フォントを設定すれば大丈夫です。英語でよいならデフォルトのフォントでもよいと思います。

!pip install japanize-matplotlib

インストールしたら任意の位置でインポートするだけです。後からインポートした他のライブラリのデフォルト設定などで別の設定を上書きされる事もあるらしいので、うまくいかないときは最後にインポートすれば大丈夫だと思います。

import japanize_matplotlib

日本語フォントの設定ができたので、日本語を表示してみます。その他の図の大きさや軸の設定も以下の通りです。

# 全体の設定
# タイトルの設定
config_style['figure']['title'] = '空気線図'                        
# 図の大きさ
config_style['figure']['figsize'] = [16, 9]                         
# Falseだと左と上に線が追加されて図が囲まれる
config_style['figure']['partial_axis'] = True                       
# 図の中のグラフの位置[左, 下, 幅, 高さ] 
config_style['figure']['position'] = [0.0025, 0.075, 0.925, 0.875]  

# X軸の設定
# 軸の色、線種、太さ
config_style['figure']['x_axis'] = {'color': [0.2, 0.2, 0.2], 
                                    'linestyle': '-', 
                                    'linewidth': 2}                     
# ラベルの色、フォントサイズ
config_style['figure']['x_axis_labels'] = {'color': [0.2, 0.2, 0.2], 
                                           'fontsize': 10}              
# 目盛の色、方向
config_style['figure']['x_axis_ticks'] = {'color': [0.2, 0.2, 0.2],
                                          'direction': 'out'}           
# ラベルの文字
config_style['figure']['x_label'] = '乾球温度, $°C$'                   

# Y軸の設定
# 軸の色、線種、太さ
config_style['figure']['y_axis'] = {'color': [0.2, 0.2, 0.2], 
                                    'linestyle': '-', 
                                    'linewidth': 2}                     
# ラベルの色、フォントサイズ
config_style['figure']['y_axis_labels'] = {'color': [0.2, 0.2, 0.2], 
                                           'fontsize': 10}              
# 目盛の色、方向
config_style['figure']['y_axis_ticks'] = {'color': [0.2, 0.2, 0.2], 
                                          'direction': 'out'}           
# ラベルの文字
config_style['figure']['y_label'] = '絶対湿度, $g_w / kg_{da}$'         

なお、defaultの設定を読み込むとconfig_style['figure']['base_fontsize']という項目があるのですが、おそらく使っていません。

3.5 その他の設定

湿り空気線図を書く際の大気圧を設定することができます。

# 大気圧の設定(Noneなら標準大気圧)
config_style['limits']['pressure_kpa'] = None
# 指定高度での標準大気圧にする(pressure_kpaが設定されてされていればそちらを優先)
config_style['limits']['altitude_m'] = 0

描画している曲線は実は直線を細かくつなげているだけです。その間隔を設定できるので試しに大きい値にして描画してみると何をやっているか分かると思います。

# 直線近似する曲線の乾球温度での間隔(小さいほうが滑らか)
config_style['limits']['step_temp'] = 1.0   

4. 追加表示データの設定

4.1 領域の塗りつぶし

湿り空気線図の領域を指定して塗りつぶしてみます。

設定データの読み込みにはload_zoneという関数を使います。load_zoneの中身は実質load_configなのですが、引数なしで実行したときにzone用のデフォルトのテンプレートを読み込んでくれるところだけが違います。

from psychrochart import load_zones
config_zone = load_zones()
config_zone

デフォルトでは夏用と冬用の二つの快適範囲の領域を塗っています。config_zone['zones']が各領域の設定のdictのlistになっています。config_zone['zones'][n]でn+1番目の要素の設定をします。

まずは冬用の快適範囲を消して描画してみます。PsychroChartの引数にconfig_zoneを追加していることに注意してください。

config_zone['zones'].pop() # リストの末尾のデータを削除
chart = PsychroChart(config_style, config_zone)
ax = chart.plot()
ax.get_figure()

ゾーンを追加して描画してみます。15℃以下を青くしてみましょう。領域の名称を表示したくない場合はconfig_zone['zones'][1]['label'] = ''としておけば大丈夫です。

# 末尾にデータを追加
config_zone['zones'].append(config_zone['zones'][0].copy())

# 追加したデータの設定
config_zone['zones'][1]['label'] = 'Cold'         # 領域の名称
config_zone['zones'][1]['points_x'] = [0, 15]      # x座標(ここでは乾球温度)
config_zone['zones'][1]['points_y'] = [0, 100]      # y座標(ここでは相対湿度)
config_zone['zones'][1]['style'] = {'edgecolor': [0.0, 0.0, 0.8, 0.8],
                                    'facecolor': [0.0, 0.0, 0.8, 0.5],
                                    'linestyle': '--',
                                    'linewidth': 2} # 塗りつぶしの描画設定(辺の色、面の色、線種、線の太さ)
config_zone['zones'][1]['zone_type'] = 'dbt-rh'     # 座標位置の指定タイプ、他に'xy-points'が指定できる

4.2 点と線のプロット

湿り空気線図に点や線をプロットするにはchart.plot_points_dbt_rhという関数を使います。この関数は珍しくdoctringがしっかり書かれているのでhelpを確認してみるとよいと思います。JupyterだとPsychroChartをimportした状態でPsychroChart.plot_points_dbt_rh?とセルに入力して実行すれば確認できます。ここで紹介していない機能もあります。
まずは点を一つ書きます。chart.plot_points_dbt_rhの位置に注意してください。設定のxyの項目が乾球温度と相対湿度です。

# 点を一つだけプロット(系列の名前,色とマーカーの種類とサイズ、乾球温度と相対湿度を指定)
point = {'point1': {'label': 'point1',
                       'style': {'color': [0.85, 0.0, 0.0, 0.5],
                                 'marker': 'o', 
                                 'markersize': 10},
                       'xy': (26, 60)}}

# 描画して設定を確認
chart = PsychroChart(config_style, config_zone)
ax = chart.plot()
chart.plot_points_dbt_rh(point)
ax.get_figure()

次に、二つの点とそれらを結ぶ線を書きます。chart.plot_points_dbt_rhの引き数にconnectorsを追加していることに注意してください。なお、線を引いたときに幅50の太線でなぞる仕様になっており、元のソースを書き換えないとこの線は消せないと思います。

# 二つの点をそれらをつなぐ線をプロット(系列の名前,色とマーカーの種類とサイズ、乾球温度と相対湿度を指定)
points = {'pointa': {'label': 'pointA',
                       'style': {'color': [0.855, 0.004, 0.278, 0.8],
                                 'marker': 'X', 
                                 'markersize': 15},
                       'xy': (31.06, 32.9)},
          'pointb': {'label': 'pointB',
              'style': {'color': [0.573, 0.106, 0.318, 0.5],
                        'marker': 'x', 
                        'markersize': 10},
              'xy': (36.7, 25.0)}}
# 点をつなぐ線(始点と終点、線の名前、線の色と太さと種類を指定)
connectors = [{'start': 'pointa',
               'end': 'pointb',
               'label': 'line1',
               'style': {'color': [0.573, 0.106, 0.318, 0.7],
                         "linewidth": 2, 
                         "linestyle": "-."}}]

# 描画して設定を確認
chart = PsychroChart(config_style, config_zone)
ax = chart.plot()
chart.plot_points_dbt_rh(points, connectors)
ax.get_figure()

複数の点データを一度に描画したい場合はnumpyのarrayデータを入力します。今回は適当なデータを生成してプロットしてみます。points_styleに点のスタイルを設定していますが、書式はmatplotlibのAxes.scatterの設定そのままで、ここではサイズ、透過度、色だけを設定しています。

# 複数の点を一度にプロット
import numpy as np

n = 1000 # データの個数
temp_array = np.random.rand(n)*40-5 # 乾球温度をランダムにn個作成
humid_array = np.random.rand(n)*100 # 相対湿度をランダムにn個作成

points_array = {'points_series_name': (temp_array, humid_array)}
points_style = {'s': 9, 'alpha': 0.8, 'color': 'darkorange'}

chart = PsychroChart(config_style, config_zone)
ax = chart.plot()
chart.plot_points_dbt_rh(points_array, scatter_style=points_style)
ax.get_figure()

細い三角形を描画できるplot_arrows_dbt_rhという関数も使えます。
chart.plot_points_dbt_rhの代わりに線を引くのに使ってもよいかもしれません。ただ、"arrowstyle"が"wedge"で固定になっているのと、線の太さは変えれず透過度は0.6で固定になっているようなので物足りなさはあると思います。以下に緑の横線を書いているのですが見えづらいですね。

# 矢印(細い三角形)のプロット(矢印の名前、色、乾球温度と相対湿度)
points_pair =  {'wedgea': {'label': 'wedgeA',
                       'style': {'color': [0.0, 1.0, 0.0]},
                       'xy': [(25.0, 60), (18, 95)]}}
chart = PsychroChart(config_style, config_zone)
ax = chart.plot()
chart.plot_arrows_dbt_rh(points_pair)
ax.get_figure()

他にplot_vertical_dry_bulb_temp_lineという関数がありますがここでは説明を割愛します。公式のサンプルノートブックに使い方の例があります。簡潔に言うと乾球温度を指定して縦線を引くときに線にラベルを添えてくれるものになっています。

4.3 凡例の追加

凡例を表示するにはchart.plot_legendを使います。試しに二つの点とそれらを結ぶ線を追加して凡例を確認してみましょう。

chart = PsychroChart(config_style, config_zone)
ax = chart.plot()
chart.plot_points_dbt_rh(points, connectors)

# 凡例の設定(マーカーのサイズ、枠の有無、フォントサイズ、凡例の間隔)
chart.plot_legend(markerscale=.7, frameon=False, fontsize=16, labelspacing=0.5)
ax.get_figure()

ベースの湿り空気線図の凡例が邪魔なので消します。

# 凡例のラベル名、空文字にしておくと凡例が表示されない
config_style['chart_params']['constant_temp_label'] = ''
config_style['chart_params']['constant_h_label'] = '' 
config_style['chart_params']['constant_humid_label'] = '' 
config_style['chart_params']['constant_rh_label'] = '' 
config_style['chart_params']['constant_v_label'] = '' 
config_style['chart_params']['constant_wet_temp_label'] = '' 

なお、複数のデータや細い三角形の凡例の入れ方はよく分かりませんでした。複数のデータの方は別途同じ色でデータを一つプロットしてしまえばよいかもしれません。

5. 画像ファイルの書き出し

画像ファイルの出力はpngやsvgに対応しています。以下のようにpngの場合はフォーマットを指定しなくてもよいです。

png_filepath = './img.png'
chart.save(png_filepath)
svg_filepath = './img.svg'
chart.save(svg_filepath, format='svg')

保存したら以下のようにしてダウンロードします。

# ファイルのダウンロード
from google.colab import files
files.download(png_filepath)
files.download(svg_filepath)

6. 最後に

一通りpsychrochartの使い方を確認しました。湿り空気線図は自分でグラフを描こうとすると結構面倒なので活用していただけたらと思います。線を引く機能が物足りなかったり、もっと自由な図形を書き込みたい事もあるかもしれませんが、ソースコードを読み込めば良い方法が分かるかもしれません。(__init__.pyPsychroCurvePsychroCurvesの二つのクラスを読んでいるのでこれらを使う方法があったりする?)ただ、オープンソースなのでpsychrochartをベースに自分で自由にコードを付け足したり改変しても良いと思います。

Discussion