반응형

예전에 테스트삼아 해봤는데, 오랫만에 하니까 잘 모르는 것도 있고, 좀 바뀐 부분도 있어서 정리도 할겸 올립니다. 아래와 같은 tkinter 화면을 만들겁니다.

 

1. main.py

우선 main.py에서는 구동만 시켜주고, 화면을 구성하는 파일은 gui.py로 별도 모듈로 만들 예정입니다.

import gui

if __name__ == '__main__':
    gui.main_screen()

 

2. gui.py

import tkinter as tk


def main_screen():
    root = tk.Tk()
    root.title("GUI Sample")
    root.geometry("640x480+100+100")
    root.resizable(True,True)
    root.configure(background='white')  # 배경을 흰색으로 하고,
    # root.wm_attributes("-transparentcolor", 'white') # 흰색을 투명으로 하면 투명한 앱이 됩니다.

    #레이블
    label_1=tk.Label(root, text="위젯 테스트", width=20,height=3,fg="red",relief="solid")
    label_1.pack()
    label_2=tk.Label(root, text="위젯 테스트2", width=20, height=3, fg="blue", relief="groove")
    label_2.pack()

    #리스트박스
    listbox = tk.Listbox(root, selectmode='extended', height=0)
    listbox.insert(0, "no1")
    listbox.insert(1, "no2")
    listbox.insert(2, "no3")
    listbox.insert(3, "no4")
    listbox.insert(4, "no5")
    listbox.pack()

    #체크박스
    checkVal1 = tk.IntVar()
    checkVal2 = tk.IntVar()
    checkBtn1 = tk.Checkbutton(root, text="체크박스 고르기1", variable=checkVal1, activebackground="blue")
    checkBtn2 = tk.Checkbutton(root, text="체크박스 고르기2", variable=checkVal2, activebackground="blue")
    checkBtn1.pack()
    checkBtn2.pack()

    #라디오버튼
    radioVal1=tk.IntVar()
    radioBtn1 = tk.Radiobutton(root, text="1번", value=3, variable=radioVal1)
    radioBtn2 = tk.Radiobutton(root, text="2번", value=6, variable=radioVal1)
    radioBtn3 = tk.Radiobutton(root, text="3번", value=9, variable=radioVal1)
    radioBtn1.pack()
    radioBtn2.pack()
    radioBtn3.pack()

    #상단메뉴
    def close():
        root.quit()
        root.destroy()

    menubar = tk.Menu(root)

    menu_1 = tk.Menu(menubar, tearoff=0)
    menu_1.add_command(label="Sub Menu1-1")
    menu_1.add_command(label="Sub Menu1-2")
    menu_1.add_separator()
    menu_1.add_command(label="종료", command=close)
    menubar.add_cascade(label="Menu1", menu=menu_1)

    menu_2 = tk.Menu(menubar, tearoff=0, selectcolor="red")
    menu_2.add_radiobutton(label="Sub Menu2-1", state="disable")
    menu_2.add_radiobutton(label="Sub Menu2-2")
    menu_2.add_radiobutton(label="Sub Menu2-3")
    menubar.add_cascade(label="Menu2", menu=menu_2)

    menu_3 = tk.Menu(menubar, tearoff=0)
    menu_3.add_checkbutton(label="Sub Menu3-1")
    menu_3.add_checkbutton(label="Sub Menu3-2")
    menu_3.add_checkbutton(label="Sub Menu3-3")
    menubar.add_cascade(label="Menu3", menu=menu_3)

    root.config(menu=menubar)

    # 메뉴 버튼 (상단 메뉴바랑 상관 없음)
    menubutton = tk.Menubutton(root, text="Menu Button", relief="raised", direction="right")
    menubutton.pack()

    menu = tk.Menu(menubutton, tearoff=0)
    menu.add_command(label="Sub-1")
    menu.add_separator()
    menu.add_command(label="Sub-2")
    menu.add_command(label="Sub-3")

    menubutton["menu"] = menu

    # 배치연습
    bb1=tk.Button(root, text="(50,50)")
    bb1.place(x=50,y=50)
    bb2 = tk.Button(root, text="(130,50)",width=10, height=1)
    bb2.place(x=130, y=50)
    bb3 = tk.Button(root, text="(50,100)", border=3)
    bb3.place(x=50, y=100)
    bb4 = tk.Button(root, text="(130,100)")
    bb4.place(x=130, y=100)


    root.mainloop()
반응형
반응형

