YutaKaのPython教室

Python の文法やライブラリ、API、環境構築について画像・動画・ソースコード付きで徹底解説!

【コピペOK!】改行を削除するPythonスクリプト

pyhonでテキストファイルを読み込んだ時に、改行コード\nが残って困ってしまうことがありますね。

今回はテキストデータから改行コードを削除する方法を3つ紹介します。

  • 文字列の置換メソッド:replace()で削除
  • reモジュールの置換メソッド:re.subで削除
  • 文字列の末尾削除メソッド:rstrip()で削除

応用例として、クリップボードにコピーしたテキストから、改行コードを削除する効率化技も紹介しています。

改行コードの削除方法

改行を含むテキストデータを読み込むと、改行は改行コード"\n"として読み込まれます。

例えば、次のような改行のあるテキストファイルがあるとします。

'一行目'
'二行目'
''
'三行目'

このとき改行を明示的に\nで表現すると次のようになります。

'一行目\n'
'二行目\n'
'\n'
'三行目'

改行のあるファイルをそのまま読み込むと、次のように改行が\nとして読み込まれます。

with open("改行のあるテキスト.txt", "r", encoding="UTF-8") as f:
    text = f.read()

text
# '一行目\n二行目\n\n三行目'

状況によっては、この改行コード\nを削除したい場合がありますね。

今回は、この改行コートどの削除方法を次の2種類で紹介します。

  • テキスト全体から改行を一括削除
  • テキストを一行ずつ読みながら削除 次のような、改行のあるテキストファイルを例に実行例をみてみましょう。
'一行目\n'
'二行目\n'
'\n'
'三行目'

テキスト全体から改行を一括削除

一括で改行を削除する場合は、改行コード\nを空の文字列""で置換します。

pythonは置換の方法が豊富で、どれを使えばいいか困りますが、結果は同じなので好きな方法を選びましょう。

  • 文字列の置換メソッド:文字列.replace("\n", "")
  • reモジュールの置換メソッド:re.sub("\n", "", 文字列)

改行を削除するのでなく、空白の文字列に置換したい場合は、" "で置換すればOKです。

まずは、文字列の.replace()メソッドの実行例を紹介します。

# 改行を削除
text.replace("\n", "")
# '一行目二行目三行目'

# 改行を空白に変換
text.replace("\n", " ")
# '一行目 二行目  三行目'

次に、reモジュールre.sub()関数の実行例を紹介します。

import re

# 改行を削除
re.sub("\n", "", text)
# '一行目二行目三行目'

# 改行を削除
re.sub("\n", " ", text)
# '一行目 二行目  三行目'

一行ずつ読みながら改行処理

テキストファイルを一行ずつ読み込んで、末尾の改行を削除する例を紹介します。

末尾の改行を削除する場合は、文字列のメソッドrstrip()を使用すると良いですね

  • 文字列.rstrip(XXX)文字列の末尾のXXXを削除
    • 文字列.rstrip()のように引数を省略すると、末尾の空白を削除

改行を削除せずに一行ずつ読み込んでみます、

with open("改行のあるテキスト.txt", "r", encoding="UTF-8") as f:
    for line in f:
        print(repr(line)) # 改行の存在を見やすいようにreprで改行を"\n"で表現

# '一行目\n'
# '二行目\n'
# '\n'
# '三行目'

.rstrip(\n)で改行を削除しながら、一行ずつ読み込んでみます。

with open("改行のあるテキスト.txt", "r", encoding="UTF-8") as f:
    for line in f:
        print(repr(line.rstrip("\n"))) # 改行の存在が見やすいようにreprで改行を\nで表現
        
# '一行目'
# '二行目'
# ''
# '三行目'

続いて、read.lines()で行をリストで受け取った場合の改行処理を紹介します。

with open("改行のあるテキスト.txt", "r", encoding="UTF-8") as f:
    lines = f.readlines() # テキストファイルの改行を要素とするリストで読み込み

print(lines)
# ['一行目\n', '二行目\n', '\n', '三行目']

リスト内の要素が改行を持っているので、各要素のrstrip()メソッドを実行します。

各要素のメソッドを使用する場合は、次の2つの方法があります。

  • リスト内包表記で処理
  • map()関数で処理
# リスト内包表記で処理
[line.rstrip("\n") for line in lines]
# ['一行目', '二行目', '', '三行目']

# map()関数で処理
list(map(lambda l: l.rstrip("\n"), lines))
# ['一行目', '二行目', '', '三行目']

クリップボードのテキスト改行処理

pyperclipモジュールを使用すると、クリップボードのテキストをコピペできます。

これを応用すると、コピーしたテキストの改行を削除して、貼り付けという作業を半自動化することができます。

import pyperclip

# 例えば"一行目\n二行目"をコピーしているとする
src = pyperclip.paste() # クリップボードからテキスト読み込み
res = src.replace("\n","") # 改行削除
pyperclip.copy(res) # クリップボードにテキストを戻す

print(src)
# 一行目二行目

pyperclipモジュールの詳しい使い方は、次の記事で紹介しています。

≫pyperclipの使い方:おススメ置換の自動化スクリプト付き!
pyperclipの使い方を、おススメ実例付きで紹介します!pyperclipは、簡単に言うと、普段手作業で行っているコピペをpythonスクリプトに組み込んじゃおう!というモジュールです。非常にシンプルな機能ゆえに、応用しだいでは絶大な業務効率化の効果を発揮します!
www.yutaka-note.com/entry/pyperclip
 

Pythonで作業を効率化する方法

今回はipynbmarkdownに変換する方法を紹介しました。

