Python 공부 기록-31

김시헌·2025년 6월 11일

버튼 생성하기

Plotly를 활용하면 아주 간편히 버튼 생성이 가능합니다. 버튼을 활용하여 사용자가 직접 그래프 스타일 변경, 데이터 변경 등을 선택할수 있습니다. Plotly 인터렉티브 환경의 끝판왕 이라고 볼수있습니다.

버튼 생성 방법

fig.update_layout(
    updatemenus=[
        dict(
            type = "buttons",
            buttons=list([dict(label="None",
                    method= 버튼을 눌렀을때 어떤 기능을 수행할지 설정,
                    args = [...]method 에 맞춰 구체적인 동작 지정,
                    args2 = [...]버튼을 2번째 눌렀을때 구체적인 동작 지정,
                    label = 버튼 텍스트)]),
            pad=버튼 패딩,
            x= 버튼위치 x좌표,
            y= 버튼위치 y좌표,
            showactive={True, False} 현재 버튼 활성화 여부 판단,
            active = 처음 그래프 생성 시 활성화 버튼 번호
        ),])

[사용 함수]

  • fig.update_layout()

[함수 input 내용]

  • updatemenus = dict() 형태로 아래의 정보들을 지정합니다.
    • type = "buttons"
    • buttons = [...] 버튼의 기능 관련 정보를 각각 dict() 형태로 넣습니다.
      • method= {"restyle", "relayout", "update", "animate"}
        • restyle : 데이터 변경 or 그래프 타입 변경 액션
        • relayout : 그래프 레이아웃(타이틀, 축 등등..) 변경 액션
        • update : 위의 두개를 동시에 수행할때
        • animate : 애니메이션 플레이 스탑 버튼
      • args = [...] 위의method 에 맞춰 구체적인 동작 지정
      • label = 버튼 내부 레이블 지정
    • pad ={"r": 오른쪽, "l": 왼쪽, "t": 위쪽, "b":아랫쪽} 버튼의 pading을 지정합니다.
    • x = 버튼 위치의 x좌표
    • y = 버튼 위치의 y좌표
    • active = 처음 그래프 생성 시 활성화 되어있는 버튼의 index 번호

그래프 Type이 변경되는 예제

random_x=np.random.randint(1, 101, 100)
random_y=np.random.randint(1, 101, 100)

fig=px.Figure()

fig.add_trace(px.Scatter(x=random_x, y=random_y, mode='markers'))

fig.update_layout(
    updatemenus=[
        dict(
            type="buttons",
            buttons=list([
                dict(args=["type", "scatter"],
                     label="Scatter Plot",
                     method="restyle"),
                dict(args=["type", "bar"],
                     label="Bar Chart",
                     method="restyle")
            ]),
        ),
    ]
)

fig.show()
  • 기본적으로 px.Sxatter()을 사용하여 산포도 그래프를 나타냅니다.
  • 버튼 2개를 추가해줍니다.
# 1번 버튼
dict(args=["type", "scatter"],
     label="Scatter Plot",
     method="restyle"),
     
# 2번 버튼
dict(args=["type", "bar"],
     label="Bar Chart",
     method="restyle")
  • 1번 버튼은 type를 scatter로 지정해줬기 때문에 버튼을 클릭하면 그래프의 타입이 scatter plot형태로 바뀝니다.
  • 2번 버튼은 type를 bar로 지정해줬기 때문에 버튼을 클릭하면 그래프의 타입이 bar plot 형태로 바뀝니다.

실행 결과-1번 버튼 클릭

실행 결과-2번 버튼 클릭

그래프를 통으로 삭제 생성하는 예제

fig = px.Figure()

x = ['A', 'B', 'C', 'D']

fig.add_trace(px.Bar(name='Data 1',x=x, y=[100, 200, 500, 673]))

fig.add_trace(px.Bar(name='Data 1',x=x, y=[56, 123, 982, 213]))

fig.update_layout(
    updatemenus=[
        dict(
            type="buttons",
            buttons=list([
                dict(label="Both",
                     method="update",
                     args=[{"visible": [True, True]},
                           {"title": "Both"}]),
                dict(label="Data 1",
                     method="update",
                     args=[{"visible": [True, False]},
                           {"title": "Data 1",}]),
                dict(label="Data 2",
                     method="update",
                     args=[{"visible": [False, True]},
                           {"title": "Data 2",}]),
            ]),
        ),
    ]
)

