Python&reportlabでPDFを生成2

# -*- coding: utf-8 -*-

from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.cidfonts import UnicodeCIDFont
import reportlab.lib.colors as color

def make(filename="test"):
	pdf_canvas = set_info(filename)
	print_string(pdf_canvas)
	# print_figure(pdf_canvas)
	# print_line(pdf_canvas)
	pdf_canvas.save()

# 初期設定
def set_info(filename):
	pdf_canvas = canvas.Canvas("./{0}.pdf".format(filename), bottomup=False) # 原点は左上

	pdf_canvas.setAuthor("hpscript")
	pdf_canvas.setTitle("make pdf using reportlab")
	pdf_canvas.setSubject("reportlab")

	return pdf_canvas


# 文字
def print_string(pdf_canvas):
	pdfmetrics.registerFont(UnicodeCIDFont("HeiseiKakuGo-W5"))
	pdfmetrics.registerFont(UnicodeCIDFont("HeiseiMin-W3"))

	pdf_canvas.setFont("HeiseiKakuGo-W5", 15)
	pdf_canvas.drawString(50, 50, "日経平均レバレッジ上場投信")

	pdf_canvas.setFont("HeiseiMin-W3", 30)
	pdf_canvas.drawString(300, 100, "日経ダブルインバース上場投信")

if __name__ == '__main__':
	make()

$ python test.py

いけますね、なんとなく掴みました。
続いて図形

def print_line(pdf_canvas):
	pdf_canvas.rect(50, 150, 200, 250)

	pdf_canvas.setFillColor(color.blue)
	pdf_canvas.circle(400, 350, 50, stroke=False, fill=True)

# 線
def print_line(pdf_canvas):
	# 普通の線
	pdf_canvas.line(50, 450, 500, 450)

	# 赤い太い線
	pdf_canvas.setStrokeColor(color.red)
	pdf_canvas.setLineWidth(10)
	pdf_canvas.line(100, 500, 550, 500)

	# 破線
	pdf_canvas.setStrokeColor(color.black)
	pdf_canvas.setLineWidth(5)
	pdf_canvas.setDash([2, 8, 5, 10])
	pdf_canvas.line(150, 550, 600, 550)

	# 複数の線
	pdf_canvas.setLineWidth(1)
	pdf_canvas.setDash([])
	lines = [(100, 650, 200, 750),(200, 750, 300, 650),(300, 650, 300, 750),(100, 700, 400, 700)]
	pdf_canvas.lines(lines)

OK^^

PythonでPDFの見積書を描画したい1

販売管理システムの見積一覧ページで、詳細ボタンを押下するとPDFの見積書を表示し、ダウンロードボタンを押下するとPDFの見積書をダウンロードできるようにしたい。

最初なのでデザインはなるべくシンプルに
▼見積書イメージ

## reportlab
PDF作成ライブラリのreportlabを使用します。

– reportlabのインストール
$ pip install reportlab

### 初期設定
app.py

def make(filename="estimate"):
	pdf_canvas = set_info(filename)
	print_string(pdf_canvas)
	pdf_canvas.save() # pdfを保存

def set_info(filename):
	pdf_canvas = canvas.Canvas("./{0}.pdf".format(filename))
	pdf_canvas.setAuthor("hpscript")
	pdf_canvas.setTitle("見積書")
	pdf_canvas.setSubject("見積書")
	return pdf_canvas

### 日本語設定

def print_string(pdf_canvas)
	# フォント登録
	pdfmetrics.registerFont(UnicodeCIDFont('HeiseiKakuGo-W5'))

	width, height = A4

	font_size = 24

	pdf_canvas.setFont('HeiseiKakuGo-W5', font_size)

	pdf_canvas.drawString(60, 770, '見積書')

### 表の描画
データ入力
-> 二次元配列で書く
e.g. 三行四列の場合

	data = [
		['(0,0)', '(1,0)', '(2,0)'],
		['(0,1)', '(1,1)', '(2,1)'],
		['(0,2)', '(1,2)', '(2,2)'],
		['(0,3)', '(1,3)', '(2,3)'],
	]

tableの大きさ指定
->全列30mm, 全行40mmの場合

table = Table(data, colWidths=30*mm, rowHeights=40*mm)

->1列目10mm、2列目20mm、3列目30mm、1〜2行目30mm、3〜4行目50mmの場合

table = Table(data, colWidths=(10*mm, 20*mm, 30*mm), rowHeights=(30*mm, 30*mm, 50*mm, 50*mm))

tableの装飾

	table.setStyle(TableStyle([
		...
	]))

表にフォントを設定する

('FONT', 始点, 終点, fontname, size)
('FONT', (0, 0), (2, 3), self.font_name, 10)
('FONT', (0, 0), (-1, -1), self.font_name, 10)