pythonを使えば、簡単なスクリプトで作業を劇的に効率化することも可能です!

pythonの効率化関係で言えば、次の記事で紹介しているような本が自動化の本がおススメです。

≫【レビュー】退屈なことはPythonにやらせよう | 単純作業は自動化
名著「退屈なことはPythonにやらせよう 」をレビュー!単純作業を自動化して、自分が本当にしたいことのために時間を確保していこう!所要時間やできるようになったことを紹介!この本を参考にして作成した、自作自動化スクリプトも紹介しています!
www.yutaka-note.com/entry/python_jido
 
≫【レビュー】Python自動処理 全部入り。 | 即効性重視!Pythonによる自動化事例集!
今回は、Pythonの作業自動処理の解説本『Python自動処理全部入り』をレビュー!この本は、特定の作業に特化した即効性の重視の自動化解説本です。よくある作業から自動化しやすい作業を抽出して、それらの自動化を集中的に解説した本という印象です。本の中に自分のニーズに合った自動化処理が見つかれば、その日からすぐ使える事例集のような印象です。
www.yutaka-note.com/entry/python_jido_zenbu
 

【図解で解説】白色部分を透明化処理|Python×OpenCV

Pythonの画像処理ライブラリOpenCVを使用して、画像の白色部分を透明化する方法を紹介します。

正直言って、白色部分を透明化処理するだけであれば、ウェブ上に無料のソフトがあります。

しかし、自分でスクリプトを書けば、複数ファイルの自動処理など、応用の幅が広がります

とはいえ、いざやってみようとすると難しいものです。

そこで今回は、OpenCVを使用した白色部分の透明化処理について紹介します。

透明化処理とは?

画像データは、BGR(青緑赤)の3つのデータの重ね合わせで構成されます。

しかし、BGRに加えて透明度、アルファチャンネル(Alpha)を併せ持つ画像もあります。

透明度を持つ画像は、BGRA(青緑赤透明度)の4つのデータの重ね合わせです。

次の画像は背景が、白色と透明の場合の違いを表しています。

左側の元画像は同じ見た目ですが、他の画像に重ねた時に透明だと裏側が透けて見えます

画像を重ねる際に、背景が透明化どうかは大切になってきますね。

以下ではOpenCVを使用して、白色を透明化する方法を解説します。

OpenCV環境の準備

まずはじめに、PythonでOpenCVを使用できる環境を整えましょう。

ここではAnacondaでOpenCV環境を構築、jupyter notebookで使用する方法を紹介します。

OpenCVのインストール

ここではPythonのモジュール管理ソフトAnacondaを使用した例を紹介します。

Anacondaターミナルで次のコマンドを実行すれば、base環境にインストールできます。

conda install opencv

ただし、baseの環境には新規のライブラリをインストールすることは推奨されていません。

次のように新規の仮想環境を作成することをオススメします。

conda create -n 環境名
conda activate 環境名
conda install opencv

必要に応じて新規仮想環境にjupyter notebookやNumPyもインストールしておきましょう。

conda install numpy pandas notebook

jupyter notebookでOpenCVを使う

OpenCVをインストールした仮想環境でjupyter notebookを起動する方法を紹介します。

Anacondaのターミナルで次のコマンドを実行しましょう。

conda activate 環境名
conda jupyter notebook

もしくは、スタートメニュー ⇒ <Anaconda3(64-bit)> ⇒ <Jupyter Notebook(環境名)>をクリックしてもOKです。

白色部分の透明化(スクリプト紹介)

以下のスクリプトで、白色部分を透明化できます。

src.pngの白色部分が透明化されてdst.pngとして保存されます。

# OpenCVとNumPyをインポート
import cv2
import numpy as np
 
# 元画像の読み込み
path = "./figure_bgr.png"
src = cv2.imread(path)
 
# Point 1: 白色部分に対応するマスク画像を生成
mask = np.all(src[:,:,:] == [255, 255, 255], axis=-1)
 
# Point 2: 元画像をBGR形式からBGRA形式に変換
dst = cv2.cvtColor(src, cv2.COLOR_BGR2BGRA)
 
# Point3: マスク画像をもとに、白色部分を透明化
dst[mask,3] = 0
 
# png画像として出力
cv2.imwrite("dst.png", dst)

このスクリプトでは、次の3つがポイントです。

  • Point 1:白色部分に対応するマスク画像を生成
  • Point 2:元画像をBGR形式からBGRA形式に変換
  • Point 3:マスク画像をもとに、白色部分を透明化

次の3×3の画像を例に各ポイントを解説していきます。

Point 1:白色部分に対応するマスク画像を生成

画像の白色部分をTrue、それ以外をFalseとする真偽値の配列を作成します。

mask = np.all(src[:,:,:] == [255, 255, 255], axis=-1)

np.all()関数で、BGR全てが255(=白色)ならTrue、そうでなければFalseとなる配列を作ります。

このような特定の条件を満たす領域を抽出するための画像をマスク画像と呼びます。

Point 2:元画像をBGR形式からBGRA形式に変換

元の画像はBGRのデータしかないので、アルファチャンネルを追加します。

dst = cv2.cvtColor(src, cv2.COLOR_BGR2BGRA)

これでBGRA形式の画像になったため、透明度の設定ができるようになりました。

ここまでで下準備OKです。あろは白色部分を透明に書き換えるだけです。

Point 3:マスク画像をもとに、白色部分を透明化

画像の(x,y)の位置のピクセルのα値は、[x,y,3]に対応しています。

α値を0にすると透明になるので、マスク画像のTrueの場所(=白色)のα値を0にします。

dst[mask,3] = 0

