2012年5月17日木曜日

[Python, pylab]how to transform graphics with 3-by-3 transformation matrix.

pylabでベジエ曲線が描けたので、今度は変換行列で、変換を行ってみます。
# -*- coding: utf-8 -*-
import pylab
from math import radians, sin, cos, tan

def make_bezier(p0, p1, p2, p3):
    # ベジエ曲線の公式
    # t: 0.0~1.0までの値 0.0のとき、始点をplotし、1.0のとき、終点をplotする。
    def formula(t, p0, p1, p2, p3):
        return ((1-t)**3)*p0 + (3*t)*((1-t)**2)*p1 + 3*(t**2)*(1-t)*p2 +(t**3)*p3
    def _bezier(t):
        return [formula(t, p0[i],p1[i],p2[i],p3[i]) for i in (0, 1)]
    return _bezier

def transform(x, y, m):
    return (x*m[0] + y*m[3] + m[6], \
            x*m[1] + y*m[4] + m[7], \
            x*m[2] + y*m[5] + m[8])

if __name__ == '__main__':
    t = pylab.arange(0.0, 1.001, 0.01)
    bazier = make_bezier((0, 0), (0, 3), (3, 0), (3, 3))

    # 変換なし
    m = (1, 0, 0, \
         0, 1, 0, \
         0, 0, 1)

    coordinates = [(x, y) for x, y, z in (transform(x, y, m) for x, y in zip(*bazier(t)))]
    (xs,ys) = zip(*coordinates)
    pylab.plot(xs, ys)
    
    # 平行移動 (3, 3)
    m = (1, 0, 0, \
         0, 1, 0, \
         3, 3, 1)

    coordinates = [(x, y) for x, y, z in (transform(x, y, m) for x, y in zip(*bazier(t)))]
    (xs,ys) = zip(*coordinates)
    pylab.plot(xs, ys)

    # 拡大 (-1.5, -1.5) ※原点対照に反転し、1.5培する。
    m = (-1.5, 0, 0, \
         0, -1.5, 0, \
         0, 0, 1)

    coordinates = [(x, y) for x, y, z in (transform(x, y, m) for x, y in zip(*bazier(t)))]
    (xs,ys) = zip(*coordinates)
    pylab.plot(xs, ys)

    # 回転 60°
    r = radians(60)
    m = (cos(r), sin(r), 0, \
         -sin(r), cos(r), 0, \
         -5, 5, 1)

    coordinates = [(x, y) for x, y, z in (transform(x, y, m) for x, y in zip(*bazier(t)))]
    (xs,ys) = zip(*coordinates)
    pylab.plot(xs, ys)

    # 傾斜 a=15° b=20°
    a = radians(-15)
    b = radians(-20)
    m = (1, tan(a), 0, \
         tan(b), 1, 0, \
         -5, 5, 1)

    coordinates = [(x, y) for x, y, z in (transform(x, y, m) for x, y in zip(*bazier(t)))]
    (xs,ys) = zip(*coordinates)
    pylab.plot(xs, ys)

    pylab.grid()
    pylab.axis([-15, 15, -15, 15])
    pylab.show()

2012年5月16日水曜日

[Python,pylab]how to plot bezier curve.

pylabの実験のために、ベジエ曲線を描いてみました。 ベジエ曲線を描くためのメソッドを使用するのではなく、 数式で座標を計算してプロットしました。
>>> import pylab
>>> def bezier(p0, p1, p2, p3):
        def f(t, p0, p1, p2, p3):
            return ((1-t)**3)*p0 + (3*t)*((1-t)**2)*p1 + 3*(t**2)*(1-t)*p2 +(t**3)*p3
        def _bezier(t):
     return [f(t, p0[i],p1[i],p2[i],p3[i]) for i in (0, 1)]
        return _bezier

>>> t = pylab.arange(0.0, 1.0, 0.01)
>>> f = bezier((2, 2), (3, 4), (4.5, 4), (5, 1.5))
>>> pylab.plot(*f(t))
>>> pylab.axis([0, 6, 0, 6])
>>> pylab.show()

確かにベジエ曲線が描けました。

2012年3月8日木曜日

python mapserver-6.0.2 mapscript layerObj NameError

MapServerの調査をしています。 SWIG MapScript APIのpython版にバグがあるようです。 以下のようなコードを書くと、例外が発生します。
>>>import mapscript

>>>map = mapscript.mapObj('./x.map')
>>>layer = mapscript.layerObj(map)
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/local/lib/python2.7/site-packages/MapScript-6.0.2-py2.7-linux-x86_64.egg/mapscript.py", line 1381, in __init__
    if args and len(args)!=0:
NameError: global name 'args' is not defined

