見出し画像

python(tkinter)で関数グラフを描くプログラムを作ろう(発展編)

この記事は前回の記事の続きです。前回の記事を見ていない方は下のリンクからご覧ください。

発展編として、今回は前回作成した関数類に色々付け足していきます。


原点Oを書く

前回の初期ウィンドウは下のような感じで原点が描かれていませんでした。

これでは原点がわかりづらいので、原点Oを文字として書いてみましょう。tkinterで文字を書くには次のようなコードを書きます。

canvas変数.create_text(x座標,y座標,text='書く文字',font=('フォント',文字サイズ),fill='色'))

fontとfillは無理に書く必要はありません。指定しなくても動作します。これを使い、原点Oを書いてみましょう。reset関数のx軸,y軸を書くプログラムの下にこのように1行追加します。

    canvas.create_text(258,258,text='O')

これを追加して実行すると、ウィンドウは下のようになるはずです。

実行結果

しっかり原点Oが表示されるようになりました。

グラフの色指定

前回のプログラムでは、描画したグラフはすべて赤色で表示されていました。しかし、これだとグラフを複数描いたときにどれがどの式のグラフかがわかりにくいですよね。そこで、グラフの色を指定できるようにしましょう。これをやるためにはdraw関数に色指定用の引数を追加し、また入力部のg関数にも色を入力する部分を追加します。これは結構大規模な変更になってしまうのでここの項は載せませんが、最後の全体プログラムコードに載せたのでそれを参照してください。

x切片,y切片の表示

次はグラフ上にx切片とy切片を点として表示してみましょう。しかし、tkinterでは点は打てないので、代わりに小さい円を描きます。円を描くには$${\verb|create_oval|}$$関数を使います。この関数はちょっと特殊で、長方形基準で円を描きます。つまりは下の図のような感じです。

真ん中の楕円を描くときは外の長方形が基準になる


$${\verb|create_oval|}$$関数の構文は下のようになります。これのあとにfillやoutlineなどのキーワード引数を指定することもできます。

canvas変数.create_oval(x1,y1,x2,y2)

基本的にこれを使っていきますが、こちらも変更箇所が複数あるので、最後にまとめて載せます。
ただし、交点と言ってもm=0やy1=0になるときのみの判定なので交点が小数の時はうまく判定してくれません(特にy1=0が条件のx切片)。

式の表示

最後にグラフへの式表示をしてみましょう。結構面倒ではありますが、わかりやすくするためには必要です。draw関数の引数nlistは係数の配列なので、これを利用します。draw関数の最初で出力用の文字列も作っておきましょう。$${\verb|n=len(nlist)-1|}$$の下に次のプログラムを追加します。

    ###出力用文字列
    put = 'y='
    for p in range(0,n+1):
        if p == (n-1):
            if nlist[p] == 1:
                if p == 0:
                    put += 'x'
                else:
                    put += '+x'
            elif nlist[p] == -1:
                put += '-x'
            elif nlist[p] > 0:
                if p == 0:
                    put += '%sx' % str(k(nlist[p]))
                else:
                    put += '+%sx' % str(k(nlist[p]))
            elif nlist[p] < 0:
                put += '%sx' % str(k(nlist[p]))
        elif p == n:
            if nlist[p] > 0:
                if p == 0:
                    put += str(k(nlist[p]))
                else:
                    put += '+%s' % str(k(nlist[p]))
            elif nlist[p] < 0:
                put += str(k(nlist[p]))
        elif nlist[p] == 1:
            if p == 0:
                put += 'x^%s' % str(n-p)
            else:
                put += '+x^%s' % str(n-p)
        elif nlist[p] == -1:
            put += '-x^%s' % str(n-p)
        elif nlist[p] > 0:
            if p == 0:
                put += '%sx^%s' % (str(k(nlist[p])),str(n-p))
            else:
                put += '+%sx^%s' % (str(k(nlist[p])),str(n-p))
        elif nlist[p] < 0:
            put += '%sx^%s' % (str(k(nlist[p])),str(n-p))

さて、ここではk関数というまだ定義してない関数が出てきてしまっていますね。なのでdraw関数の前にk関数を追加します。

###小数のいらない.0を削除(1.0 → 1, 0.250 → 0.25など)
def k(number):
    if isinstance(number,float) and number.is_integer():
        return int(number)
    return number

ここでdraw関数の上のプログラムの下に$${\verb|print(put)|}$$を追加して実行してみると、シェルに描いた関数の式が表示されるはずです。今回はシェルに表示するわけではないので、変数に割り当てておきます。これを表示するのは関数を描いた後になります。表示タイミングについては下の項の全体プログラムコードをご覧ください。

全体のプログラムコード

さて、下のプログラムが完全版で完成形です。解説しきれなかったところ、まだ紹介していないところも載せています。

from tkinter import *
tk = Tk()
tk.title("graph")
canvas = Canvas(tk,width=500,height=500)
canvas.pack()

###グラフ画面の初期化
def reset():
    canvas.delete('all')
    for X in range(0,50):
        canvas.create_line(10+X*10,0,10+X*10,500,fill="lightgray")
    for Y in range(0,50):
        canvas.create_line(0,10+Y*10,500,10+Y*10,fill="lightgray")
    for X in range(-1,49,5):
        canvas.create_line(10+X*10,0,10+X*10,500,fill="gray")
    for Y in range(-1,49,5):
        canvas.create_line(0,10+Y*10,500,10+Y*10,fill="gray")
    canvas.create_line(0,250,500,250)
    canvas.create_line(250,0,250,500)
    canvas.create_text(258,258,text='O')