これで白色の部分のα値が0になって、透明化されました。

このスクリプトを使えば次のように、白色を透明に変換できます。

おわりに

Web上に無料ソフトなどもありますが、自分でOpenCVを使えれば、複数ファイルの自動処理など、応用の幅が広がりますね。

これまで何冊かOpenCVの本や動画を見てきましたが、基礎から学ぶにはこちらの本がおススメです。

色の処理やフィルタ処理から始まってオブジェクト検出まで網羅的に解説しています。

PythonでのOpenCV初めての一冊にはピッタリかと思いますね。

Pythonでネットワーク分析【図解でわかりやすく解説】

Pythonには、データ分析をサポートする様々なモジュールが存在します。

その一つに、強力なネットワーク分析ツールとしてNetworkXというものがあります。

NetworkXを使えば、次のようなネットワーク分析を簡単に行うことができます。

  • ネットワーク分析
  • ネットワーク構造の可視化
  • 中心性や連結性などの解析

この記事では、NetworkXの基本的な使い方を中心にわかりやすく解説していきます。

さらに詳しい内容については、次のような書籍を参考にしてみてください。

ネットワーク分析の準備

まずはネットワーク分析の基礎知識、分析のための環境構築について解説していきます。

ちなみに以下で解説するような基本的な内容を網羅的に学びたい場合は次のような書籍がおススメです。

私もこの書籍から入門しています。

ネットワーク分析の基礎知識

ネットワーク分析に関する超基本用語を整理していきましょう。

次の4つの用語をおさえれば、基本的な可視化を行うことができます。

要素 NetwrokXでの名前 適用
ネットワーク Graph ネットワーク図全体のこと
頂点 node 一つ一つの要素のこと
edge 頂点と頂点を繋ぐ線のこと
次数 degree 頂点の持つ辺の数のこと

ネットワーク図を使って、各要素がどこに対応するか確認してみましょう。

この他にも必要に応じて各要素に任意の属性を持たせることも可能です。

例えば、次のような要素を与えることができます。

  • size: nodeの大きさ
  • weight: nodeedgeの重み(経路探索などの最適化問題で使うことがある)
  • color: nodeedgeの色

これらは属性として与えられるというだけで、属性をネットワーク図に反映するには別途設定が必要です。

基本用語を把握できたので、次はネットワーク分析用のモジュールNetworkXについて解説します。

NetworkXとは?

NetworkXとは、Pythonでネットワーク分析を行うため外部モジュールです。

NetworkXを使うと次の様な操作を行うことができます。

  • ネットワーク図の作成
  • 各要素のデータの出力
  • ネットワークの分析(最適解の探索など)

特にグラフの作成が非常に簡単かつ高速なので、Pythonでネットワーク分析を行う際には必須のモジュールとも言えます。

以下でNetworkXの基本的な使い方をわかりやすく解説していきます。

環境構築

NetworkXは組み込みライブラリではないので、pipまたはcondaでインストールします。

pipでインストールする場合は、ターミナルで以下のコマンドを実行します。

pip install pypdf

Anacondaの場合は次のコマンドでインストールしましょう。

conda install networkx

ただし、condaの場合はNetworkXのバージョンが古い場合があります。

最新のNetworkXに比べて、バージョンが古い場合はconda-forgeからインストールするのも一つの手です。

conda install networkx -c conda-forge
  • 【参考】conda-forgeの使い方については、次の記事で詳しく解説しています。
≫バッチファイルでJupyter Lab起動!ダブルクリックで起動可能に!
Jupyter Labを起動するときに、いちいちコンソールを開いて、jupyter labと打つのがめんどくさい!という方のために、Jupyter Labを起動するバッチファイルの作成方法を紹介します。少し応用すると、ノートブックを指定して起動するバッチファイルも作成可能です!これでダブルクリックだけで、Jupyter Labを起動できるようになりますね。
www.yutaka-note.com/entry/jupyter_bat
 

環境構築は飛ばして、とりあえずネットワーク分析を試したい場合は、Google Colaboratoryを使用すれば、初めからインストールされているので設定不要です。

≫5min. Python解説動画【入門編】|第2回 Colaboratoryで環境構築!
Google Colaboratoryを使えば、初心者の方でもすぐにPythonを始められます。この記事ではColaboratoryの初期設定方法、コードの書き方、押さえておきたい便利な使い方を紹介しています!
www.yutaka-note.com/entry/5min_python_02
 

NetworkXのインポート

NetworkXのインストールが終わったらコード上でインポートして使いましょう。

NetworkXnxという別名でインポートする慣例があるようです。

import networkx as nx

ネットワーク分析ではグラフの出力をすることもあるので、一緒にMaplotlibもインストールしておくと良いですね。

import matplotlib.pyplot as plt
import networkx as nx

NetworkXのバージョンは次のスクリプトで確認できます。

import networkx as nx
print(nx.__version__)

# 3.1

NetworkXMatplotlibで、どちらかのバージョンが極端に古いと互換性がない場合があります。

両方とも新しいバージョンにしておくと、そういったトラブルを避けやすくなると思います。

  • 【参考】Matplotlibの使い方については、次の記事で詳しく解説しています。
≫【初心者向け】Matplotlibの特徴と使い方をわかりやすく解説!
脱初心者のためのMatplotlibマスターガイドです。そもそもどういう流れでプロットするのか?どんな種類のグラフが描けるのか?日本語設定は?タイトルや軸の設定は?オブジェクト指向って何?そんな疑問を解決します!この記事で、脱Matplotlib初心者を目指そう!
www.yutaka-note.com/entry/matplotlib_guid
 

ネットワーク分析・可視化の超基本形

