반응형

Slider를 꾸밀 수 있는 여러 방법에 대해서 공부를 해보자

horizontal orientation을 기준으로 진행을 할거다

먼저 기본적인 slider의 모습은 다음과 같다

사실 Mac OS 환경에서는 기본 슬라이더가 제일 이쁘다. 하지만 리눅스 환경에서는...

다음으로는 PyQT 홈페이지에서 제공하는 예제를 보자.

https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider

 

Qt Style Sheets Examples | Qt Widgets 5.15.16

 

doc.qt.io

위의 예제코드에서 vertical만 horizontal로 바꾼 것이다.

간단하게, handle은 초록색, 진행된 곳은 분홍색, 진행되지 않은 곳은 흰색으로 되는 코드이다.

QSlider::groove:vertical {
    background: red;
    position: absolute; /* absolutely position 4px from the left and right of the widget. setting margins on the widget should work too... */
    left: 4px; right: 4px;
}

QSlider::handle:vertical {
    height: 10px;
    background: green;
    margin: 0 -4px; /* expand outside the groove */
}

QSlider::add-page:vertical {
    background: white;
}

QSlider::sub-page:vertical {
    background: pink;
}

하지만 내가 만들고 싶은 것은 handle의 위치와 상관없이 slider의 배경 생각을 자유롭게 바뀌는 slider이다. 이를 위해서는 stylesheet을 사용하는 것이 아닌 다음과 같이 custom slider class를 만들어야한다.

class CustomSlider(QSlider):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
    def paintEvent(self, event):
        painter = QPainter(self)
        groove_rect = QRect(self.rect().x(), self.rect().y(), self.rect().width(), self.rect().height())
        add_page_width = int(self.value() / (self.maximum() - self.minimum()) * self.rect().width())
        add_page_rect = QRect(self.rect().x(), self.rect().y(), add_page_width, self.rect().height())
        sub_page_rect = QRect(add_page_width, self.rect().y(), self.rect().width() - add_page_width, self.rect().height())
        
        # 그루브
        groove_color = QColor("#dddddd")
        painter.fillRect(groove_rect, groove_color)
        
        # add-page
        add_page_color = QColor("#b5b5b5")
        painter.fillRect(add_page_rect, add_page_color)
        
        # sub-page
        sub_page_color = QColor("#dddddd")
        painter.fillRect(sub_page_rect, sub_page_color)
        
        # handle
        handle_center = QPoint(self.sliderPosition() * self.width() / self.maximum(), self.height() / 2)
        handle_radius = 10
        handle_color = QColor("#eeeeee")
        painter.setBrush(handle_color)
        painter.drawEllipse(handle_center, handle_radius, handle_radius)

위 코드를 빌드하면 다음과 같은 slider가 나온다. 아직은 이전 코드와 같은 기능만 가능하다.

 

반응형
반응형

이제 원하는 폴더만 출력될 수 있도록 filter를 설정해보자. 기본적으로 설정할 수 있는 filter 리스트는 아래 페이지에서 확인할 수 있다.

https://doc.qt.io/qtforpython-5/PySide2/QtCore/QDir.html

 

QDir — Qt for Python

QDir The QDir class provides access to directory structures and their contents. More… Synopsis Functions Static functions Detailed Description A QDir is used to manipulate path names, access information regarding paths and files, and manipulate the under

doc.qt.io

기본적으로 QFileSystemModel에 설정되어있는 filter는 아래와 같다.

If a filter has not been set, the default filter is AllEntries | NoDotAndDotDot | AllDirs.

여기서 우리는 원하는 조건의 폴더만 출력해보자.

먼저 나는 폴더만 출력하고 싶기 때문에 QDir.Dirs 필터를 걸겠다. 아래와 같이 폴더만 불러오게 되었지만 쓸때 없는 ., ..와 같은 표시도 나타나게 되었다. default filter가 사라졌기 때문이다. 다시 QDir.NoDotAndDotDot filter도 설정해주자.

이제 아래와 같이 깔끔하게 폴더명만 나타가게 되었다.