펠리칸(Pelican) 정적사이트 생성기

  파이썬하면 요즘 ML/DL, 데이터분석 등으로 엄청난 인기를 끌고 있는데요. 웹프로그래밍에서도 매우 많은 인기가 있습니다. 우리나라에서는 점유율이 많이 못미치지만, 해외에서 Django, FastAPI등은 매우 좋은 반응을 보이고 있습니다. 오늘 소개할 도구는 Django나 FastAPI와 같은 서버도구는 아닌, 파이썬으로 만들어진 정적사이트 생성기 펠리칸(Pelican)입니다.

 

1. 설치

우선 일반적인 파이썬 프로젝트 시작방법과 마찬가지로 가상환경을 만들어줍니다. (pycharm을 활용하면 쉽게 가상환경이 만들어집니다. VSCode로 진행하면 조금 까다로우니, 다른 포스팅을 참고하세요). 가상환경이 만들어지면 아래의 pip install ~ 로 pelican을 설치합니다. 

pip install pelican

 

2. 추가 라이브러리 설치

github page 배포를 위한 라이브러리 및 마크다운 문서 표시를 위한 추가 라이브러리를 설치합니다.

pip install ghp-import markdown

 

3. 프로젝트 생성

본격적인 프로젝트를 생성합니다. 첫번째 물음에서 [.]으로 되어있으면 현재 사이트에 생성한다는 의미입니다.

pelican-quickstart

생성이 완료되면 아래와 같이 프로젝트 구성이 보입니다.

 

4. 샘플 페이지 작성

content 폴더에 Hello.md파일을 작성합니다.

# hello.md #
Title: Are ‘you’ just inside your skin or is your smartphone part of you?
Date: 2018-02-26
Category: Psychology
Slug: are-you-just-inside-your-skin-or-is-your-smartphone-part-of-you

In November 2017, a gunman entered a church in Sutherland Springs in Texas, where he killed 26 people and wounded 20 others. He escaped in his car, with police and residents in hot pursuit, before losing control of [...]

 

5. 빌드

pelican content

 

6. 실행

특이하게도 실행은 output폴더로 이동해서 수행해야합니다. 이점은 다른 SSG(Static Site Generator)에 비해 조금 불편하네요. 그리고 일반적인 파이썬 프로젝트와 달리 main.py에서 실행하는게 아니고 pelican.server로 실행해야 합니다. 스크립트를 만들면 되긴 할텐데, 파이썬 공부한지가 오래되어 잘 기억이 안나네요. 

cd output
python -m pelican.server

 

<결과>

드디어 결과가 나왔습니다. 기본 구성 치고는 여러 요소들을 포함하고 있어 보이는데, 이뻐보이진 않습니다. 손대야 할 부분이 많아보이네요.

펠리칸(Pelican) 정적사이트 생성기

 

오늘은 간단히 파이썬 정적사이트 생성기인 펠리칸(pelican)에 대해 간단히 알아봤습니다. 파이썬을 좋아하시는 분들이라면 한번 시도해보셔도 좋을 것 같습니다.

반응형
반응형

시군별 평균수입/총수입 자료를 지도에 매핑해서 나타내보도록 하겠습니다.

 

아래의 자료는 시군별 평균수입/총수입 자료입니다.

aaa.csv
0.00MB

 

한가지 추가로 필요한 파일이 시군구 지형자료입니다. 아래의 파일도 같은 프로젝트 폴더에 저장하고 실행합니다.

skorea_municipalities_geo_simple.json
0.35MB

 

import folium as g
import json
import webbrowser
import pandas as pd

g_map = g.Map(location=[37.4, 127], 
            tiles='cartodbpositron', 
            # tiles = 'Stamen Terrain',
            zoom_start=7)
geo_data = json.load(open('skorea_municipalities_geo_simple.json', encoding='utf-8'))
df = pd.read_csv('aaa.csv', encoding='utf-8', dtype={'code':'str'})
g.Choropleth(geo_data=geo_data,
                data = df,
                columns=['sigun', 'avg_income'],
                key_on='feature.properties.name',
                fill_color='YlGn',
                fill_opacity=0.8
            ).add_to(g_map)
            
g_map.save('map.html')
webbrowser.open_new_tab('map.html')

fill_color옵션으로 색상 스타일을 변경할 수 있습니다. 종류는 아래와 같이 12가지 입니다.
'BuGn', 'BuPu', 'GnBu', 'OrRd', 'PuBu', 'PuBuGn', 'PuRd', 'RdPu', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd'

 

반응형
반응형

특정 폴더의 파일 전체에 대해서 일괄 수정하는 기능을 구현해 보았습니다.

add_string 함수는 파일명에 접두사 접미사를 붙여서 출력하는 기능이고,