ネットワークの可視化のためには、次の手順を踏みます。

  1. Graphオブジェクトの作成:G = nx.Graph()
  2. nodeの追加:G.add_nodes_from([node1, node2, node3,…])
  3. edgeの追加:G.add_edges_from([(node1, node2), (node2, node3), …])
  4. ネットワークの可視化:nx.draw(G, witlabels = True)

オブジェクト作成から、可視化までの基本形は次のようになります。

# Graphオブジェクトの作成
G = nx.Graph()
 
# nodeデータの追加
G.add_nodes_from(["A", "B", "C", "D", "E", "F"])
 
# edgeデータの追加
G.add_edges_from([("A", "B"), ("B", "C"), ("B", "F"),("C", "D"), ("C", "E"), ("C", "F"), ("B", "F")])

# ネットワークの可視化
nx.draw(G, with_labels = True)
plt.show()

これで、次のようなグラフが描けます。

各手順について詳細を確認していきましょう。

Graphオブジェクトの作成

まずは、Graphオブジェクトを生成します。

  • G = nx.Graph()

この時点では、空のグラフが生成されているだけです。

このグラフにnodeedgeを追加して、ネットワークを完成させていきます。

nodeの追加

次にnodeを追加していきます。

1つだけ追加する場合は、.add_node(), 2つ以上追加する場合は.add_nodes_from()を使います。

  • G.add_node(node1)
  • G.add_nodes_from([node1, node2, node3,…])

nodeの要素としては辞書のキーとして使えるものが使用できると考えると良いです。

G = nx.Graph()
G.add_nodes_from(["A", "B", "C", "D", "E", "F"])

nx.draw(G, with_labels = True)
plt.savefig("03_add_nodes_fromの例.png", bbox_inches="tight")
plt.show()

次のようにnodeが生成されています。

edgeは指定していないので、node同士は結合していませんね。

次のようにnodeに属性を与えることもできます。

  • G.add_nodes_from(["A", "B"], size=10)
  • G.add_nodes_from([("A", {"size":10}), ("B", {"size":20})])

任意の属性を与えることが可能です。

ただし、属性を設定するだけで自動でグラフの見た目が変化するわけではないです。

グラフに反映する場合は自分で見た目の変更を行いましょう。

edgeの追加

次にnodeを追加していきます。

1組だけ追加する場合は、.add_edge(), 2つ以上追加する場合は.add_edges_from()を使います。

  • G.add_edge(node1, node2)
  • G.add_edges_from([(node1, node2), (node2, node3), …])

存在しないnodeを指定すると自動で追加されます。

## edgeの追加

# ネットワーク可視化の実行例
# Graphオブジェクトの作成
G = nx.Graph()
 
# nodeデータの追加
G.add_nodes_from(["A", "B", "C", "D", "E", "F"])
 
# edgeデータの追加
G.add_edges_from([("A", "B"), ("B", "C"), ("B", "F"),("C", "D"), ("C", "E"), ("C", "F"), ("B", "F")])

# ネットワークの可視化
nx.draw(G, with_labels = True)
plt.savefig("04_edgeの追加例.png", bbox_inches="tight")
plt.show()

次のようなネットワーク図が完成します。

nodeと同様に、edgeにも属性を与えることができます。

edgeの属性としては、wieghtを与えることが多いので、weightを与えるためのメソッドも存在します。

  • G.add_edges_from([("A", "B"), ("B", "C")], weight=1)
  • G.add_weighted_edges_from([("A", "B", 1), ("B", "C", 2)])

.add_weighted_edges_from()では、("node1", "node2", weight)の組み合わせを渡しています。

ネットワーク図の保存

作成した図を保存するのは、Matplotlibと同様にplt.savefig()を使用します。

  • plt.savefig("保存名.png")

【参考】Matplotlibでの画像の保存方法については、次の記事で詳しく解説しています。

≫matplotlib 画像の保存方法|savefigの使い方
Pythonのデータ可視化ライブラリといえば、Matplotlibですね。Matplotlibで作成した画像は様々なファイル形式で保存することができます。しかし、実際に画像を保存しようとすると、次のような問題に直面することも… ① 画像として保存するにはどのメソッドを実行すればいいの? ② ファイルの種類を指定することはできる? ③ 画像の見た目を調整してから保存したい! この記事では、Matplotlibの.savefig()を使って画像を保存する方法について、分かりやすく解説していきます。
www.yutaka-note.com/entry/matplotlib_savefig
 

基本的な特性値の出力

次に作成したネットワークの基本データを出力する方法を確認していきましょう。

出力内容 出力方法
ノードとエッジの数 print(G)
ノードの数 G.number_of_nodes()
ノードの要素 G.nodes()
エッジの数 G.number_of_edges()
エッジの要素 G.edges()
各ノードの実数 G.degrees()

バージョン2.Xまでは、nx.info()という関数で基本テータを出力できましたが、3.Xからはこの関数はなくなりました。

基本データをさっと確認する場合はprint()関数で確認します。

print(G)

# Graph with 7 nodes and 6 edges

その他の実行例も確認してみましょう。

ノードの出力

ノードの基本出力メソッドは次の通りです。

  • ノードの数:G.number_of_nodes()
  • ノードの要素:G.nodes()

サンプルコードで挙動を確認してみましょう。

print("number of nodes:",G.number_of_nodes())
print("nodes:", G.nodes())
 
# number of nodes: 6
# nodes: ['A', 'B', 'C', 'D', 'E', 'F']

隣接したノードの出力方法

隣接したノードを出力したい場合は、.all_neighbors()関数を使います。

  • nx.all_neighbors(G, ノード名)