fig.show()
  • px.bar()를 활용해서 총 2개의 막대 그래프를 생성합니다.
 # 1번 그래프
fig.add_trace(px.Bar(name='Data 1',x=x, y=[100, 200, 500, 673]))

# 2번 그래프
fig.add_trace(px.Bar(name='Data 1',x=x, y=[56, 123, 982, 213]))
  • 버튼 3개를 추가해줍니다.
# 1번 버튼
dict(label="Both",
    method="update",
    args=[{"visible": [True, True]},
    {"title": "Both"}]),

# 2번 버튼                           
dict(label="Data 1",
    method="update",
    args=[{"visible": [True, False]},
    {"title": "Data 1",}]),

# 3번 버튼
dict(label="Data 2",
    method="update",
    args=[{"visible": [False, True]},
    {"title": "Data 2",}])
  • 1번 버튼을 누르면
    • {"visible": [True, True]} : 1번 2번 그래프 모두 나타납니다.
    • {"title": "Both",} : 타이틀이 Both 로 변경됩니다.
  • 2번 버튼을 누르면
    • {"visible": [True, False]} : 1번 그래프는 나타나고 2번 그래프는 나타나지 않습니다.
    • {"title": "Data 1",} : 타이틀이 Data 1로 변경됩니다.
  • 3번 버튼을 누르면
    • {"visible": [False, True]} : 2번 그래프는 나타나고 1번 그래프는 나타나지 않습니다.
    • {"title": "Data 2",} : 타이틀이 Data 2로 변경됩니다.

실행 결과-1번 버튼 클릭

실행 결과-2번 버튼 클릭

실행 결과-3번 버튼 클릭

그래프 데이터가 변경되는 예제

x=np.linspace(-np.pi, np.pi, 10)

y1=np.sin(x)
y2=np.tan(x)

fig=px.Figure()

fig.add_traces(px.Scatter(x=x, y=y1, visible=True, showlegend=True))

fig.update_layout(
    updatemenus=[
        dict(
            type="buttons",
            buttons=list([
                dict(label="Toggle Sine / Tangent",
                     method="restyle",
                     args=[{'y': [y1]}],
                     args2=[{'y': [y2]}],
                ),

            ])
        ),
    ],
)

fig.show()       
  • px.Scatter() 를 활용해서 총 1개의 Scatter Plot을 생성합니다.
  • 1개의 버튼에 총 2개의 기능을 넣습니다.
dict(label="Toggle Sine / Tangent",
     method="restyle",
     args=[{'y': [y1]}],
     args2=[{'y': [y2]}],
                    )
  • 처음 생성했을 시 args = {'y', [y1]} 이기 때문에 y1 결과인 sin 그래프가 생성됩니다.
  • 버튼을 한번 누르면 args2 = {'y', [y2]} 이기 때문에 y2 결과인 tan 그래프가 생성됩니다.
  • 버튼을 한번 더 누르면 args = {'y', [y1]} 로 다시 원복되어 sin 그래프가 생성됩니다.

실행 결과-1

실행 결과-2

버튼 스타일 지정하기

fig.update_layout(
    updatemenus=[
        dict(
            type = "buttons",
            font_color = 텍스트 색,
            font_family = 텍스트 서체,
            font_size = 텍스트 사이즈,
            bgcolor = 배경색,
            bordercolr = 테두리색,
            borderwidth = 테두리 두깨,
        ),])

[사용 함수]

  • fig.update_layout()

[함수 input 내용]

  • updatemenus = dict() 형태로 아래의 정보들을 지정합니다.
    • type = "buttons"
    • font_color = 텍스트 색,
    • font_family = 텍스트 서체,
    • font_size = 텍스트 사이즈,
    • bgcolor = 배경색,
    • bordercolr = 테두리색,
    • borderwidth = 테두리 두깨,

예제)

fig = px.Figure()

x = ['A', 'B', 'C', 'D']

fig.add_trace(px.Bar(name='Data 1',x=x, y=[100, 200, 500, 673]))

fig.add_trace(px.Bar(name='Data 1',x=x, y=[56, 123, 982, 213]))