change_string 함수는 파일명에 특정 문자열을 다른 문자열로 바꾸는 기능입니다.

 

<주의>
우선은 파일명을 확인하는 부분까지만 구현하고, 실제 변경하는 부분은 주석 처리하였습니다. 사용하실 분은 해당 부분 주석 해제후 사용하세요.
import os

def add_string(path, prefix, suffix):
    for filename in os.listdir(path):
        name_only, ext = filename.split('.')    # 파일명과 확장자로 분리
        print(name_only, ext)
        new_name = prefix + name_only + suffix + '.' + ext  # 새 파일명 조합
        print(new_name)
        # os.rename(path+filename, path+new_name)

def change_string(path, prev, next):
    for filename in os.listdir(path):
        new_name = filename.replace(prev,next)
        print(new_name)
        # os.rename(path+filename, path+new_name)

add_string('d://test', 'test','뭐뭐뭐')
change_string('d://test','abc','abcdef')

 

<원본>

 

<add_string>

 

<change_string>

반응형
반응형

Pycharm이던 Jupyter Notebook이던 Dataframe형태의 결과를 볼 때, 칼럼의 수가 많아지면 기본적으로는 중간이 ....으로 표시됩니다. 간단하게 확인만 할건데 매번 추가코드를 작성하기도 귀찮고....

 

이럴 때 옵션 하나면 간단히 처리할 수 있습니다.

# row 생략 없이 출력
pd.set_option('display.max_rows', None)
# col 생략 없이 출력
pd.set_option('display.max_columns', None)

 

누군가에겐 도움이 되었길

반응형
반응형

키보드 입력에 맞추어 비프음을 내도록 하겠습니다. 이번 프로그램을 위해서는 비프음을 내도록 하는 windsound 모듈과 키보드 인풋을 받아들이는 pynput 모듈이 필요합니다. 그 중 windwound 모듈은 기본으로 내장되어있으니 pynput 모듈만 설치해주도록 합니다.

 

1. 라이브러리 설치

pip install pynput

 

2. pynput모듈

pynput 모듈에서는 on_press 이벤트와 on_release 이벤트에 대해 리스너를 통해 입력받는 방법이 있습니다.

from pynput import keyboard

def on_press(key):
    print('Pressed Key: %s' % key)

def on_release(key):
    print('Pressed Key: %s' % key)
    if key == keyboard.Key.esc: #esc 키가 입력되면 종료
        return False
        
 # 리스너 등록방법1
listener = keyboard.Listener(
     on_press=on_press,
     on_release=on_release)
listener.start()
listener.join()

# 리스너 등록방법2
with keyboard.Listener(
    on_press=on_press,
    on_release=on_release) as listener:
    listener.join()

이런식으로 이용하면 되지만, 이번에는 동기화 방식에 의한 방법으로

from pynput import keyboard
 
with keyboard.Events() as events:
    for event in events:
        if event.key == keyboard.Key.esc:
            print("Exit!!")
            break
        if event.key == keyboard.KeyCode(char='a'):
            print("Pressed:", keyboard.KeyCode(char='a'))

와 같이 사용하려고 합니다. 이벤트의 종류와 상관없이 처리를 하게 됩니다.

 

3. winsound 모듈

winsound.Beep(음계주파수, 지속시간)

와 같이 사용합니다. 연주를 위해서는 음계에 대한 정확한 주파수를 입력해야합니다. 다행스러운 것은 한 옥타브 위의 음에 대해서는 2배의 Frequency에 해당하는 주파수를 갖고 있습니다.

 

4. 전체 소스코드

from pynput import keyboard
import winsound

# 1옥타브: C, C#, D, D#, E, F, F#, G, G#, A, A#, B
pitch = {'c_': 523, 'cs': 554, 'd_': 587, 'ds': 622, 'e_': 659,
         'f_': 698, 'fs': 740, 'g_': 784, 'gs': 831, 'a_': 880,
         'as': 932, 'b_': 988}
# 2옥타브
pitch2={}
for key, value in pitch.items():
    pitch2[key] = value * 2  # 한옥타브 위는 주파수가 2배.
print(pitch2)

# 지속시간
lasting = 100