結果はイテレータで返されます。

サンプルコードで挙動を確認してみましょう。

for n in nx.all_neighbors(G, "C"):
    print(n) 
# B
# D
# E
# F

エッジの出力

エッジの基本出力メソッドは次の通りです。

  • エッジの数:G.number_of_edges()
  • エッジの要素:G.edges()

サンプルコードで挙動を確認してみましょう。

print("number of edges:",G.number_of_edges())
print("edges:", G.edges())
 
# number of edges: 6
# edges: [('A', 'B'), ('B', 'C'), ('B', 'F'), ('C', 'D'), ('C', 'E'), ('C', 'F')]

次数の出力

次数の基本出力メソッドは次の通りです。

  • 各ノードの次数:G.degrees()

各ノードの次数が自動集計を自動で集計することができます。

サンプルコードで挙動を確認してみましょう。

print("degrees:", G.degree())
 
# degrees: [('A', 1), ('B', 3), ('C', 4), ('D', 1), ('E', 1), ('F', 2)]

ネットワーク図の見た目変更

ネットワーク図の見た目を変更するには、nx.draw()メソッドでキーワード引数を設定します。

基本的な設定要素は下記の通りです。

要素 引数 設定例
nodeの色 edge_color "色名" or "色名のリスト"など
※デフォルト:'C0' 薄い青
nodeのサイズ node_size "数値" or "数値のリスト"など
※デフォルト:300
edgeの色 edge_color "色名" or "色名のリスト"など
※デフォルト:'black'
edgeの太さ width "数値" or "数値のリスト"など
※デフォルト:1

それぞれ、グラフ内で一括で設定する場合には、"色名""数値"を指定します。

要素ごとに設定する場合は、要素の数に応じた[リスト]等で指定します。

それぞれ実行例を確認してみましょう。

一括で設定(色、ノードサイズ、エッジの太さ)

キーワード引数としてシリアル値(リストでなく1つの値)を与えると、グラフ全体に適用されます。

ノードの色を"red"、エッジの色を"gray"、太さを500にしてみましょう。

nx.draw(G, with_labels=True, 
        node_color = "red",
        edge_color = "gray",
        node_size = 500, 
        width = 5)
plt.savefig("05_ネットワーク図の見た目変更(一括設定)例.png", bbox_inches="tight")
plt.show()

ネットワーク図の見た目が一括で変更されていますね。

要素毎に設定

[リスト]で設定値を渡すことで、各ノード、エッジに異なる設定を適用できます。

各要素の順番に対応するように設定値を渡します。

次の例ではノードの各要素の色をcolorsというリストで渡しています。

colors = ["lightblue", "green", "red", "cyan", "magenta", "yellow"]
nx.draw(G, with_labels=True, node_color = colors)
plt.savefig("06_ネットワーク図の見た目変更(個別設定)例.png", bbox_inches="tight")

plt.show()

次のようにノードに色が設定されます。

色の設定で個別に色を設定する場合は、Matplotlibのカラーサイクルを使うとキレイに色付けできます。

カラーマップを生成して、要素の数だけ色を準備しておきます。

  • カラーマップ生成:cmap = plt.get_cmap("Pastel1")
  • node数の色を準備:node_color = [cmap(i) for i in range(G.number_of_nodes())]

サンプルコードで挙動を確認してみましょう。

# カラーマップから色の準備
cmap = plt.get_cmap("Pastel1")
node_color = [cmap(i) for i in range(G.number_of_nodes())]

# ネットワークの可視化
nx.draw_networkx(G, with_labels=True, node_color = node_color)
plt.savefig("01_simple_network.png", bbox_inches="tight")

plt.show()

次のようにカラーマップで色付けされたネットワーク図が作れます。

  • 【参考】カラーマップの使い方については、次の記事で詳しく解説しています。
≫Matplotlib color 色の指定 | 一文字指定からカラーマップの使い方まで徹底解説
伝わるグラフを作るためのポイントはなんでしょうか?いかに視覚的にわかりやすいか、これが大切です。それには重要な要素に色をつけて、視覚的にうったえることが超大切!この記事では、matplotlibでの色の指定方法について、基本から応用まで徹底解説!
www.yutaka-note.com/entry/matplotlib_color
 

ネットワーク可視化例|次数に応じた配色・サイズ変更

最後に、各ノードの次数に応じて配色・サイズ変更する例を紹介します。

これまで、紹介してきた特性値の出力方法、ネットワーク図の見た目変更を組み合わせていきます。

実行例として、次のようなグラフを作成してみましょう。

このグラフは次の様なグラフになっています。

  • ネットワーク図のnodeのサイズが次数の数に比例
  • ネットワーク図と棒グラフで各nodeの色が対応

色やサイズの設定が適切に設定できれば簡単に作成できます。

簡単な工夫ですが、デフォルトのネットワーク図よりも視認性がだいぶ上がっていますね。

以下で実装例を紹介していきます。

次数に応じたネットワーク図の例

まずは、ノードの色付け、次数に応じたサイズ調整を行いましょう。

d = G.degree()
import numpy as np
np.array([d for n, d in G.degree()])
degrees = np.array([d for n, d in G.degree()])
degrees.mean()
# 各nodeの次数を取得
degrees = np.array([d for n, d in G.degree()])

# ノードの次数に比例するようにサイズを設定
sizes = 300 * degrees / degrees.mean()
print(sizes)
# [150.0, 450.0, 600.0, 150.0, 150.0, 300.0]
 
# カラーマップから色を生成
cmap = plt.get_cmap("Pastel1")
node_color = [cmap(i) for i in range(G.number_of_nodes())]