fig.update_layout(
    updatemenus=[
        dict(
            type="buttons",
            buttons=list([
                dict(label="Both",
                     method="update",
                     args=[{"visible": [True, True]},
                           {"title": "Both"}]),
                dict(label="Data 1",
                     method="update",
                     args=[{"visible": [True, False]},
                           {"title": "Data 1",
                            }]),
                dict(label="Data 2",
                     method="update",
                     args=[{"visible": [False, True]},
                           {"title": "Data 2",
                            }]),
            ]),
        font_color = 'red',
        font_size = 20 ,
        bgcolor = 'blue',
        borderwidth = 2

        ),
    ]
)

fig.show()
  • 버튼 스타일 변경

슬라이더 생성하기

Plotly의 슬라이더 기능을 활용하면 아주 간단한 코드로 시간의 변화 또는 범부 변화에 따른 경향 확인기 가능합니다.

express 를 활용한 슬라이더 생성

import plotly.express as px

df = px.data.gapminder()
fig = px.scatter(df, x="gdpPercap", y="lifeExp",size="pop", color="continent",
               log_x=True, size_max=55, range_x=[100,100000], range_y=[25,90],
                animation_frame="year")

fig["layout"].pop("updatemenus")
fig.show()
  • 슬라이더를 통해 변화되는 과정을 보여주고 싶은 컬럼명을 animation_frame = 에 지정합니다.
  • 본 예제에서는 animation_frame="year" 로 지정하였기 때문에 연도별 데이터 변화량을 확인 할 수 있는 슬라이더가 생성되었습니다.
  • fig["layout"].pop("updatemenus") 코드는 슬라이더 옆에 재생 버튼을 삭제하기 위해 추가했습니다. 이부분은 상황에 맞게 설정하시면 됩니다.

실행 결과

범위 슬라이더(range slider)생성

특정 범위를 선택할수 있게 도와주는 슬라이더를 범위 슬라이더(range slider) 라고 합니다. 범위 슬라이더를 추가하려면 아래 코드를 추가해야 합니다.

df = px.data.tips()

fig = px.scatter(df, x="total_bill", y="tip", color="sex",)

fig.update_layout(xaxis=dict(rangeslider_visible=True))

fig.show()

[사용 함수] - fig.update_layout()

[Input 내용] - xaxis : x축 관련 설정 - rangeslider_visible = True

  • 슬라이더 창이 그래프 아랫쪽에 생성이 되며 슬라이더 창의 범위를 마우스 드래그를 통해 설정하면 위의 그래프도 동일 범위로 변경이 됩니다.

실행 결과

직접 슬라이더 한 step 씩 만들기

직접 슬라이더 한 step 씩 만들기 위해서는 2단계의 과정이 필요합니다.

  • 1단계 : 각 스텝 별 그래프 생성합니다.
import plotly.graph_objects as go
import numpy as np

fig = go.Figure()

for step in np.arange(0, 3, 0.1):
    fig.add_trace(
        go.Scatter(
            visible=False,
            line=dict(color="#00CED1", width=6),
            name="𝜈 = " + str(step),
            x=np.arange(0, 10, 0.02),
            y=np.sin(step * np.arange(0, 10, 0.02))))
  • 총 30 개의 Scatter plot이 fig에 차례차례 쌓입니다.(np.arange(0, 3, 0.1))
  • 각각의 Scatter plot은 fig.data[i] 를 통해 index로 불러올 수 있습니다.
  • 예를들어 총 몇개의 Trace가 쌓였는지 확인하려면 아래 코드를 통해 확인이 가능합니다.
len(fig.data)
  • 2단계 : 각 스텝 별 슬라이더 데이터를 생성합니다.
steps = []
for i in range(len(fig.data)):
    step = dict(
        method="update",
        args=[{"visible": [False] * len(fig.data)},
              {"title": "Slider switched to step: " + str(i)}],  # layout attribute
    )
    step["args"][0]["visible"][i] = True  # Toggle i'th trace to "visible"
    steps.append(step)

