•  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

연구실(bwlee42)/251109

최근 수정 시각 : 2025-11-09 23:30:06 | 조회수 : 56


목차

1. 합성함수 그래프 그리기
1.1. 개요 및 코드
1.2. 실행

1. 합성함수 그래프 그리기

1.1. 개요 및 코드

matplotlib.animation을 통해 합성함수 그래프를 그려보자.
합성함수가 그려지는 과정을 시뮬레이션으로 쉽게 알아보자는 목적으로 만들었다.하지만 볼 사람이 아무도 없을 것으로 예상된다

파일명은 function composition 줄여서 fc로 했고, _(숫자)는 버전이다.

코딩은 직접 할 시간 없어서사실 능력도 안 된다 챗지피티한테 맡겼다.
프롬프트는 내가 직접 짰다.

프롬프트는 잘 알아먹는데, 에러 로그는 잘 못 잡는다. 어느정도 타협하고 만들었다.

fc_7.py(누르면 펼쳐짐)
import tkinter as tk
from tkinter import messagebox
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

def start_animation():
    f_expr = f_entry.get()
    g_expr = g_entry.get()

    if not f_expr or not g_expr:
        messagebox.showerror("Error", "f(x)와 g(x)를 모두 입력하세요!")
        return

    try:
        f = lambda x: eval(f_expr, {"x": x, "np": np, "__builtins__": {}})
        g = lambda x: eval(g_expr, {"x": x, "np": np, "__builtins__": {}})
    except Exception as e:
        messagebox.showerror("Error", f"함수 입력 오류: {e}")
        return

    # x값 범위
    x_vals = np.linspace(-3, 3, 200)

    # f, g(f(x)) 전체 계산
    f_all, gf_all = [], []
    for x in x_vals:
        y_f = f(x)
        if not isinstance(y_f, (list, tuple, np.ndarray)):
            y_f = [y_f]
        f_all.extend(y_f)
        gf_all.extend([g(y) for y in y_f])
    f_all = np.array(f_all)
    gf_all = np.array(gf_all)

    # ---------------------------
    # 애니메이션 패널
    # ---------------------------
    fig, axes = plt.subplots(1,3,figsize=(15,4))

    # f 패널
    axes[0].plot(x_vals, [np.mean(f(x)) if isinstance(f(x),(list,tuple,np.ndarray)) else f(x) for x in x_vals], color='lightblue')
    axes[0].set_title('f(x)')
    axes[0].set_xlabel('x')
    axes[0].set_ylabel('f(x)')
    dot_f, = axes[0].plot([],[], 'ro')
    trail_f, = axes[0].plot([],[], 'b', lw=2)
    axes[0].set_xlim(min(x_vals), max(x_vals))
    axes[0].set_ylim(min(f_all)-0.5, max(f_all)+0.5)

    # g 패널
    g_all_sorted = np.sort(f_all)
    g_vals = [g(y) for y in g_all_sorted]
    axes[1].plot(g_all_sorted, g_vals, color='lightgreen')
    axes[1].set_title('g(y)')
    axes[1].set_xlabel('f(x)')
    axes[1].set_ylabel('g(f(x))')
    dot_g, = axes[1].plot([],[], 'ro')
    trail_g_scatter = axes[1].scatter([],[], c=[], cmap='Greens', s=50)
    axes[1].set_xlim(min(f_all)-0.5, max(f_all)+0.5)
    axes[1].set_ylim(min(gf_all)-0.5, max(gf_all)+0.5)

    # h 패널
    axes[2].set_title('h(x) = g(f(x))')
    axes[2].set_xlabel('x')
    axes[2].set_ylabel('h(x)')
    dot_h, = axes[2].plot([],[], 'ro')
    trail_h, = axes[2].plot([],[], 'r', lw=2)
    axes[2].set_xlim(min(x_vals), max(x_vals))
    axes[2].set_ylim(min(gf_all)-0.5, max(gf_all)+0.5)

    # ---------------------------
    # 히스토리
    # ---------------------------
    x_hist_f, y_hist_f = [], []
    x_hist_h, y_hist_h = [], []
    trail_g_count = {}

    # ---------------------------
    # 애니메이션 업데이트
    # ---------------------------
    def update(frame):
        x = x_vals[frame]
        y_f_raw = f(x)
        if not isinstance(y_f_raw,(list,tuple,np.ndarray)):
            y_f_vals = [y_f_raw]
        else:
            y_f_vals = y_f_raw
        y_h_vals = [g(y) for y in y_f_vals]

        # f
        dot_f.set_data([x]*len(y_f_vals), y_f_vals)
        x_hist_f.extend([x]*len(y_f_vals))
        y_hist_f.extend(y_f_vals)
        trail_f.set_data(x_hist_f, y_hist_f)

        # g
        dot_g.set_data(y_f_vals, y_h_vals)
        for xf,yf in zip(y_f_vals,y_h_vals):
            key = (xf,yf)
            trail_g_count[key] = trail_g_count.get(key,0)+1

        xs,ys,cs=[],[],[]
        for (xf,yf),count in trail_g_count.items():
            xs.append(xf)
            ys.append(yf)
            cs.append(min(count,10))
        if xs:
            trail_g_scatter.set_offsets(np.c_[xs,ys])
            trail_g_scatter.set_array(np.array(cs))

        # h
        dot_h.set_data([x]*len(y_h_vals), y_h_vals)
        x_hist_h.extend([x]*len(y_h_vals))
        y_hist_h.extend(y_h_vals)
        trail_h.set_data(x_hist_h, y_hist_h)

        return dot_f, trail_f, dot_g, trail_g_scatter, dot_h, trail_h

    ani = FuncAnimation(fig, update, frames=len(x_vals), interval=50, blit=False, repeat=False)
    plt.show()