# グラフの出力
plt.figure(figsize = (10,5))
plt.subplot(121)
nx.draw(G, with_labels=True, node_color = node_color, node_size = sizes, edge_color = "black")

plt.show()

次のようにノードのサイズに応じたサイズ変更ができました。

情報をわかりやすくするために、次数に関する棒グラフを作成してみましょう。

次数順の棒グラフの作成

次に各ノードの次数順の棒グラフを作成してみましょう。

nodes_sorted_by_degree = sorted(G.degree(), key=lambda x: x[1], reverse=True)
print(nodes_sorted_by_degree)
# [('C', 4), ('B', 3), ('F', 2), ('A', 1), ('D', 1), ('E', 1)]
 
# 色のリストを次数順に並び替える
colors_dict = dict(zip(G.nodes(), node_color))
colors_sorted = [colors_dict[node] for node, _ in nodes_sorted_by_degree]

# グラフの出力
x, height = list(zip(*nodes_sorted_by_degree))
plt.subplot(122)
plt.xlabel("Number of degrees")
plt.ylabel("Name of node")
plt.barh(x, height, color = colors_sorted)

plt.savefig("08_次数の棒グラフ.png", bbox_inches="tight")
plt.show()

ネットワーク図の描画と合わせて実行すると、次の様なグラフができます。

  • 【参考】subplotの使い方については、次の記事で詳しく解説しています。
≫Matplotlib plt.subplotの使い方徹底図解!|一つの図に複数グラフを描く
Matplotlibで一つの図の中に複数のグラフを並べるにはどうすればいいの?plt.subplot()でグラフを並べられるらしいけど、使い方がよくわからない!という方のために、「plt.subplot()の基本的な使い方」を画像付きで解説していきます!plt.subplot()でプロットをキレイに配置して、見やすく人に伝わるグラフを目指しましょう!
www.yutaka-note.com/entry/2020/01/02/232925
 
  • 【参考】Matplotlibでの棒グラフ作成方法については、次の記事で詳しく解説しています。
≫Matplotlib 棒グラフを徹底解説|複数系列・積み上げ棒グラフ全てOK
Matplotlibで棒グラフを作成する方法がよくわからない…。 棒グラフで悩むなら、MatplotlibあきらめてExcel使おうかな…。 と思ったことはありませんか?そんな方のために、Matplotlibの棒グラフ作成方法を徹底的に解説しました!複数系列?積み上げ棒グラフ?全部大丈夫!
www.yutaka-note.com/entry/matplotlib_bar
 

最短経路の探索

NetworkXにはネットワーク内の最短経路を探索する関数も準備されています。

特定の2点間の最短距離を探すには、nx.shortest_path()関数を使用します。

  • nx.shortest_path(G, source=始点ノード, target=終点ノード)

サンプルコードで挙動を確認してみましょう。

nx.shortest_path(G, source="A", target="D")
# ['A', 'B', 'C', 'D']

最短経路の探索結果をネットワーク図内に表示する例を紹介します。

探索結果をもとにネットワーク図の見た目を変更すればOKです。

# カラーマップから色を生成
cmap = plt.get_cmap("Pastel1")
node_color = [cmap(i) for i in range(G.number_of_nodes())]

# 最短経路の探索
shortest_pass = nx.shortest_path(G, source="A", target="D")
highlited_edges = list(zip(shortest_pass, shortest_pass[1:]))

# 最短経路のエッジに色付け
G.add_edges_from(highlited_edges, color="tab:blue")
edge_color_dict = nx.get_edge_attributes(G, "color")
edge_color = [edge_color_dict[p] if p in edge_color_dict else "gray" for p in G.edges()]

# ネットワーク図の描画
nx.draw(G, node_color=node_color, edge_color=edge_color, with_labels=True)

plt.savefig("09_最短経路を強調.png", bbox_inches="tight")
plt.show()

次のように最短経路を探索して、強調表示したグラフを描けます。

NetworkXの機能をうまく使えば、最短経路の描画も簡単ですね。

上の例ではMatplotlibのデフォルトの色(tab:blue)を使って、最短経路を強調表示しています。

他のグラフとの一貫性を保つために、Matplotlibのデフォルトの色を使用することも多いです。

  • 【参考】Matplotlibのデフォルトの色については、次の記事で詳しく解説しています。
≫Matplotlib デフォルトの色の変更|実は一行でできます!
Matplotlibでグラフを描くと、デフォルトで青→オレンジ→緑→…と色が変わっていきます。この記事では、`Matplotlib`のデフォルトの色(カラーサイクル)の設定変更について紹介していきます。①データが10系列以上あるときに、また青に戻ってしまう場合の対応方法②自分好みにカラーサイクルを変更する方法また、デフォルトの色を指定して使用する方法についても触れています。
www.yutaka-note.com/entry/matplotlib_color_cycle
 

ネットワーク分析おススメの1冊!

pythonでネットワーク分析をしたい方には、こちらの本がおススメです。

実は私はネットワーク分析の基本どころか、NetworkXの存在すらしらなかったのですが…。

この本では次の様な内容が詳しく解説されています。

  • ネットワーク分析の流れや用語説明
  • NetworkXをサンプルコード付きで解説

私のような初学者でもすぐに簡単なネットワーク分析をできるようになりました!

今回の記事では紹介しませんでしたが、本の中では次の様な内容についても解説しています。

  • ネットワークの中心性を解析する方法
  • グループの分割・抽出方法

ネットワーク分析の勉強にオススメな1冊でした!

Python turtle|組み込みモジュールturtleで桜を描こう!