fig.update_layout(
sliders = [dict(
    active=10,
    currentvalue={"prefix": "Frequency: "},
    pad={"t": 50},
    steps=steps
)])
  • 먼저 steps 라는 리스트에 각 step 별 조건을 dict() 형태로 담습니다.
  • 이때 가장 중요한 부분은
    • args=[{"visible": [False] * len(fig.data)} : 우선 위에서 생성한 30개의 trace를 다 visible False 로 지정합니다. 즉 모두 안보이게 처리합니다.
    • step["args"][0]["visible"][i] = True : 그다음 i번째 인덱스의 Trace만 visible =True 로 바꿔주어서 해당 step 데이터는 index가 i 번째 Trace만 보이게 되는 조건입니다.
    • 최종적으로 이렇게 만든 steps 라는 리스트를 fig.update_layout() 함수의 sliders 조건에 넣어줍니다.
fig.update_layout(
sliders = [dict(
    active=10,
    currentvalue={"prefix": "Frequency: "},
    pad={"t": 50},
    steps=steps
)])

최종 코드 종합

import plotly.graph_objects as go
import numpy as np

fig = go.Figure()

# 각 스텝 별 그래프(Trace)를 만들기
for step in np.arange(0, 3, 0.1):
    fig.add_trace(
        go.Scatter(
            visible=False,
            line=dict(color="#00CED1", width=6),
            name="𝜈 = " + str(step),
            x=np.arange(0, 10, 0.02),
            y=np.sin(step * np.arange(0, 10, 0.02))))

# 처음 그래프 생성했을땐 index 10의 Trace 가 보이게 설정
fig.data[10].visible = True

# 스텝 별 슬라이더 데이터 리스트 생성
steps = []
for i in range(len(fig.data)):
    step = dict(
        method="update",
        args=[{"visible": [False] * len(fig.data)},
              {"title": "Slider switched to step: " + str(i)}],  # layout attribute
    )
    step["args"][0]["visible"][i] = True  # Toggle i'th trace to "visible"
    steps.append(step)

# 최종 슬라이더 데이터 업데이트
fig.update_layout(
sliders = [dict(
    active=10,
    currentvalue={"prefix": "Frequency: "},
    pad={"t": 50},
    steps=steps
)])

fig.show()

실행 결과

슬라이 스타일 지정하기

fig.update_layout(
    sliders=[
        dict(
            type = "buttons",
            font_color = 텍스트 색,
            font_family = 텍스트 서체,
            font_size = 텍스트 사이즈,
            bgcolor = 배경색,
            bordercolr = 테두리색,
            borderwidth = 테두리 두깨,
        ),])

[사용 함수]

  • fig.update_layout()

[함수 input 내용]

  • sliders= dict() 형태로 아래의 정보들을 지정합니다.
    • type = "buttons"
    • font_color = 텍스트 색,
    • font_family = 텍스트 서체,
    • font_size = 텍스트 사이즈,
    • bgcolor = 배경색,
    • bordercolr = 테두리색,
    • borderwidth = 테두리 두깨,
    • ticklen = ticker 길이
    • tickcolor = ticker 색
    • tickcwidth = ticker 두깨

예제)

# Figure 생성
fig = go.Figure()

# 각 스텝 별 그래프(Trace)를 만들기
for step in np.arange(0, 3, 0.1):
    fig.add_trace(
        go.Scatter(
            visible=False,
            line=dict(color="#00CED1", width=6),
            name="𝜈 = " + str(step),
            x=np.arange(0, 10, 0.02),
            y=np.sin(step * np.arange(0, 10, 0.02))))

# 처음 그래프 생성했을땐 index 10의 Trace 가 보이게 설정
fig.data[10].visible = True

# 스텝 별 슬라이더 데이터 리스트 생성
steps = []
for i in range(len(fig.data)):
    step = dict(
        method="update",
        args=[{"visible": [False] * len(fig.data)},
              {"title": "Slider switched to step: " + str(i)}],  # layout attribute
    )
    step["args"][0]["visible"][i] = True  # Toggle i'th trace to "visible"
    steps.append(step)

# 최종 슬라이더 데이터 업데이트
fig.update_layout(
sliders = [dict(
    active=10,
    currentvalue={"prefix": "Frequency: "},
    pad={"t": 50},
    steps=steps,
    bgcolor="blue",
    font_color = "red",
    font_size= 20,
    ticklen = 3 ,
    tickcolor = "green",
)])

fig.show()

실행 결과

0개의 댓글