pensize()だけじゃない?Python Turtleで線の太さを制御する代替テクニック
turtle.pensize()
は、Pythonのタートルグラフィックスモジュールにおいて、描画される線の太さ(ペンのサイズ)を設定するための関数です。
基本的な使い方
この関数は引数として数値を1つ取ります。この数値が線の太さになります。
import turtle
# タートルオブジェクトの作成
t = turtle.Turtle()
# ペンのサイズを5ピクセルに設定
t.pensize(5)
# これ以降の描画は太さ5の線になる
t.forward(100)
t.right(90)
t.forward(100)
turtle.done()
上記の例では、t.pensize(5)
とすることで、タートルt
が描画する線の太さが5ピクセルになります。
引数なしの場合
もしturtle.pensize()
を引数なしで呼び出した場合、それは現在のペンの太さを返す関数として機能します。
import turtle
t = turtle.Turtle()
# 初期状態のペンの太さを表示(通常は1)
print(f"初期のペンの太さ: {t.pensize()}")
# ペンのサイズを設定
t.pensize(10)
# 設定後のペンの太さを表示
print(f"設定後のペンの太さ: {t.pensize()}")
turtle.done()
turtle.pensize()
: 現在設定されている線の太さ(ピクセル単位の数値)を返します。turtle.pensize(width)
: 描画する線の太さをwidth
(ピクセル単位の数値)に設定します。
よくあるエラーとその原因
a. AttributeError: 'module' object has no attribute 'pensize'
または 'Turtle' object has no attribute 'pensize'
-
原因2: オブジェクト指向と関数型の混同
turtle
モジュールには、直接関数を呼び出す方法(例:turtle.pensize(5)
)と、Turtle
オブジェクトを作成してそのメソッドを呼び出す方法(例:t = turtle.Turtle(); t.pensize(5)
)の2種類があります。これらを混同するとエラーになります。- 例えば、
t = turtle.Turtle()
でタートルオブジェクトt
を作成したのに、turtle.pensize(5)
のようにモジュール名でpensize
を呼び出すと、t
には反映されません。あるいは、turtle.Turtle().pensize(5)
のように、無名の一時的なタートルオブジェクトに対して設定しようとして、その後の描画がデフォルトの太さのままになることがあります。 - トラブルシューティング
- 特定のタートルオブジェクトのペンサイズを変更したい場合は、必ずそのオブジェクトのメソッドとして呼び出します。
import turtle my_turtle = turtle.Turtle() my_turtle.pensize(5) # OK # turtle.pensize(5) # これは別の(デフォルトの)タートルに適用されるか、意図しない動作になる
- モジュールのグローバルな設定を変更したい場合は、
turtle.
を付けて呼び出します。import turtle turtle.pensize(5) # OK (デフォルトのタートルに適用される)
- 特定のタートルオブジェクトのペンサイズを変更したい場合は、必ずそのオブジェクトのメソッドとして呼び出します。
-
- Pythonは、モジュールをインポートする際に、まず現在のディレクトリ内を探します。もし、あなたのPythonスクリプトの名前が
turtle.py
だった場合、Pythonは標準のturtle
モジュールではなく、あなた自身のturtle.py
をインポートしようとします。その結果、あなたのファイルにはpensize
という属性がないため、AttributeError
が発生します。 - トラブルシューティング
スクリプトのファイル名をmy_turtle_drawing.py
やgraphics_app.py
など、turtle.py
以外の名前に変更してください。
- Pythonは、モジュールをインポートする際に、まず現在のディレクトリ内を探します。もし、あなたのPythonスクリプトの名前が
b. ペンサイズを変更しても描画に反映されない
-
原因2: 複数のタートルオブジェクトを扱っている
- 複数の
turtle.Turtle()
オブジェクトを作成している場合、pensize()
を呼び出すタートルオブジェクトを間違えている可能性があります。例えば、t1
というタートルのペンサイズを変更したつもりが、実際にはt2
で描画していた、といったケースです。 - トラブルシューティング
どのタートルオブジェクトに対してpensize()
を呼び出しているか、そしてどのタートルオブジェクトで描画しているかを明確に確認してください。import turtle t1 = turtle.Turtle() t2 = turtle.Turtle() t1.pensize(5) # t1のペンサイズを設定 t2.pensize(10) # t2のペンサイズを設定 t1.circle(50) # t1で描画される(太さ5) t2.forward(100) # t2で描画される(太さ10) turtle.done()
- 複数の
-
原因1:
t.reset()
の呼び出し後であるturtle.reset()
は、タートルの状態(位置、向き、ペン色、ペンサイズなど)を初期状態に戻します。そのため、pensize()
で設定した後にreset()
を呼び出すと、ペンサイズがリセットされてしまいます。- トラブルシューティング
pensize()
の設定は、reset()
を呼び出した後に再度行ってください。import turtle t = turtle.Turtle() t.pensize(10) t.forward(50) t.reset() # ここでペンサイズもリセットされる t.pensize(5) # 再度設定する必要がある t.forward(50) turtle.done()
c. TypeError: pensize() takes 1 positional argument but 2 were given
または pensize() takes 1 positional argument but 0 were given
- 原因: 引数の数の間違い
pensize()
は、線の太さを設定する場合は1つの引数(数値)を取ります。現在のペンサイズを取得する場合は引数を取らない(t.pensize()
)で呼び出します。- 引数を2つ以上渡したり、設定したいのに引数を渡さなかったりすると
TypeError
が発生します。 - トラブルシューティング
- 太さを設定する場合:
t.pensize(数値)
- 太さを取得する場合:
t.pensize()
- 太さを設定する場合:
d. ValueError: bad width
または Tkinter.TclError: bad width "-5"
- 原因: 無効な引数を渡した
pensize()
の引数には、0以上の整数または浮動小数点数を指定する必要があります。負の値を渡したり、数値ではない文字列(例:t.pensize("太い")
)を渡したりするとエラーになります。- トラブルシューティング
pensize()
には、t.pensize(3)
のように有効な数値を渡してください。
- turtle.done()またはturtle.mainloop()を最後に追加する
タートルグラフィックスのウィンドウがすぐに閉じてしまう場合、プログラムの最後にturtle.done()
またはturtle.mainloop()
(より現代的なアプローチ)を追加することで、ユーザーが手動で閉じるまでウィンドウを開いたままにすることができます。これはエラーとは直接関係ありませんが、結果を確認しやすくするために重要です。 - インポートの確認
import turtle
が正しく行われていることを確認してください。 - コードの簡略化と隔離
もし複雑なプログラムで問題が発生した場合、turtle.pensize()
に関連する部分だけを抜き出して、最小限のコードでテストしてみると、原因を特定しやすくなります。 - エラーメッセージを注意深く読む
Pythonのエラーメッセージは、問題の原因を特定する上で非常に役立ちます。特に、AttributeError
やTypeError
の場合、どのオブジェクトのどの属性で問題が発生しているかが示されます。
基本的な線の太さの設定
最も基本的な使い方です。特定の太さの線を描画したい場合に用います。
import turtle
# タートルオブジェクトの作成
t = turtle.Turtle()
# ペンのサイズを5ピクセルに設定
t.pensize(5)
# 前に100ピクセル進む(太さ5の線が描かれる)
t.forward(100)
# 右に90度向きを変える
t.right(90)
# さらに100ピクセル進む(太さ5の線が描かれる)
t.forward(100)
# 描画ウィンドウを閉じるまで待機
turtle.done()
解説
t.pensize(5)
を呼び出すことで、その後のt
による描画がすべて5ピクセルの太さになります。
ペンサイズの取得
引数なしでpensize()
を呼び出すと、現在のペンの太さを取得できます。
import turtle
t = turtle.Turtle()
# 初期状態のペンの太さを取得して表示(デフォルトは通常1)
initial_size = t.pensize()
print(f"初期のペンの太さ: {initial_size}ピクセル")
# ペンのサイズを8ピクセルに設定
t.pensize(8)
t.forward(50)
# 設定後のペンの太さを取得して表示
current_size = t.pensize()
print(f"設定後のペンの太さ: {current_size}ピクセル")
t.right(90)
t.forward(50)
turtle.done()
解説
t.pensize()
のように引数を渡さずに呼び出すと、現在タートルに設定されているペンサイズが返されます。これを使って、プログラムの途中で現在の設定を確認することができます。
異なる太さの線を描く
プログラムの途中でpensize()
を再度呼び出すことで、線の太さを変更しながら描画できます。
import turtle
t = turtle.Turtle()
# 最初の正方形を細い線で描く
t.pensize(2)
for _ in range(4):
t.forward(80)
t.right(90)
# 少し間隔を空ける
t.penup()
t.forward(100)
t.pendown()
# 次の正方形を太い線で描く
t.pensize(10)
for _ in range(4):
t.forward(80)
t.right(90)
turtle.done()
解説
1つ目の正方形を描く前にt.pensize(2)
で太さを2に設定し、2つ目の正方形を描く前にt.pensize(10)
で太さを10に設定しています。これにより、同じ図形でも異なる太さで描画できます。
アニメーションでペンサイズを変化させる
pensize()
をループ内で使うことで、線の太さを連続的に変化させるアニメーション効果を作成できます。
import turtle
import time # 一時停止のためにインポート
t = turtle.Turtle()
t.speed(0) # 描画速度を最速に設定
# 円を描きながらペンサイズを変化させる
for i in range(1, 21): # ペンサイズを1から20まで変化させる
t.pensize(i)
t.circle(i * 5) # 円の半径もペンサイズに合わせて大きくする
t.right(15) # 少しずつ向きを変える
turtle.done()
解説
for
ループの中でt.pensize(i)
を呼び出すことで、ループごとに線の太さが徐々に太くなっていきます。同時に円の半径も大きくすることで、渦巻きのような視覚効果が生まれます。
ユーザーに線の太さを入力させ、それに応じて描画することも可能です。
import turtle
t = turtle.Turtle()
# ユーザーにペンサイズを入力させる
try:
user_size = int(turtle.textinput("ペンサイズ", "線の太さを入力してください (1-20):"))
if 1 <= user_size <= 20:
t.pensize(user_size)
else:
print("無効な入力です。デフォルトの太さ(3)を使用します。")
t.pensize(3)
except ValueError:
print("数値ではありません。デフォルトの太さ(3)を使用します。")
t.pensize(3)
# 正方形を描画
for _ in range(4):
t.forward(100)
t.right(90)
turtle.done()
解説
turtle.textinput()
を使ってユーザーから数値の入力を受け取ります。入力された値は文字列なので、int()
で整数に変換し、エラーハンドリング(try-except
ブロック)も行っています。これにより、ユーザーが入力した太さで図形が描画されます。
turtle.width()
これはturtle.pensize()
の**エイリアス(別名)**です。機能的には全く同じであり、単に関数名が違うだけです。
import turtle
t = turtle.Turtle()
# pensize()と同じように機能する
t.width(5)
t.forward(100)
t.right(90)
# width()も引数なしで現在の太さを返す
current_width = t.width()
print(f"現在の線の太さ: {current_width}")
t.forward(100)
turtle.done()
解説
turtle.width()
はturtle.pensize()
と完全に同じ機能を持つため、どちらを使っても結果は同じです。コードの読みやすさや個人の好みに応じて使い分けることができます。
turtle.setheading() や t.setx(), t.sety() などによる点描
これは厳密には線の太さを設定する代替ではありませんが、線を引かないで図形を描画するという点で、線そのものの太さを変更するのではなく、描画方法を変えるアプローチです。点を連続して打つことで、太い線のように見せることもできます。
import turtle
t = turtle.Turtle()
t.speed(0) # 高速化
# ペンを下ろす
t.pendown()
# ペンサイズを非常に細く設定(あるいはデフォルトのまま)
t.pensize(1)
# 点を連続して打ち、太い線のように見せる
# この例では、点のサイズ(dotの引数)が太さの代わりになる
for i in range(200):
t.dot(10) # 10ピクセルの大きさの点を打つ
t.forward(2) # 少し進む
t.left(2) # 少し曲がる
turtle.done()
解説
t.dot(size)
は、タートルの現在の位置に指定されたサイズの点を描画します。これを連続して行うことで、線の太さとは異なる方法で「太い」表現を実現できます。これはpensize()
の直接の代替というよりは、太い線に見える別の描画方法です。
これは直接的なpensize()
の代替ではありませんが、描画される線の見た目の太さが、スクリーンの設定によって相対的に変わる可能性があるという点で関連があります。
例えば、turtle.screensize(canvwidth, canvheight)
やturtle.setworldcoordinates(llx, lly, urx, ury)
を使ってキャンバスのサイズや座標系を変更すると、同じpensize(5)
でも、描画される線のピクセル数そのものは変わらなくても、ユーザーが見る表示上での相対的な太さの感じ方が変わる可能性があります。
import turtle
# ウィンドウを小さく設定した場合
# turtle.setup(width=400, height=300)
# turtle.screensize(canvwidth=200, canvheight=150) # キャンバスを小さくする
t = turtle.Turtle()
t.pensize(5) # 5ピクセルの線
t.forward(100)
t.right(90)
t.forward(100)
# 別の例:カスタム座標系
# turtle.setworldcoordinates(-100, -100, 100, 100)
# この場合、pensize(5)は、-100から100までの範囲で5ピクセルとなるため、
# 見た目の相対的な太さが変わる可能性がある。
turtle.done()
解説
これはpensize()
の機能そのものを代替するものではなく、pensize()
で設定した絶対的なピクセル単位の太さが、表示されるウィンドウや座標系の設定によって、見た目の相対的な印象に影響を与える可能性があるという点です。通常、この設定をいじることは稀で、線の太さそのものを変えるにはpensize()
を使います。
- スクリーン・座標系設定
pensize()
で設定した太さが、表示スケールによって見た目の相対的な太さの印象に影響を与えることがありますが、直接的な代替方法ではありません。 - t.dot(size)
線を引く代わりに点を打つことで、太い表現を代替的に実現できます。線の概念とは異なります。 - turtle.width()
turtle.pensize()
と完全に同じ機能を持つエイリアスです。最も直接的な代替です。