# The event listener will be running in this block
with keyboard.Events() as events:
    for event in events:
        if event.key == keyboard.Key.esc:
            print("Exit!!")
            break
        elif event.key == keyboard.KeyCode(char='q'):
            winsound.Beep(494, lasting)
        elif event.key == keyboard.KeyCode(char='a'):
            winsound.Beep(pitch['c_'], lasting)
        elif event.key == keyboard.KeyCode(char='w'):
            winsound.Beep(pitch['cs'], lasting)
        elif event.key == keyboard.KeyCode(char='s'):
            winsound.Beep(pitch['d_'], lasting)
        elif event.key == keyboard.KeyCode(char='e'):
            winsound.Beep(pitch['ds'], lasting)
        elif (event.key == keyboard.KeyCode(char='d')) | (event.key == keyboard.KeyCode(char='r')):
            winsound.Beep(pitch['e_'], lasting)
        elif event.key == keyboard.KeyCode(char='f'):
            winsound.Beep(pitch['f_'], lasting)
        elif event.key == keyboard.KeyCode(char='t'):
            winsound.Beep(pitch['fs'], lasting)
        elif event.key == keyboard.KeyCode(char='g'):
            winsound.Beep(pitch['g_'], lasting)
        elif event.key == keyboard.KeyCode(char='y'):
            winsound.Beep(pitch['gs'], lasting)
        elif event.key == keyboard.KeyCode(char='h'):
            winsound.Beep(pitch['a_'], lasting)
        elif event.key == keyboard.KeyCode(char='u'):
            winsound.Beep(pitch['as'], lasting)
        elif (event.key == keyboard.KeyCode(char='j')) | (event.key == keyboard.KeyCode(char='i')):
            winsound.Beep(pitch['b_'], lasting)
        elif event.key == keyboard.KeyCode(char='k'):
            winsound.Beep(pitch2['c_'], lasting)
        elif event.key == keyboard.KeyCode(char='o'):
            winsound.Beep(pitch2['cs'], lasting)
        elif event.key == keyboard.KeyCode(char='l'):
            winsound.Beep(pitch2['d_'], lasting)
        elif event.key == keyboard.KeyCode(char='p'):
            winsound.Beep(pitch2['ds'], lasting)
        elif (event.key == keyboard.KeyCode(char=';')) | (event.key == keyboard.KeyCode(char='[')):
            winsound.Beep(pitch2['e_'], lasting)
        elif event.key == keyboard.KeyCode(char="'"):
            winsound.Beep(pitch2['f_'], lasting)
        elif event.key == keyboard.KeyCode(char="]"):
            winsound.Beep(pitch2['fs'], lasting)

# 빈 키(z,x,c,v... ) 에 대해 추가로 음계 할당
        elif event.key == keyboard.KeyCode(char="z"):
            winsound.Beep(pitch['c_'], lasting)
        elif event.key == keyboard.KeyCode(char="x"):
            winsound.Beep(pitch['d_'], lasting)
        elif event.key == keyboard.KeyCode(char="c"):
            winsound.Beep(pitch['e_'], lasting)
        elif event.key == keyboard.KeyCode(char="v"):
            winsound.Beep(pitch['f_'], lasting)
        elif event.key == keyboard.KeyCode(char="b"):
            winsound.Beep(pitch['g_'], lasting)
        elif event.key == keyboard.KeyCode(char="n"):
            winsound.Beep(pitch['a_'], lasting)
        elif event.key == keyboard.KeyCode(char="m"):
            winsound.Beep(pitch['b_'], lasting)
        elif event.key == keyboard.KeyCode(char=","):
            winsound.Beep(pitch2['c_'], lasting)
        elif event.key == keyboard.KeyCode(char="."):
            winsound.Beep(pitch2['d_'], lasting)
        elif event.key == keyboard.KeyCode(char="/"):
            winsound.Beep(pitch2['e_'], lasting)

 

이상으로 연주 가능한 키보드를 만들어보았습니다.

 

~~끝~~

반응형
반응형

행성들이 가운데 태양을 중심으로 공전하는 모습을 구현해보겠습니다.

 

<main.py>

import math

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.clock import Clock
import math

Window.size = (900, 900)
center_w = Window.size[0]/2
center_h = Window.size[1]/2

class Sun(Widget):
    pass

class Mercury(Widget):
    pass

class Vinus(Widget):
    pass

class Earth(Widget):
    pass

class Mars(Widget):
    pass