여기서 더 나아가 name filter도 사용해보자. A로 시작하는 폴더명만 보여주는 필터는 다음과 같이 정의할 수 있다.

nameFilters = ['A*']

이에 대한 결과는 다음과 같다. name filter에 걸리지 않은 폴더들은 다음과 같이 비활성화되었다. 비활성화된 폴더들은 선택을 할 수 없게 된다.

이에 대한 코드는 아래와 같다. 객체를 생성해서 함수를 사용할 수도 있지만 나는 CustomFileSystemModel을 정의하고 싶었기에 다음과 같이 사용을 하였다. 

class CustomFileSystemModel(QFileSystemModel):
    def __init__(self):
        super().__init__()
        nameFilters = ['A*']
        self.setNameFilters(nameFilters)
        self.setFilter(QDir.Dirs | QDir.NoDotAndDotDot)

또한 treeview가 펼쳐진 상태로 시작되었으면 한다면 다음과 같은 함수를 사용하면 된다.

self.tree.expandAll()

 

반응형
반응형

어느 정도 사용하는 파일 경로가 정해져 있지만 그때그때 사용하고 싶은 폴더를 여러개 선택할 수 있는 기능을 만들고 싶어졌다.

따라서 QTreeView와 QFileSystemModel을 사용해서 이러한 기능을 만들어보려고 한다.

참고로 PyQt5를 기준으로 구현을 진행하였다.

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

먼저 간단하게 QFileSystemModel을 상속받는 CustomFileSystemModel을 정의해주었다.

class CustomFileSystemModel(QFileSystemModel):
    def __init__(self):
        super().__init__()

그리고 이러한 CustomFileSystemModel를 QTreeView로 불러와 준다.

        self.model = CustomFileSystemModel()
        self.model.setRootPath(QDir.currentPath())

        self.tree =  QTreeView()
        self.tree.setSelectionMode(QAbstractItemView.MultiSelection)
        self.tree.setModel(self.model)

        vbox = QVBoxLayout()
        vbox.addWidget(btn1)
        vbox.addWidget(self.tree)

한번에 여러 아이템을 선택할 수 있도록 MultiSelection 모드로 설정해준다. 또한 간단하게 현재 선택한 아이템 정보를 다이나믹하게 읽을 수 있도록 간단한 버튼을 만들어주었다. 그럼 다음과 같은 화면으로 프로그램이 실행된다.

개인적으로 폴더나 파일의 이름만 불러왔으면 좋겠다. Size, Kind, ... 이런 것들이 뜨지 않게 해보자.

다음과 같이 필요없는 column을 숨겼다. 

        self.tree.hideColumn(1)
        self.tree.hideColumn(2)
        self.tree.hideColumn(3)

아래와 같이 깔끔하게 원하는 이름만 나오는 것을 확인할 수 있다.



이제 선택된 아이템들의 경로를 확인해보자. 버튼을 이용해서 선택된 아이템들의 경로를 print하는 기능을 추가하였다.

    def print(self):
        for idx in self.tree.selectedIndexes():
            print(self.model.filePath(idx))

아래와 같이 여러 개의 아이템을 선택한 후 button1을 누르면 해당 파일의 절대 경로가 나오게 된다.

아래와 같은 절대 경로가 출력된다.

/Library/Apple
/Library/Image Capture

반응형
반응형

 개인적으로 논문을 읽을때 논문의 전체적인 완성도를 중요하게 생각하는 편이다. 물론 아닌 논문들도 있다는 것을 알지만, 논문을 읽으면서 논문의 전체적인 완성도가 좋지 않으면 논문의 내용도 별로일 것이라는 편견을 가지고 읽게 된다. 반대로 완성도가 좋은 논문들은 좋은 인상을 가지고 읽기 시작하고 대체적으로 내용도 훌륭하다고 인식하게 된다. 따라서 논문의 완성도에 주요한 요인 중 하나로 들어가는 Figure를 잘 그리고 싶다는 생각을 항상하고 있었는데 이번 기회에 한번 정리를 해보려고 한다. 본 글의 중점은 이쁜 Figure 그리기!

 