表を罫線で囲む

	('BOX', 始点, 終点, 太さ, color)
	('BOX', (0, 0), (2, 3), 1, colors.black)
	('BOX', (0, 0), (-1, -1), 1, colors.black)

四角の内側に罫線を書く

	('INNERGRID', 始点, 終点, 太さ, color)
	('INNERGRID', (0, 0), (2, 3), 1, colors.black)
	('INNERGRID', (0, 0), (-1, -1), 1, colors.black)

フォントの場所を指定

	('VALIGN', 始点, 終点, TOP or MIDDLE or BOTTOM)
	('VALIGN', (0, 0), (0, 3), TOP)
	('VALIGN', (1, 0), (1, 3), MIDDLE)
	('VALIGN', (2, 0), (2, 3), BOTTOM)

セルの結合

	('SPAN', 始点, 終点)
	('SPAN', (0,0), (0, 1))
	('SPAN', (2, 2) (2, 3))


指定した場所に線を引く
- 横線

	('LINEBEFORE', 始点, 終点, 太さ, color)
	('LINEBEFORE', (2, 1), (2, 2), 1, colors.black)

– 縦線

	('LINEABOVE', 始点, 終点, 太さ, color)
	('LINEABOVE', (0, 0), (0, 0), 1, colors.black)

テーブルを書き出す位置を指定

	table.wrapOn(pdf_canvas, 145*mm, 235*mm)
	table.wrapOn(pdf_canvas, 145*mm, 235*mm)

なんとなく基礎を理解したので、次は実際に書いていきたいと思います。

ubuntuでデフォルトのpathをpython3.8にしたい

### python3.8インストール
$ sudo apt install -y python3.8

### 入っているpython
$ python -V
Python 2.7.17
$ python3 -V
Python 3.6.9
$ python3.8 -V
Python 3.8.0

$ ll /usr/bin/python*
lrwxrwxrwx 1 root root 9 Apr 16 2018 /usr/bin/python -> python2.7*
lrwxrwxrwx 1 root root 9 Apr 16 2018 /usr/bin/python2 -> python2.7*
-rwxr-xr-x 1 root root 3637096 Apr 15 17:20 /usr/bin/python2.7*
lrwxrwxrwx 1 root root 9 Oct 25 2018 /usr/bin/python3 -> python3.6*
-rwxr-xr-x 1 root root 1018 Oct 28 2017 /usr/bin/python3-jsondiff*
-rwxr-xr-x 1 root root 3661 Oct 28 2017 /usr/bin/python3-jsonpatch*
-rwxr-xr-x 1 root root 1342 May 1 2016 /usr/bin/python3-jsonpointer*
-rwxr-xr-x 1 root root 398 Nov 15 2017 /usr/bin/python3-jsonschema*
-rwxr-xr-x 2 root root 4526456 Apr 18 01:56 /usr/bin/python3.6*
-rwxr-xr-x 2 root root 4526456 Apr 18 01:56 /usr/bin/python3.6m*
-rwxr-xr-x 1 root root 5203488 Oct 28 2019 /usr/bin/python3.8*
lrwxrwxrwx 1 root root 10 Oct 25 2018 /usr/bin/python3m -> python3.6m*

$ cd /usr/bin
$ sudo rm python
$ sudo ln -s python3.8* python
$ python -V
Python 3.8.0

class.__dict__[‘attribute’]

class Test(object):
	def __init__(self):
		self.test = 1

t = Test()
print(t.__dict__['test'])

[vagrant@localhost python]$ python app.py
1

クラスのattributeには、class.__dict__[‘attribute’]というアクセス方法がある
呼び出しの方法で便利なのね。

pythonのclassととコンストラクタ

基本型

class Tea:
	def test(self):
		print("this is mugicha")

tea = Tea()
tea.test()

[vagrant@localhost python]$ python app.py
this is mugicha

メソッドの中で、インスタンスが生成されるときに自動的に呼び出されるメソッドのことをコンストラクタと言う。
コンストラクタを定義する際には、initというメソッドを作成する

class Tea:
	def __init__(self, num):
		self.num = num; 

	def test(self):
		print("this is mugicha v{}".format(self.num))

tea = Tea(2)
tea.test()

[vagrant@localhost python]$ python app.py
this is mugicha v2

selfはインスタンス自身を表す

最小二乗法

まず、散布図を作成します。

import matplotlib.pyplot as plt 

x = [1,2,3,4,5]
y = [1571,1630,1681,1603,1623]

plt.scatter(x, y)

合計距離の最小値を求める
D = 5Σ[t=1]*{yl – (w0 + w1xl)}^2

実装する

import numpy as np
import matplotlib.pyplot as plt 

x = np.array([1,2,3,4,5])
y = np.array([1571,1630,1681,1603,1623])

def reg1dim(x, y):
	a = np.dot(x, y)/ (x ** 2).sum()
	return a 