class Solar(Widget):
    sw_seconds = 0
    def update(self, nap):  # nap: 증분, dt delta time
        self.sw_seconds += nap

        ## Earth
        E_dis = 300   # 태양으로부터의 거리
        E_r = self.ids.earth.size[0]      # 지구 직경
        E_rv = 45 # 각도도
        self.ids.earth.pos = self.calc_pos(E_dis, E_r, E_rv)

        ## Mercury
        M_dis = 80  # 태양으로부터의 거리
        M_r = self.ids.mercury.size[0]    # 수성 직경
        M_rv = 60  # 시간에 따른 각도
        self.ids.mercury.pos = self.calc_pos(M_dis, M_r, M_rv)

        ## Vinus
        V_dis = 120  # 태양으로부터의 거리
        V_r = self.ids.vinus.size[0]  # 금성 직경
        V_rv = 50  # 시간에 따른 각도
        self.ids.vinus.pos = self.calc_pos(V_dis, V_r, V_rv)

        ## Mars
        MS_dis = 350  # 태양으로부터의 거리
        MS_r = self.ids.mars.size[0]  # 화성 직경
        MS_rv = 30  # 시간에 따른 각도
        self.ids.mars.pos = self.calc_pos(MS_dis, MS_r, MS_rv)



    def calc_pos(self, dis, radius, radial_v):
        degree = radial_v * self.sw_seconds
        pos_x = dis * math.cos(math.pi * degree / 180) + center_w
        pos_y = dis * math.sin(math.pi * degree / 180) + center_h
        pos = (pos_x, pos_y)
        return pos

class SolarApp(App):
    def build(self):
        SolarSystem = Solar()
        Clock.schedule_interval(SolarSystem.update, 1.0 / 60.0)
        return SolarSystem

if __name__ == '__main__':
    SolarApp().run()

 

<solar.kv>

<Sun>:
    size: 50, 50
    canvas:
        Color:
            rgb: 1,0,0
        Ellipse:
            size: self.size
            pos: self.pos

<Mercury>:
    size: 15, 15
    canvas:
        Color:
            rgb: 0,0,1
        Ellipse:
            size: self.size
            pos: self.pos
<Vinus>:
    size: 20, 20
    canvas:
        Color:
            rgb: 1,1,0
        Ellipse:
            size: self.size
            pos: self.pos

<Earth>:
    size: 20, 20
    canvas:
        Color:
            rgb: 0,1,1
        Ellipse:
            size: self.size
            pos: self.pos
<Mars>:
    size: 18, 18
    canvas:
        Color:
            rgb: 1,0.3,0
        Ellipse:
            size: self.size
            pos: self.pos

<Solar>:
    Sun:
        id:sun
        pos: self.parent.center
    Mercury:
        id:mercury
        pos: self.parent.center
    Vinus:
        id:vinus
        pos: self.parent.center
    Earth:
        id:earth
        pos: self.parent.center
    Mars:
        id:mars
        pos: self.parent.center

<결과>

반응형
반응형

1. hello_world.py

import PySimpleGUI as sg

sg.Window(title="Hello World", layout=[[]], margins=(100,50)).read()

 

2. hello_psg.py

import PySimpleGUI as sg

layout = [
    [sg.Text("Hello from PySimpleGUI")],
    [sg.Button("OK")]
]

window = sg.Window("Demo", layout)

while True:
    event, values = window.read()
    if event =="OK" or event == sg.WIN_CLOSED:
        break

window.close()

3. Image_Viewer.py

import PySimpleGUI as sg
import os.path
file_list_column = [
    [
        sg.Text("Image Folder"),
        sg.In(size=(25,1), enable_events=True, key="-FOLDER-"),
        sg.FolderBrowse(),
    ],
    [
        sg.Listbox(
            values=[], enable_events=True, size=(40, 20),
            key="-FILE LIST-"
        )
    ],
]
image_viewer_column = [
    [sg.Text("Choose an image from the list on the left:")],
    [sg.Text(size=(40,1), key="-TOUT-")],
    [sg.Image(key="-IMAGE-")],
]

layout = [
    [
        sg.Column(file_list_column),
        sg.VSeperator(),
        sg.Column(image_viewer_column),
    ]
]

window = sg.Window("Image Viewer", layout)

while True:
    event, values = window.read()
    if event =="Exit" or event == sg.WINDOW_CLOSED:
        break
    if event == "-FOLDER-":
        folder = values["-FOLDER-"]
        try:
            file_list = os.listdir(folder)
        except:
            file_list = []

        fnames = [
            f
            for f in file_list
            if os.path.isfile(os.path.join(folder, f))
            and f.lower().endswith((".png", ".gif"))
        ]
        window["-FILE LIST-"].update(fnames)
    elif event == "-FILE LIST-":
        try:
            filename = os.path.join(
                values["-FOLDER-"], values["-FILE LIST-"][0]
            )
            window["-TOUT-"].update(filename)
            window["-IMAGE-"].update(filename=filename)
        except:
            pass


window.close()

 

<결과>

반응형

+ Recent posts