pythonの標準ライブラリには、turtleという絵画用ライブラリがあります。

操作も簡単で、子供たちのプログラミング入門にも人気だそうです。

今回は、簡単な使用方法とその応用例としてturtleで桜を描く方法を紹介します。

turtleの基本的な使用方法

絵画を描くのに必要な最低限の機能をサンプルコード付きで紹介します。

詳しく知りたい方は、公式ドキュメントを参照してください。

絵画領域とタートルの作成

まずturtule.setup()関数で絵画領域を作成します。

その中に、タートルインスタンスturtle.Turtle()を作成します。

このタートルが、絵画領域内を走り回って、線を描きます。

import turtle
turtle.setup(width=300, height=300)  # 絵画領域の作成
my_turtle = turtle.Turtle()  # タートル

絵画領域の座標は(x, y)形式で、中心が(0, 0)です。

タートルを移動させる:forward(), setpos()

次の2つの移動方法を紹介します。

タートルの移動方法

forward(n):タートルが向いている方向に、nだけ前進

setpos(x, y):引数で指定した座標(x, y)に、タートルが移動

⇒移動する際に、タートルは線を描きます。

実際に移動してみます。

my_turtle.forward(100)  # 100前進
my_turtle.setpos(0, -100) #(0, -100)に移動

タートルが移動した際に、線を引きたくない場合には、penup()を実行します。

すると、次にpendown()が実行されるまで線が引かれなくなります。

my_turtle.penup() # 筆を上げる
my_turtle.forward(50)  # 100前進(筆が上がってるので線ひかない)
my_turtle.pendown() # 筆を下ろす
my_turtle.forward(-50)  # 100前進(筆が下がってるので線ひく)

タートルを回転させる:setheading()

setheading()では、指定した角度にタートルが回転します。

タートルの向き

右向き:setheading(0)

上向き:setheading(90)

左向き:setheading(180)

下向き:setheading(270)

回転と前進を、組み合わせると様々な線が引けます。

my_turtle.setheading(90)  # 上を向く
my_turtle.forward(100)  # 100前進

点を描く:dot()

dot()関数で、タートルがいる場所に●を描けます。

dot(n, "color")とすると、nでサイズを指定、"color"で色を指定できます。

my_turtle.dot(10, "red") # 赤丸を描く

これで線と●が自由に描けます。

あとはアイデアしだいで、いろいろなことができますよ!

応用turtleで桜を描く

タートルの基本機能を組む合わせて、桜を描いてみましょう。

ここで説明するスクリプトを実行すると、こんな桜が描けます。

サンプルコードのgistもありますので、ぜひ遊んでみてください!

hanasaka_python_simple.py · GitHub

桜を描く方法は次のサイトを参考に作成しました。

How to draw a beautiful tree 2.0 with Python - Programmer Sought

使用ライブラリ

turtlerandomのみです。

どちらも組み込みライブラリなので、importするだけです。

import turtle
import random

メインスクリプト

まずは、メインスクリプトを紹介します。

(クラスを作成すればもう少しすっきりします。今回は多くの人に楽しんでいただきたいので関数で作りました)

初期設定、種まき、木の成長、開花というフローになっています。

if __name__ == "__main__":
    # 絵画領域の準備
    turtle.setup(width=300, height=300)
 
    # タートルの用意
    my_turtle = turtle.Turtle()
    my_turtle.speed(0)  # タートルの移動速度の設定
    my_turtle.setheading(90)  # 上向きにする
 
    # 枝の短点を格納するリストを用意しておく
    bloom_point = []
 
    # 木が生える場所に種をまく
    seed(x=0, y=-150, my_turtle=my_turtle)
 
    # 木を成長させる
    tree(n=5, length=40, my_turtle=my_turtle, bloom_point=bloom_point)
 
    # 花を咲かせる
    bloom(my_turtle=my_turtle, bloom_point=bloom_point)
 
    # 終了後も絵画領域を表示させたままにする
    turtle.done()

次に各関数の中身を作成していきます。

種まき

オシャレに種まきseedと名付けましたが、木が生える場所にタートルを移動させるだけです。

def seed(x, y, my_turtle):
    # (x, y)にタートルを移動させる
    my_turtle.pu()  # 移動時、線を引かない
    my_turtle.setposition(x, y)

木を育てる

枝や幹を描く再起関数を作成します。

再起関数のフロー

幹から枝の先端まで、n回の分岐をするとする。

①幹を描いたら、先端でn1減らして、枝を描く。

n1減らして、枝を描く。

n0になったら、n=1に戻って分岐があればまた枝を描く。

③'分岐がなければ、n1増やして分岐があるか調べる。

このフローを再起関数で実現します。

def tree(n, length, my_turtle, bloom_point):
    # 幹または枝を描く
    my_turtle.pd()
    my_turtle.pensize(n)
    my_turtle.forward(length)

    # 描いている枝が、先端(n=0)でなければ、さらに分岐した枝を描く
    if n > 0:
        # 枝が生える分岐点の座標を記録
        branch_point = my_turtle.pos()

        # 分岐点から生える枝の数を2~4本でランダムに選ぶ
        branch_number = random.randint(2, 4)

        # 枝を1本ずつ
        for _ in range(branch_number):
            # 枝の角度、長さをランダムに決める
            branch_angle = random.uniform(-45, 45)
            branch_length = length * random.uniform(0.75, 0.9)

            # 枝の方向を向く
            my_turtle.right(branch_angle)
            # 再起関数で、もう一段細い枝を描く
            tree(n - 1, branch_length, my_turtle, bloom_point)
            # 枝の方向からもとの角度に戻る
            my_turtle.left(branch_angle)

            # 枝の分岐点に戻る
            my_turtle.pu()
            my_turtle.setpos(branch_point)

    # 描いている枝が、先端(n=0)であれば、座標を記録する
    else:
        # 枝の先端を記録
        bloom_point.append(my_turtle.pos())