mapscript.pyをのぞいてみると、確かに"args"という変数は未定義です。
class layerObj(_object):
    __swig_setmethods__ = {}
    __setattr__ = lambda self, name, value: _swig_setattr(self, layerObj, name, value)
    __swig_getmethods__ = {}

    # 略

    def __init__(self, map = None):
        this = _mapscript.new_layerObj(map)
        try: self.this.append(this)
        except: self.this = this
        if 1:
                 if args and len(args)!=0: #'args' is not defined!
                       self.p_map=args[0]
                 else:
                       self.p_map=None

    # 略

しょうがないので、以下のように修正し、python-mapscriptをインストールしなおしました。
class layerObj(_object):
    __swig_setmethods__ = {}
    __setattr__ = lambda self, name, value: _swig_setattr(self, layerObj, name, value)
    __swig_getmethods__ = {}

    # 略

    def __init__(self, map = None):
        this = _mapscript.new_layerObj(map)
        try: self.this.append(this)
        except: self.this = this
        #if 1:
        #         if args and len(args)!=0: #'args' is not defined!
        #               self.p_map=args[0]
        #         else:
        #               self.p_map=None
        self.p_map = map
    # 略
これで一応動きました。 追記: classObjのコンストラクターも同様に修正が必要でした。 あと、既知のバグみたいです。 MapServer Issue Tracker "MapScript classObj Error" http://trac.osgeo.org/mapserver/ticket/3940

2012年2月23日木曜日

easy_install bad interpreter

pythonでモジュールのインストールに使う、“easy_install”をインストールして使おうとしたところ、
↓こんなエラーがでました。
$ sudo easy_install
-bash: /usr/local/bin/easy_install: .: bad interpreter: Permission denied


shebang(シェルスクリプトの1行目の#!で始まる行)を確認すると

#!.
# EASY-INSTALL-ENTRY-SCRIPT: 'setuptools==0.6c11','console_scripts','easy_install'
__requires__ = 'setuptools==0.6c11'
import sys
from pkg_resources import load_entry_point

と、#!.になっていたので、pythonの実行ファイルのパスを指定したらエラーが起こらなくなりました。

$ sudo easy_install
error: No urls, filenames, or requirements specified (see --help)

なぜ、shebangがそんな風になっていたのか、原因は調べていません。

2012年2月21日火曜日

mysql-python MySQLdb ImportError: libmysqlclient_r.so.15

mysql-python(MySQLdb)をインストールして、以下のエラーが発生した場合、
共有オブジェクトにパスが通ってないのかもしれません。
その場合、ldconfigを使用して、当該shared objectにパスを通すと、動くようになります。

$ python
>>> import MySQLdb
Traceback (most recent call last):
File "", line 1, in
File "build/bdist.linux-i686/egg/MySQLdb/__init__.py", line 19, in
File "build/bdist.linux-i686/egg/_mysql.py", line 7, in
File "build/bdist.linux-i686/egg/_mysql.py", line 6, in __bootstrap__
ImportError: libmysqlclient_r.so.15: cannot open shared object file: No such file or directory
>>>

$ sudo vi /etc/ld.so.conf
Include ld.so.conf.d/*.conf
/usr/local/lib
/usr/lib/mysql ←これを追加。

$ sudo ldconfig

$ python
>>> import MySQLdb
>>>

2012年1月19日木曜日

python MySQLdb で取得したデータを Jinja2でrenderすると UnicodeDecodeError

MySQLから取得したデータをJinja2を使って出力する場合、
MySQLdbモジュールのconnect関数でConnectionオブジェクトを取得する際に、
use_unicodeとcharset引数を設定し、取得結果の文字列をunicodeで保持する必要があります。

API - Jinja2 2.7-dev documentation Unicode
http://jinja.pocoo.org/docs/api/#unicode

下記の記述があります。
Jinja2 is using Unicode internally which means that you have to pass Unicode objects to the render function or bytestrings that only consist of ASCII characters.
訳:
Jinja2 の内部処理はUnicodeを使用しているので、render関数にはUnicodeオブジェクトかASCII文字のみからなるバイト文字列を渡す必要があります。

MySQLdb User's Guide MySQLdb Functions and attributes
http://mysql-python.sourceforge.net/MySQLdb.html#functions-and-attributes
connect(parameters...)
use_unicode
charset

以下に実例を示します。

$ python
Python 2.7.1 (r271:86832, Nov 10 2011, 09:26:52) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import MySQLdb as db
>>> import jinja2 as j2
>>> def get_rows_with(con):
...     with con:
...         cur = con.cursor()
...         cur.execute("select * from test_table")
...         rows = cur.fetchall()
...         cur.close()
...     return rows
... 
>>> t = j2.Template('{% for row in rows %}{{ row[0] }} | {{ row[1] }}\n{% endfor %}')
>>> con = db.connect(host='localhost', db='test', user='test_user', passwd='xxxx')
>>> rows = get_rows_with(con)
>>> print t.render(rows=rows)
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/local/lib/python2.7/site-packages/Jinja2-2.6-py2.7.egg/jinja2/environment.py", line 894, in render
    return self.environment.handle_exception(exc_info, True)
  File "