이번에 사용한 python 라이브러리는 matplotlib으로 데이터 시각화에 널리 사용되는 라이브러리 중 하나이다. 설치 방법은 다음 두가지 중 하나를 본인의 환경에 맞게 선택해서 설치하면 된다.

conda install matplotlib
pip install matplotlib

 

matplotlib 라이브러리는 일반적으로 다음과 같이 정의해서 사용한다.

from matplotlib import pyplot as plt

 

 

그래프 색상표 Graph color platettes

 그래프를 그리다보면 하나의 figure에 여러 개의 그래프를 합쳐서 그려야할 때가 있다. 그런 경우에는 각각의 색상들이 명확하게 구분이 가능해야한다. 심지어 흑백으로 프린트해서 보더라도! (심사하는 사람들이 흑백으로 뽑아서 볼 수도 있으니까) 따라서 어느정도 조화로우면서도 흑백으로 봤을때도 구분이 가능한 색상 팔랫트를 추천하고자 한다.

plt.bar(a1, b1, color=['#1D5B79', '#468B97', '#e9c46a', '#f4a261', '#e76f51'])

 

color=['#abc4ab', '#a39171', '#dcc9b6', '#727d71', '#6d4c3d']

 

color=['#16697a', '#489fb5', '#82c0cc', '#ede7e3', '#ffa62b']

 

color=['#8cb369', '#f4e285', '#f4a259', '#5b8e7d', '#bc4b51']

 

color=['#d88c9a', '#f2d0a9', '#f1e3d3', '#99c1b9', '#8e7dbe']

 

color=['#ed6a5a', '#f4f1bb', '#9bc1bc', '#5ca4a9', '#e6ebe0']

 

color=['#f79256', '#fbd1a2', '#7dcfb6', '#00b2ca', '#1d4e89']

막대 그래프 패턴 넣기 Add hatch style for bar graph

막대 그래프에 색상을 넣는 것이 부담스럽다면 패턴을 넣는 방식으로 구분하는 것도 가능하다. hatch라는 키워드를 사용해서 검색을 하면 나오는데 색상 없이 그냥 패턴만 넣는 것도 가능하지만 다음과 같이 색상과 패턴을 함께 사용하는 것도 가능하다.

plt.bar(a1, b1, color=color, hatch=['/', '//', '|', '+', 'x'])

하지만 난 개인적으로 패턴을 넣는 막대 그래프는 하얀색 배경을 사용하는 것이 깔끔해 보인다고 생각한다. (그래프가 작을때 더 이쁜듯)

 

반응형
반응형

본 글에서 사용한 pytorch의 버전은 1.13.0이다.

종종 pytorch을 사용하다 보면 임의의 배열을 만들 필요가 생긴다. 그럴때 유용한 코드를 공유한다.

 

zeros

0으로 채워진 주어진 사이즈의 tensor를 만든다.

a = torch.zeros((2,2))
print(a.shape)
#torch.Size([2, 2])
print(a)
#tensor([[0., 0.],
#        [0., 0.]])

 

ones

1로 채워진 주어진 사이즈의 tensor를 만든다.

a = torch.ones((2, 2))
print(a.shape)
print(a)
#torch.Size([2, 2])
#tensor([[1., 1.],
#        [1., 1.]])

empty

초기화 되지 않은 값으로 주어진 사이즈의 tensor를 만든다.

a = torch.empty((2, 2))
print(a.shape)
#torch.Size([2, 2])

 

References

https://pytorch.org/docs/stable/torch.html

 

torch — PyTorch 2.0 documentation

Shortcuts

pytorch.org

 

반응형
반응형
from PIL import Image

PIL Image 모듈을 사용하기 위해서 위와 같이 import하는 것이 편하다.

img = Image.open('./help.jpeg')

이렇게 이미지를 불러오면 RGB 채널을 가진 3 channel의 이미지를 불러온다.

np.array(img).shape
#(225, 225, 3)

numpy array로 변환해서 확인하면 다음과 같이 확인할 수 있다.