a = reg1dim(x, y)

plt.scatter(x, y, color="k")
plt.plot([0,x.max()], [0,a * x.max()])

ああああああああああ、全然やりたいことと違う
plotする時に、0からスタートすると駄目なのか。。

平均(mean)は、np.mean()だから、こうか?

x = np.array([1,2,3,4,5])
y = np.array([1571,1630,1681,1603,1623])

m = np.mean(y)

def reg1dim(x, y):
	a = np.dot(x, y)/ (x ** 2).sum()
	return a 

a = reg1dim(x, y)

plt.scatter(x, y, color="k")
plt.plot([0,x.max()], [m,a * x.max()])

あれ、なんかちゃうなー、 [m,a * x.max()]のところがおかしい。。

最小二乗法はこういう図になるはずなんだけど。。

確率変数

変数Xが確率Pで得られる確率は、P(X)
Xが飛び飛びの場合は、離散型確率変数
続くものは、連続型確率変数(身長、体重、経過時間など)
-> 正規分布、指数分布、スチューデントのt分布、パレート分布、ロジスティック分布などがある。

P(X) = f(x)

ヒストグラムはplt.hist(x)

import numpy as np 
import matplotlib.pyplot as plt 

x = np.random.normal(40, 10, 1000)

plt.hist(x)

離散確率分布は、ベル・カーブ=正規分布と呼ばれる釣鐘型に近づく。

確率

probabilityを指定する

import numpy as np 
n = np.random.choice(["a","b","c","d"], p=[0.8, 0.1, 0.05, 0.05])
print(n)

8割の確率で”a”が出力される
[vagrant@localhost python]$ python app.py
a

アルファベットではなく、数字で指定も可能

n = np.random.choice(4, p=[0.8, 0.1, 0.05, 0.05])
import numpy as np 
n = np.random.choice(4, size=10, p=[0.8, 0.1, 0.05, 0.05])
print(n)

numpyに限らず、ランダム関数は面白いね。
[vagrant@localhost python]$ python app.py
[0 0 0 0 0 0 3 0 0 0]

import numpy as np 
import pandas as pd 
import scipy.stats 

a = pd.Series([5,2,4,9])
print(a.describe())

[vagrant@localhost python]$ python app.py
count 4.00000
mean 5.00000
std 2.94392
min 2.00000
25% 3.50000
50% 4.50000
75% 6.00000
max 9.00000
dtype: float64

固有値と固有ベクトル

Ax = λEx
λを固有値、xを固有ベクトルと言う
(A – λE)x = 0
線形変換でベクトルの回転が起こらず、拡大・縮小のみで表現

2×2の行列の場合、固有値と固有ベクトルは必ず2ペア存在する。

import numpy as np

import numpy.linalg as LA
a = np.array([[1,0],[0,2]])
print(a)

print(LA.eig(a))

b = np.array([[2,5],[3, -8]])

print(b)
print(LA.eig(b))

[vagrant@localhost python]$ python app.py
[[1 0]
[0 2]]
(array([1., 2.]), array([[1., 0.],
[0., 1.]]))
[[ 2 5]
[ 3 -8]]
(array([ 3.32455532, -9.32455532]), array([[ 0.96665615, -0.40390206],
[ 0.25607791, 0.91480224]]))

なるほど、確かに2ペアあります。
LA.eig(x)が固有値、固有ベクトルの計算ですね。

c = np.random.randint(-10,10,size=(3,3))

w,v = LA.eig(c)
print(w)
print(v)

[vagrant@localhost python]$ python app.py
[ 4.97854958+7.44028681j 4.97854958-7.44028681j -9.95709916+0.j ]
[[ 0.08381118-0.45630028j 0.08381118+0.45630028j 0.41009134+0.j ]
[ 0.81099969+0.j 0.81099969-0.j -0.22863604+0.j ]
[ 0.30533936+0.18388344j 0.30533936-0.18388344j 0.88292166+0.j ]]

有向線分(矢印)の計算

要はベクトル計算です

from numpy import array

v1 = array([2,5])
v2 = array([3,9])

print(v1+v2)
print(v1-v2)
print(v1*v2)
print(v1.dot(v2))

掛け算(*)はarrayの要素同士の計算
内積を使うにはdotメソッドを使用する
[vagrant@localhost python]$ python app.py
[ 5 14]
[-1 -4]
[ 6 45]
51

スカラー倍だと、単純に係数を描ければOKですね。
print(v1*5)

内積: 対応する成分同士を掛け算してそれらの和を取る
a1b1 + a2b2 … + anbn = nΣi=1*aibi
内積の公式
= ||a|| ||b||*cosθ
a = (2,1), b = (1,3)の時、 = √5 * √10 * √2/2 = 5

内積が0のベクトルは直行
|a| |b| *cos90° = 0