ここではカウンターnを減らしながら、再起関数を呼ぶテクニックを利用しています。

再起関数のテクニック

・カウンターnを減らしながら実行

n>0nn-1にして、再起関数を内部で呼ぶ

・条件を満たしたら終了処理

n=0:先端の位置の記録

このテクニックを使用すれば再起関数を簡単に自作できます。

花が咲く

枝の先端にタートルを移動して、ピンクの円を描きます。

def bloom(my_turtle, bloom_point):
    my_turtle.pu()
    for position in bloom_point:
        # 花の場所に移動
        my_turtle.setpos(position)
        # 花が咲く
        my_turtle.dot(8, "pink")

あとはメインスクリプトを実行するだけです!

おわりに

今回はturtleを使用して、桜を描く方法を紹介しました。

工夫次第でいろいろなことができそうです!

ちなみに、クラスを作成したサンプルコードはこちらです。

hanasaka_python.py · GitHub

少しすっきりしてますね、桜を2本描くのも楽々です!

mpi4py:pythonで並列処理

pythonで並列処理をするにはmpi4pyというモジュールが便利のようです。

しかし、私の場合は初期設定でつまづいてしまいました。

とは言っても、実はモジュール以外にも必要なものがあるので、それをインストールすればいいだけの話でした!

今回はWindowsでmpi4pyを利用する方法をまとめます

mpi4pyについて、詳細を知りたい方は、公式ドキュメントもご覧ください。

MPI for Python — MPI for Python 3.0.3 documentation

MPIとは?

mpi4pyそのものが並列処理するのではなく、mpi4pyはpythonでMPIを使うためのモジュールです。

このMPIとは並列処理するための規格だそうです。

Message Passing Interface(メッセージ パッシング インターフェース、MPI)とは、並列コンピューティング利用するための標準化された規格である。実装自体を指すこともある。https://ja.wikipedia.org/wiki/Message_Passing_Interface

MPIは規格なので、どこかで入手しなければいけないようです...無料でないのかな...と思ったら?

Windows 環境では、MSMPIが使える!

WindowsではMicrosoft MPIというものを無料で利用できます!!

MSMPIと略されることが多いみたいです。

MSMPIのインストール

MicrosoftのHPからダウンロードして、インストールします。

次の二つをインストールする必要があります。

  • msmpisdk.msi
  • msmpisetup.exe

mpiexecへのパスを通す

並列計算の場合はpython.exeではなく、mpiexec.exe を使用します。そのため、このmpiexec.exeへのPATHを通しておく必要があります。

デフォルトでインストールした場合は、C:\Program Files\Microsoft MPI\Binに保存されます。

コマンドプロンプトでPATHを確認しましょう!次のコマンドで確認できます。
echo %path:;=&echo.%

f:id:YutaKa:20191129125612p:plain
私の場合は自動でPATHも通っていました(もしかして、msiでインストールして、exeでPATH通してるのかな?順番が大事??)。通ってなかったらPATHを通しましょう。

mpi4pyの入手

mpi4pyは、defaultチャンネルや conda-forgeにはなく、anacondaチャンネルにあります。

次のコマンドでmpi4pyを使うためのmpi_envという仮想環境を作ってみます。
conda create --name mpi_env mpi4py -c anaconda 

f:id:YutaKa:20191129130053p:plain

これでMPIの準備とmpi4pyの準備が完了です!

テストランしてみよう

今作った仮想環境でテストラン用のスクリプトを作ります。私の場合は、condaで作った環境をpycharmで使用しています。

yutaka01.hatenablog.com

お試し用にmpi_test.pyというスクリプトを作成してみます。

from mpi4py import MPI

comm = MPI.COMM_WORLD # 並列処理開始です!

size = comm.Get_size() # 並列処理に使用できるプロセッサ数
rank = comm.Get_rank() # 各プロセッサのIDのようなもの

print("Hello world {0} / {1}".format(rank, size))
並列処理できれば、各プロセッサがHello Worldを出力するはずです!!

python.exeで実施

普通にターミナル(pycharm画面の下の方にあります)でランすると...
python mpi_test.py

f:id:YutaKa:20191130120849p:plain

一個しか出てこない!!失敗!

mpiexecで実施

並列処理にはmpiexec.exeで、python.exeを実行する必要があります!
例えば2つのプロセッサを使うときは次のようにしてプロンプトに入力します。
mpiexec -n 2 python mpi_test.py

f:id:YutaKa:20191130120950p:plain

無事に2つのプロセッサからHello Worldが返ってきました
おつかれさまです(⌒∇⌒)

まとめ

Pythonで並列処理するには、mpi4pyを使用するのが便利です!
そのためにはMPIという規格が必要ですが、windows であればMSMPIという無料のMPIが使用できます!
自分が使いたい外部モジュールがmpi4pyを使用している場合にも、MPIは必要になるので、記憶にとどめておいてください!
この記事を読まれた方は、数値計算・科学積算系のことをされている方が多いのではないでしょうか?
数値計算関係のpythonの書籍では、次のものがおススメです。 
科学技術計算のためのPython入門 ――開発基礎、必須ライブラリ、高速化

科学技術計算のためのPython入門 ――開発基礎、必須ライブラリ、高速化

  • 作者:中久喜 健司
  • 発売日: 2016/09/22
  • メディア: 単行本(ソフトカバー)