이미지를 grayscale 그러니까 1 channel로 불러오고 싶으면 다음과 같이 변환을 시키면 된다.

img = Image.open('./help.jpeg').convert('L')
np.array(img).shape
#(225, 225)

혹은 grayscale로 불러온 이미지를 다시 RGB 이미지로 변환시키고 싶으면 다음과 같이 변환 시키면 된다.

img = img.convert('RGB')
np.array(img).shape
#(225, 225, 3)

 

References

https://pillow.readthedocs.io/en/stable/reference/Image.html

 

Image Module

The Image module provides a class with the same name which is used to represent a PIL image. The module also provides a number of factory functions, including functions to load images from files, a...

pillow.readthedocs.io

 

반응형
반응형

How to convert to python script to exec file with options

 

PyInstaller는 python script를 python interpreter나 추가적인 module 설치 없이 파일 하나로 동작할 수 있게 실행 파일을 만들어주는 패키지이다.

기본적인 사용 방법은 다음과 같다.

pyinstaller hello.py

이번에는 추가적으로 사용할 수 있는 옵션들 소개와 사용 예시를 소개하려고 한다. 물론 보다 자세한 설명은 공식 사이트에 있다.

이번 포스팅에서 사용할 hello.py 스크립트의 내용은 다음과 같다.

import argparse
import cv2

parser = argparse.ArgumentParser()
parser.add_argument('--name', type=str, default='world')
args = parser.parse_args()

def main():
    img_path = './help.jpeg'
    img = cv2.imread(img_path)
    
    print('hello ' + args.name)
    print(img.shape)

    return
if __name__ == '__main__':
    main()

스크립트와 같은 위치에 있는 help.jpeg라는 이미지와 name이라는 명령어 인자를 읽어와 hello name과 이미지 사이즈를 출력하는 간단한 코드이다. python interpreter로 간단하게 실행을 한다면 다음과 같이 출력이 된다.

(pytorch) hyeonjeong@baghyeonjeongs-MacBook-Pro Study % python hello.py --name=world    
hello world
(225, 225, 3)

이러한 script를 실행파일로 만들 때 다음과 같은 옵션들을 사용할 수 있다.

-F, --onefile

pyinstaller를 사용해서 실행파일을 생성하게 되면 프로그램에 필요한 여러 파일들이 생성된다. 이러한 추가적인 파일 없이 실행파일을 하나의 bundle로 묶어서 만들어 주는 옵션이다. 다음과 같이 두 가지 방법으로 사용할 수 있다.

pyinstaller -F hello.py
pyinstaller --onefile hello.py

이 옵션을 사용하여 실행파일을 생성하면 dist 폴더 안에 hello라는 폴더가 생성되지 않고 바로 hello라는 실행파일이 생성된다.

-y, --noconfirm

이미 pyinstaller로 실행파일을 생성한 후에 script를 수정하고 다시 생성하고 싶을 때 파일의 삭제나 대체하겠다는 입력 없이 바로 대체하여 생성시켜 주는 옵션이다.

pyinstaller -y hello.py
pyinstaller --noconfirm hello.py

--add-data <SRC;DEST or SRC:DEST>

이미지나 텍스트 파일과 같이 script에서 사용되는 추가 파일들을 실행파일에 포함시키는 옵션이다. 다음과 같이 사용할 수 있다.

이때 윈도우의 경우에는 ;를 사용하고 linux나 MacOS와 같은 대부분의 unix 시스템에서는 :를 사용하여 소스파일과 저장될 폴더를 구분하여 사용한다.

pyinstaller -F --add-data="help.jpeg:." hello.py

위의 예제에서는 script와 이미지파일이 같은 폴더 내에 있었기 때문에 이미지 경로를 단순하게./help.jpeg라고 하였지만 실행파일로 만들어지는 순간 run-time으로 임시 폴더에 있는 이미지 파일을 불러와야 하기 때문에 경로를 수정해 주어야 한다.

import argparse
import cv2
import sys
import os

parser = argparse.ArgumentParser()
parser.add_argument('--name', type=str, default='earth')
args = parser.parse_args()