###座標変換
def co(con,xy):
    if xy == 1:
        return ((con+25)*10)
    elif xy == 2:
        return ((con-25)*-10)
    else:
        return None

###小数のいらない.0を削除(1.0 → 1, 0.250 → 0.25など)
def k(number):
    if isinstance(number,float) and number.is_integer():
        return int(number)
    return number


###描画部分
def draw(nlist,color):
    n = len(nlist) - 1
    ###出力用文字列
    put = 'y='
    for p in range(0,n+1):
        if p == (n-1):
            if nlist[p] == 1:
                if p == 0:
                    put += 'x'
                else:
                    put += '+x'
            elif nlist[p] == -1:
                put += '-x'
            elif nlist[p] > 0:
                if p == 0:
                    put += '%sx' % str(k(nlist[p]))
                else:
                    put += '+%sx' % str(k(nlist[p]))
            elif nlist[p] < 0:
                put += '%sx' % str(k(nlist[p]))
        elif p == n:
            if nlist[p] > 0:
                if p == 0:
                    put += str(k(nlist[p]))
                else:
                    put += '+%s' % str(k(nlist[p]))
            elif nlist[p] < 0:
                put += str(k(nlist[p]))
        elif nlist[p] == 1:
            if p == 0:
                put += 'x^%s' % str(n-p)
            else:
                put += '+x^%s' % str(n-p)
        elif nlist[p] == -1:
            put += '-x^%s' % str(n-p)
        elif nlist[p] > 0:
            if p == 0:
                put += '%sx^%s' % (str(k(nlist[p])),str(n-p))
            else:
                put += '+%sx^%s' % (str(k(nlist[p])),str(n-p))
        elif nlist[p] < 0:
            put += '%sx^%s' % (str(k(nlist[p])),str(n-p))
    x1 = -25
    y1 = -25
    x2 = 25
    y2 = 25
    if n == 0:
        ### 0次関数
        y1 = nlist[0]
        y2 = nlist[0]
        canvas.create_line(co(x1,1),co(y1,2),co(x2,1),co(y2,2),fill=color)
        canvas.create_oval(co(-0.2,1),co(y1+0.2,2),co(0.2,1),co(y2-0.2,2),
                           fill=color)
        canvas.create_text(co(-22,1),co(y1+1,2),text=put,fill=color)
    elif n == 1:
        ### 1次関数
        x1 = (-25 - nlist[1]) / nlist[0]
        x2 = (25 - nlist[1]) / nlist[0]
        canvas.create_line(co(x1,1),co(y1,2),co(x2,1),co(y2,2),fill=color)
        canvas.create_oval(co(-0.2,1),co(nlist[1]+0.2,2),co(0.2,1),
                           co(nlist[1]-0.2,2),fill=color)
        canvas.create_oval(co(-nlist[1]/nlist[0]-0.2,1),co(0.2,2),
                           co(-nlist[1]/nlist[0]+0.2,1),co(-0.2,2),fill=color)
        if nlist[0] > 0:
            canvas.create_text(co(x1+3,1),co(y1+2,2),text=put,fill=color)
        else:
            canvas.create_text(co(x1-3,1),co(y1+2,2),text=put,fill=color)
    else:
        ### 2次以上の関数
        flag = False
        for m in range(x1*10,x2*10):
            m = m / 10
            nlist_n = n
            y1 = 0
            y2 = 0
            for nl in nlist:
                y1 += nl * (m ** nlist_n)
                y2 += nl * ((m+0.1) ** nlist_n)
                nlist_n -= 1
            canvas.create_line(co(m,1),co(y1,2),co(m+0.1,1),co(y2,2),fill=color)
            if m == 0 or y1 == 0:
                canvas.create_oval(co(m-0.2,1),co(y1+0.2,2),co(m+0.2,1),
                                   co(y1-0.2,2),fill=color)
            if m > -22 and y1 > -22 and m < 22 and y1 < 22 and flag == False:
                canvas.create_text(co(m,1),co(y1,2),text=put,fill=color)
                flag = True
                
###入力部分
def g():
    try:
        f = input("関数の係数をカンマ(,)区切りで入力してください>>>").split(',')
        c = input("""色の名前(英語)か、16進数のカラーコード(#000000など)を入力してください。
入力せずにEnterを押した場合は初期値の赤色になります。>>>""")
        if c == '':
            c = "Red"
        for num in range(0,len(f)):
            f[num] = float(f[num])
        draw(f,c)
    except NameError:
        ###エラー処理
        print("指定以外の値が入力されました。入力し直してください。")

###グラフの初期化
reset()
###説明文
print("""
このプログラムは関数のグラフを描くプログラムです。
g()と入力するとグラフを追加でき、reset()で描いたグラフを全て消せます。
g()では関数の係数を次数順のカンマ区切りで入力してください。
入力例1:1,-3,1,-1 出力:y = x^3 - 3x^2 + x - 1 のグラフ
入力例2:-2,1 出力:y = -2x + 1 のグラフ
入力例3:1,0,1 出力:y = x^2 + 1 のグラフ
""")




これを実行して、適当に関数を入れてみるとこのようになると思います。

適当に入力していくとこんな感じになるはず

これで前回のコードは真の完成と言えるでしょう。割と宿題も楽にできるプログラムになったと思います。最後まで見ていただきありがとうございました!

この記事が気に入ったらサポートをしてみませんか?