違う文字を探す脳トレ
前回、違う文字を探す脳トレを作成するPythonプログラムで、問題をリスト化するところまでプログラミングしました。
今回は問題のリストから、matplotlibを使って画像化していきます。
前回のおさらいとしてはこんな感じです。
<セル1>
import random
import json
with open('./question.json', 'r') as f_in:
question_list = json.load(f_in)
char_list = question_list[random.choice(list(question_list))]
print(char_list)
<セル2>
cell_min = 10; cell_max = 20
vertical = random.randint(cell_min, cell_max)
horizontal = random.randint(cell_min, cell_max)
num_char = vertical*horizontal
diff_char_no = random.randint(1, num_char)
print(vertical, horizontal, num_char, diff_char_no)
<セル3>
output_list = []
for num in range(1, num_char+1):
if num == diff_char_no:
output_list.append(char_list[1])
else:
output_list.append(char_list[0])
print(output_list)
それでは始めていきましょう。
フォントの配置とフォント用JSONファイルの作成
この違う文字を探す脳トレは、フォントによって、見つけやすさの難易度が結構違います(個人的感想)。
ということで、せっかくなのでランダムにフォントを選んで、画像化するようにプログラムしていきましょう。
今回使用するフォントはGoogle Fontsよりダウンロードしたこちらの6つです。
Noto Sans JP
Shippori Mincho
Dela Gothic One
Potta One
Hachi Maru Pop
New Tegomin
Google Fontsに関してはこちらの記事でも紹介していますので、よかったらどうぞ。
これらを適当なフォルダに配置します。
私の場合はこちらのようにそれぞれのフォントのフォルダを作り、その中にフォントファイルとライセンスファイルを保管しました。
FindTheDifference
├── FindTheDifference.ipynb
├── FindTheDifference.py
├── Dela_Gothic_One
│ ├── DelaGothicOne-Regular.ttf
│ └── OFL.txt
├── Hachi_Maru_Pop
│ ├── HachiMaruPop-Regular.ttf
│ └── OFL.txt
├── New_Tegomin
│ ├── NewTegomin-Regular.ttf
│ └── OFL.txt
├── Noto_Sans_JP
│ ├── NotoSansJP-Regular.otf
│ └── OFL.txt
├── Potta_One
│ ├── OFL.txt
│ └── PottaOne-Regular.ttf
├── Shippori_Mincho
│ ├── OFL.txt
│ └── ShipporiMincho-Regular.ttf
├── fonts.json
└── question.json
次にフォント用のJSONファイルを作成します。
「”フォント名”:”フォントのパス”」という形でこんな感じのJSONファイルを作成し、「fonts.json」として保存しました。
{
"NotoSans":"./Noto_Sans_JP/NotoSansJP-Regular.otf",
"ShipporiMincho":"./Shippori_Mincho/ShipporiMincho-Regular.ttf",
"DelaGothicOne":"./Dela_Gothic_One/DelaGothicOne-Regular.ttf",
"PottaOne":"./Potta_One/PottaOne-Regular.ttf",
"HachiMaruPop":"./Hachi_Maru_Pop/HachiMaruPop-Regular.ttf",
"NewTegomin":"./New_Tegomin/NewTegomin-Regular.ttf"
}
これでフォントの準備は整いました。
フォントやその他の設定
それでは画像化する部分の作成を始めていきますが、まずはフォントを読み込んだり、ファイル名や装飾の準備を行います。
その部分がこちら。
<セル4>
from matplotlib import pyplot as plt
import matplotlib.font_manager as fm
import datetime
%matplotlib notebook
promotion_text = '3PySci https://3pysci.com'
promotion_fontsize = 30
timenow = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
with open('./fonts.json', 'r') as f_in:
fonts_list = json.load(f_in)
font_path = fonts_list[random.choice(list(fonts_list))]
fp = fm.FontProperties(fname=font_path)
print(font_path)
まずインポート部分から解説していきます。
from matplotlib import pyplot as plt
import matplotlib.font_manager as fm
import datetime
%matplotlib notebook
上から画像化するためのmatplotlibのインポート、matplotlibでフォントを設定するためのマネージャーのインポート、ファイル名に日時を使うためのdatetimeのインポート、Jupyter Notebook上でmatplotlibの画像を表示するためのマジックコマンドです。
次は細々とした設定です。
promotion_text = '3PySci https://3pysci.com'
promotion_fontsize = 30
timenow = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
最初の2行はこの脳トレが拡散されるだろうと目論んで、一番下にブログの宣伝を入れるためのテキストとそのフォントサイズです。
「timenow = datetime.datetime.now().strftime(“%Y%m%d%H%M%S”)」は実行した日時を取得し、後々画像のファイル名に使用します。
次のこちらの部分はfonts.jsonよりフォントのリストを取得し、その中からランダムに一つ取り出し、そのフォントのパスを変数fonts_pathに格納しています。
with open('./fonts.json', 'r') as f_in:
fonts_list = json.load(f_in)
font_path = fonts_list[random.choice(list(fonts_list))]
新しいのはこの部分の1行目。
matplotlibで特定の部分のフォントを変えるのに、「font_manager」を使っているのですが、「.FontProperties(fname=”フォントのパス”)」で使用するフォントを読み込んでいます。
fp = fm.FontProperties(fname=font_path)
読み込んだフォント「fp」は後ほど使います。
matplotlibで画像化
次にメインのmatplotlibでの画像化の部分です。。
<セル5>
fig = plt.figure(figsize=(vertical,horizontal))
plt.clf()
i = 0
for x in range(1, vertical+1):
for y in range(1, horizontal+1):
plt.text((x-1)/vertical, (y-1)/horizontal, output_list[i], fontsize=55, fontproperties=fp)
i = i + 1
plt.gca().spines['right'].set_visible(False)
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['bottom'].set_visible(False)
plt.gca().spines['left'].set_visible(False)
plt.tick_params(labelbottom=False, labelleft=False, labelright=False, labeltop=False,
bottom=False, left=False, right=False, top=False)
plt.xlabel(promotion_text, fontsize=promotion_fontsize, fontproperties=fp)
plt.show()
plt.savefig(f'{timenow}.png', bbox_inches='tight', pad_inches = 0.1)
まず画像サイズですが、今回縦と横の文字数はランダムに決定されます。
そのため、画像サイズを一律で決めれませんので、単純に縦の文字数、横の文字数を画像サイズにしています。
「plt.clf()」は画像領域のクリアのコマンドです(念の為)。
fig = plt.figure(figsize=(vertical,horizontal))
plt.clf()
次の部分で文字のリストを一つずつテキストとして配置していっています。
i = 0
for x in range(1, vertical+1):
for y in range(1, horizontal+1):
plt.text((x-1)/vertical, (y-1)/horizontal, output_list[i], fontsize=55, fontproperties=fp)
i = i + 1
x、つまり縦方向の文字数をループで回しつつ、さらにyの横方向のループも回して、横にテキストを配置していっています。
matplotlibでテキストを配置するコマンドは「plt.text(Xの位置, Yの位置, “配置するテキスト”)」です。
数値のプロットがない場合、縦横ともに0から1のグラフ領域が作成されますので、それを縦の文字数、または横の文字数で分割し、Xのループ回数、Yのループ回数で位置を決めています。
「i」が累計の文字数で、「output_list[i]」とすることで前回作成した文字のリストから順番に文字を取得しています。
またオプションとして「fontsize=55」、そしてフォントを設定するために「fontproperties=fp」を追加しています。
この部分は最初の4行で枠線を、最後の1行で軸のメモリ線を消しています。
plt.gca().spines['right'].set_visible(False)
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['bottom'].set_visible(False)
plt.gca().spines['left'].set_visible(False)
plt.tick_params(labelbottom=False, labelleft=False, labelright=False, labeltop=False,
bottom=False, left=False, right=False, top=False)
この枠線を消す、軸のメモリ線を消すことの詳細はまた別の機会に解説したいと思います。
次にXラベルに宣伝用のテキストを配置しています。
この時も「fontproperties=fp」とすることで選択されたフォントを使用しています。
plt.xlabel(promotion_text, fontsize=promotion_fontsize, fontproperties=fp)
plt.show()
plt.savefig(f'{timenow}.png', bbox_inches='tight', pad_inches = 0.1)
そして「plt.show()」でJupyter Notebook上で表示し、「plt.savefig(‘画像の保存先’)」で保存しています。
「bbox_inches=’tight’, pad_inches = 0.1」はグラフの外側の余白の部分の設定です。
「bbox_inches=’tight’」で余白を無くし、「pad_inches = 0.1」で少しだけ余白を作成しています。
これで実行すると、こんな感じ。
下の宣伝用テキストが少しだけ被ってしまっていますが、そこはご愛嬌。
いい感じの画像を作ることができました。
次回はこの画像をTwitterに投稿するためのプログラムを作成していきましょう。
ではでは今回はこんな感じで。
コメント