def main():
    img_path = os.path.join(getattr(sys, '_MEIPASS'), 'help.jpeg')
    img = cv2.imread(img_path)
    
    print('hello ' + args.name)
    print(img.shape)

    return
if __name__ == '__main__':
    main()

sys 모듈을 추가로 import 하고 img_path에 sys._MEIPASS 경로에 있는 help.jpeg 이미지 경로로 수정했다.

 

With Argparse

당연하게도 만들어진 실행파일에 인자를 받아서 사용할 수 있다. 실행파일을 생성할 때는 추가로 해야 할 옵션을 없고 생성된 실행파일을 사용할 때 python interpreter를 사용해서 실행하는 것과 같이 뒤에 추가로 붙여서 사용하면 된다.

./dist/hello --name=earth
hello earth
(225, 225, 3)

 

Reference

https://pyinstaller.org/en/stable/index.html

 

PyInstaller Manual — PyInstaller 5.8.0 documentation

PyInstaller bundles a Python application and all its dependencies into a single package. The user can run the packaged app without installing a Python interpreter or any modules. PyInstaller supports Python 3.7 and newer, and correctly bundles many major P

pyinstaller.org

https://docs.python.org/ko/3/library/argparse.html

 

argparse — Parser for command-line options, arguments and sub-commands

Source code: Lib/argparse.py Tutorial: This page contains the API reference information. For a more gentle introduction to Python command-line parsing, have a look at the argparse tutorial. The arg...

docs.python.org

 

반응형
반응형

How to convert python script to exec file

 

기본적인 사용법

최근 파이썬으로 쓰여있는 코드를 다른 사람들이 함부로 볼 수 없게 실행파일로 만들어야 하는 일이 생겼었다.

구글링을 하다가 아주 적당한 패키지를 발견했다. 바로바로 PyInstaller

공식 사이트 설명에 따르면 python interpreter나 module의 설치 없이 실행할 수 있는 파일을 만들어 준다고 한다.

Window, Linux, MacOS에서 모두 사용할 수 있지만 cross-compile은 불가능하다고 한다. 즉, 윈도우에서 만들고 리눅스에서 사용은 안된다는 것.

설치 방법은 아주 간단하다. 본인이 원하는 환경에 따라서 둘 중 하나를 선택하면 된다.

conda install pyinstaller
pip install pyinstaller

기본적인 사용 방법도 아주 간단하다. 

먼저 실행파일로 만들기 원하는 python script를 준비한다. 예시 파일 이름은 hello.py

print('hello world')

그러면 다음과 같이 pyinstaller hello.py 형태로 사용할 수 있다.

(pytorch) hyeonjeong@baghyeonjeongs-MacBook-Pro Study % pyinstaller hello.py
487 INFO: PyInstaller: 5.6.2
487 INFO: Python: 3.9.15 (conda)
509 INFO: Platform: macOS-10.16-x86_64-i386-64bit
510 INFO: wrote /Users/hyeonjeong/Study/hello.spec
515 INFO: UPX is not available.
516 INFO: Extending PYTHONPATH with paths

그럼 다음과 같이 build, dist 폴더와 pythonscript.spec 파일이 생성된다.

(pytorch) hyeonjeong@baghyeonjeongs-MacBook-Pro Study % ls  
build		dist		hello.py	hello.spec

여기서 우리가 원하는 실행 파일은 dist 폴더 안에 pythonscript 이름의 폴더 안에 pythonscript 이름으로 생성되어 있다.

(pytorch) hyeonjeong@baghyeonjeongs-MacBook-Pro Study % ./dist/hello/hello
hello world

PyInstaller Manual

https://pyinstaller.org/en/stable/

 

PyInstaller Manual — PyInstaller 5.8.0 documentation

PyInstaller bundles a Python application and all its dependencies into a single package. The user can run the packaged app without installing a Python interpreter or any modules. PyInstaller supports Python 3.7 and newer, and correctly bundles many major P

pyinstaller.org

 

반응형

+ Recent posts