# ---------------------------
# Tkinter GUI
# ---------------------------
root = tk.Tk()
root.title("합성함수 애니메이션")

tk.Label(root, text="f(x) =").grid(row=0,column=0)
f_entry = tk.Entry(root, width=30)
f_entry.grid(row=0,column=1)
f_entry.insert(0,"x**2")

tk.Label(root, text="g(x) =").grid(row=1,column=0)
g_entry = tk.Entry(root, width=30)
g_entry.grid(row=1,column=1)
g_entry.insert(0,"x+1")

start_btn = tk.Button(root, text="Start Animation", command=start_animation)
start_btn.grid(row=2,column=0,columnspan=2,pady=10)

root.mainloop()

1.2. 실행

f(x)=x^2, g(x)=x+1인 경우 실행(누르면 펼쳐짐)
파일:fc-1.gif

정의역, 공역 표기가 좀 엉망이긴 한데 맨 왼쪽이 f, 가운데가 g, 맨 오른쪽이 f(g(x))이다. 대충 알아먹어라.
f의 치역이 g의 정의역에 대응되어 g의 치역이 h로 그려지는 모습이 보인다.

다시 보려면 창을 새로고침 해라.

파이썬은 비트 XOR 연산자라고 하는 독자적인? 연산자를 사용하기에
| 수학 표기 | 파이썬 입력 | | |
| ----------------- | ------------ | - | --------- |
| (x^2) | `x**2` | | |
| (sqrt{x}) | `np.sqrt(x)` | | |
| (sin(x)) | `np.sin(x)` | | |
| (cos(x)) | `np.cos(x)` | | |
| (e^x) | `np.exp(x)` | | |
| (ln(x)) | `np.log(x)` | | |
| ( | x | ) | `np.abs(x)` |
| (1/x) | `1/x` | | |
| (sin^2(x)) | `(np.sin(x))**2` | | |
| (frac{x^2 + 1}{x}) | `(x**2 + 1)/x` | | |
이런식으로 입력해야한다.