(83)

n진수->10진수 코딩하기

https://koreanraichu.tistory.com/254 백준 2745번 풀이 문제 https://www.acmicpc.net/problem/2745 2745번: 진법 변환 B진법 수 N이 주어진다. 이 수를 10진법으로 바꿔 출력하는 프로그램을 작성하시오. 10진법을 넘어가는 진법은 숫자로 표시할 수 없는 자리가 있 koreanraichu.tistory.com 여기서 잠깐 언급했던 그거 맞다. 그것까지 주저리주저리 넣었다간 대참사 터져서 따로 뺐다. 참고로 기본 원리 역시 저기 서술되어있으므로 여기서는 생략. a = input() cipher = len(a) # 자릿수가 영어로 cipher였다니 a = a[::-1] dec_number = 0 for i in range(cipher): dec_..

강해져서 돌아온 ChatGPT에게 코딩을 시켜보자 (번외편)

아니 나 급 생각난건데 얘가 코딩한걸 보니까 변수명이 my_list 막 이렇더라고... 그래서 궁금해졌음. 과연 변수명을 지정해서 코딩할 수 있는가? 또 서버오류가 반기는거 아니냐 일단 걍 리스트를 만들어보자. 전에는 my_list였는데? 아무튼 그럼 변수명을 내가 지정해주자. 변수명은 one_to_ten으로 할거다. 사실 여기에는 숨겨진 주문이 하나 더 있는데... 다들 알겠지만, 언어가 파이썬이 아니라 자바스크립트다. 리스트 이름을 지정한 변수명으로 하는 것도 무난하게 된다. 그런데... 자바스크립트 출력 방식이 console.log만 있는 게 아니란말이지... alert로 띄우게 할 건데, alert라고 직접적으로는 얘기를 안 할거다. 사실 이거 말고 HTML 요소의 내용을 바꾸는 방법도 있긴 함...

강해져서 돌아온 ChatGPT에게 코딩을 시켜보자 (2)

https://koreanraichu.tistory.com/226 강해져서 돌아온 ChatGPT에게 코딩을 시켜보자 아니 자기가 강해져서 돌아왔대잖아요... 일단 이번에 시켜볼 것은 매우 간단한 코딩들... 뭐 import 할 수는 있겠지만 패키지 설치를 요하는 건 아닌, 그런 것들을 시켜볼거다. 여담이지만 오늘 제 koreanraichu.tistory.com 1편은 여기로 모시겠습니다 고객님. 저녁에는 좀 되는듯... 아까 서버 문제있었나? 근데 지금도 네트워크 에러가 간간이 일어나는게 얘네 서버실에 커피 엎은 것 같음. (아까 시키려던거) 입력받은 문자열 출력하기 input_string = input("문자열을 입력하세요: ") print("입력한 문자열은", input_string, "입니다.") ..

강해져서 돌아온 ChatGPT에게 코딩을 시켜보자

아니 자기가 강해져서 돌아왔대잖아요... 일단 이번에 시켜볼 것은 매우 간단한 코딩들... 뭐 import 할 수는 있겠지만 패키지 설치를 요하는 건 아닌, 그런 것들을 시켜볼거다. 여담이지만 오늘 제일 많이 본 것은... 강해져서 돌아왔다며!!! Hello, World! 출력하기 print("Hello, World!") 프로그래밍 책에서도 첫빠따로 나오는 헬로월드다. 따옴표는 ""도 되고 ''도 되는데 아무튼 저 코드 자체는 잘 됐음. 일차원 배열 만들기 반복문을 사용하지 않고 a = [1,2,3,4,5] 이런 식으로 직접 할당하는 배열 말하는거다. my_list = [i for i in range(1, 6)] print(my_list) 오 고급기술... 원래 의도했던 건 a = [1,2,3,4,5]였..

Python으로 60갑자 뽑기

참고로 60갑자가 뭔지 궁금하면 달력을 보자. 올해는 임인년이라 인월 인일 인시에 사인검 하나 나온다. (인년 인월 인일 인시 해서 사인이라 사인검이다) 60갑자는 천간 10개와 지지 12개로 이루어지는데... 어? 뭐임? 하나 할인해요? ㄴㄴ 10과 12의 최소공배수가 60임다. 천간: 갑을병정무기경신임계 지지: 자축인묘진사오미신유술해 이렇게 된다. 뒤에 있는 지지가 여러분의 띠이기도 하다. 내가 태어나는 해에도 당연히 갑자가 있고 이게 60년마다 한번씩 돌아오기 때문에 환갑 = 61세(만 60세)에 치른다. 또한 지지가 12개이기때문에 띠동갑은 12살이다. cheongan = ['갑','을','병','정','무','기','경','신','임','계'] * 12 gigi = ['자','축','인','묘'..

RE with FLASK-유효성 검사

예전에 익스트림 CRUD에 나왔던 그거 맞다. 대신 익스트림 CRUD에 비해 입력받는 항목도 적고, 형식검사도 한 가지 부분에 대해서만 진행하면 되기때문에 코드가 비교적 간소하다. 입력인자 중 공백 여부를 체크할 것은 1. 시퀀스 2. 시퀀스 이름 3. 시퀀스 정보 이고, 형식을 체크할 것은 시퀀스 하나뿐이다. DNA는 다들 아시다시피 A, T, G, C로 구성되어 있고 DNA 시퀀스에도 당연히 A, T, G, C만 들어간다. 대소문자 입력을 감안해도 atgcATGC 이렇게 여덟개다. 어? 제한효소 인식 시퀀스에는 W나 N같은 것도 있잖아요! 그건 DNA 시퀀스가 문제가 아니라 그 제한효소가 인식하는 염기가 두 개 이상이라는 소리다. 예를 들어서 GGWCC라는 인식 시퀀스를 가지는 제한효소가 있다면, 이..

RE with FLASK-시퀀스 정보

FASTA, Genbank파일을 처리할때와 달리 ipynb일때부터 직접 입력하는 시퀀스 정보는 수기로 같이 받았다. 추가가 늦었을 뿐이지... 입력란 만들면서 제일 고생했던 건 CSS였음... 망할 그리드... ㅡㅡ 아무튼. 추가한 순서는 1. HTML 2. CSS(여기서 좀 고생함) 3. JS 4. app.py JS나 Python파일은 크게 수정할 건 없고 Ajax로 주고받는 것만 추가하면 된다. checked_finder.forEach(function (i) { if (checked_finder[0].checked == true) { textarea[2].disabled = false; sequence_name.disabled = false; sequence_desc.disabled = false s..

RE with FLASK-Cutter/Finder

파일 관련 기능이 다 빠졌습니다. 아니 쓰는게 노가다여 아주. 둘 다 이식 하긴 했는데 다른데서 개고생함… ㅋㅋㅋㅋㅋ 그래요 개고생이 끼어야 코딩이지… 한번에 되면 그게 이상한거지… Cutter 그... 왜 Searcher에서 라디오버튼 선택하면 값 전송하는 건 다들 아실거고... 이걸 Cutter에도 적용해야 한다. 물론 Finder에도 적용할거다. 이게 왜 필요하냐면 입력 수단이 라디오버튼이기 때문. 그리고 라디오버튼에 각각 딸려오는 요소가 있어서, 연결된 라디오버튼이 선택되지 않았을 때 비활성화도 시켜줘야 한다. 이거 근데 Finder 가면서 소스 갈아엎음. ㅇㅇ function activate() { const checked_input = document.querySelectorAll('#typi..

RE with FLASK-Searcher 이식하기

들어가기 전에 중요한 게 하나 있다. Cutter와 Finder도 내일 이식하긴 할건데, 내일 이식하는 부분에서 FASTA/Genbank 파일 올리는거랑 결과 저장 기능은 빠진다. 그래서 원본 코드에 있던 with 어쩌고를 일단 작성 없이 서버로 보내서 텍스트 에리어에서 출력하는 걸 일차적으로 진행하고 저장-업로드 순으로 할 예정. FASTA/Genbank는 JS로 파일 받아서 파이썬으로 넘겨서 열 생각인데 그거 관련해서 로직 처리가 좀 필요하고(뼈대를 보면 라디오 버튼이다) 반대로 텍스트 파일은 파이썬에서 만들어서 JS로 넘길 생각이다. 텍스트 파일은 만들어준 거 받아서 버튼 누르면 다운로드 되게 하면 끝임. 대공사 전에... 일단 공사 전인 Searcher의 뼈대를 보자. 원래 코드에서 입력으로 받던..

Wordcloud with FLASK-뼈대 대공사 (3)

Entrez쪽 뼈대 만든거랑 버튼 얘기 있으니까 기둘려보시오 Entrez with wordcloud 뼈대 이 뼈대가 완전한 건 아닌게 글꼴 선택란이 없음.. 지금 생각중인건 어비 스윗체/둘기마요/나눔고딕정도... 아무튼 Entrez with wordcloud 뼈대도 만들었음. 출력부는 별 차이 없고, 얘는 입력 인자가 검색어랑 논문 갯수뿐이라 입력란이 간소하다. 지금은 논문 개수 입력하는 란이 없는데 그건 나중에 만들면 되고… Sample text 버튼 Text with wordcloud는 찍먹이나 해보자 하는 분들을 위한 샘플 텍스트를 제공하고 있다. 한글 2 영어 2 생각중인데 영어 하나 제보좀 해주세요… 샘플 텍스트(윤동주-별 헤는 밤) 샘플 텍스트(이육사-청포도) 샘플 텍스트 3 샘플 텍스트 4 ..

경로때문에 개노가다 한 썰 푼다

일단 개고생한 이유를 축약해드리자면... 1. 윈도우에서는 폰트 저장 경로(C:\Windows\Fonts)에 있는 걸 갖다 쓰는 게 아니라 TTF, OTF파일이 있는 경로를 직접 입력해야 갖다 쓸 수 있음. 2. 근데 리눅스는 폰트 저장 경로(/usr/share/fonts)에서 선택해서 쓸 수 있음. 그래서 개고생했습니다. OS = platform.platform() if 'Linux' in OS: default_dir = '/home' root = tkinter.Tk() root.withdraw() font_dir = '/usr/share/fonts' font_path = filedialog.askopenfilename(parent=root, initialdir=font_dir, title='Choos..

Wordcloud with FLASK-뼈대 대공사 (2)

워드클라우드부터 해서 진짜 얘까지 개 노가다의 연속이었음... 그래도 이거 미리 해놔서 Entrez는 입력부만 조금 수정하면 됩니다. 워드클라우드 경로 썰은 다른 포스트에서 풀어드림. 이게 길어서 한번에 캡처 못했음다. 입력부의 각 기능 1. 텍스트 입력란(샘플 텍스트도 있음): 샘플 텍스트는 현재 한글 두개(별 헤는 밤, 청포도)랑 영어 하나(미정)를 생각중이며, 버튼을 누르면 샘플 텍스트가 텍스트에리어에 입력된다. 길면 잘 뽑히긴 한데 영어는 뭘 해야 할 지 모르겠음. 아니 그렇다고 하이 잭 하이 마이크 하와유 이딴걸 할 순 없잖수. 논문 해 논문 2. 컬러맵 선택(이따 이미지 올려드림): 이건 밑에 털어드림. 3. 마스킹이미지 ㄱㄱ: 이미지 안 쓴다는 선택지는 없음. 4. 언어 선택(한국어는 kon..

Wordcloud/RE 경로 관련 코드 수정

아니 나도 몰랐는데 파이썬으로 OS 정보를 볼 수 있더라? 근데 맥은 내가 가지고 있는 기기가 없어서 못봤음... import platform 일단 이놈을 데려온 다음 print(platform.platform()) 을 치면 자기 컴퓨터의 OS 정보를 볼 수 있다. 그래서 이걸 어떻게 수정했냐면 OS = platform.platform() if 'Linux' in OS: default_dir = '/home' font_dir = '/usr/share/fonts' else: default_dir = 'C:\\' font_dir = 'C:\\Fonts' OS 정보를 가져와서 리눅스면 기본 경로를 이렇게 하고, 아니면(윈도우면) 이렇게 해라 이렇게 했다. 위 코드는 워드클라우드고 제한효소쪽은 파일 불러오는것 ..

Wordcloud with FLASK-뼈대 대공사

일단... 현재 완성된 부분이 여긴데 어바웃 페이지만 된다. 입력받는 란은 아직 안함. 현재 구현된 기능 1) 탭 메뉴(어바웃 페이지/텍스트/엔트레즈 탭) 2) 어바웃페이지 app.py from flask import Flask, render_template from Bio import Entrez from wordcloud import WordCloud from wordcloud import STOPWORDS import matplotlib.pyplot as plot from PIL import Image import numpy as np from argparse import FileType import tkinter from tkinter import filedialog import re from k..

n진수->10진수 코딩하기

Coding/Python 2023. 6. 16. 00:36

https://koreanraichu.tistory.com/254

 

백준 2745번 풀이

문제 https://www.acmicpc.net/problem/2745 2745번: 진법 변환 B진법 수 N이 주어진다. 이 수를 10진법으로 바꿔 출력하는 프로그램을 작성하시오. 10진법을 넘어가는 진법은 숫자로 표시할 수 없는 자리가 있

koreanraichu.tistory.com

여기서 잠깐 언급했던 그거 맞다. 그것까지 주저리주저리 넣었다간 대참사 터져서 따로 뺐다. 참고로 기본 원리 역시 저기 서술되어있으므로 여기서는 생략.

 

a = input()
cipher = len(a) # 자릿수가 영어로 cipher였다니
a = a[::-1]
dec_number = 0

for i in range(cipher):
    dec_number += int(a[i]) * (2 ** i)

print(dec_number)

https://github.com/koreanraichu/Python/blob/master/Bin%20to%20Dec.py

 

GitHub - koreanraichu/Python: Upload my file

Upload my file . Contribute to koreanraichu/Python development by creating an account on GitHub.

github.com

 

a = input()
cipher = len(a) # 자릿수가 영어로 cipher였다니
a = a[::-1]
dec_number = 0

for i in range(cipher):
    dec_number += int(a[i]) * (8 ** i)

print(dec_number)

https://github.com/koreanraichu/Python/blob/master/Oct%20to%20Dec.py

 

GitHub - koreanraichu/Python: Upload my file

Upload my file . Contribute to koreanraichu/Python development by creating an account on GitHub.

github.com

 

a = input()
cipher = len(a) # 자릿수가 영어로 cipher였다니
a = a[::-1]
dec_number = 0

Hex_letter = ['A','B','C','D','E','F']
Hex_number = [10,11,12,13,14,15]

for i in range(cipher):
    try:
        dec_number += int(a[i]) * (16 ** i)
    except:
        dec_number += Hex_number[Hex_letter.index(a[i])] * (16 ** i)

print(dec_number)

https://github.com/koreanraichu/Python/blob/master/Hex%20to%20Dec.py

 

GitHub - koreanraichu/Python: Upload my file

Upload my file . Contribute to koreanraichu/Python development by creating an account on GitHub.

github.com

코드와 깃헙은 순서대로 2, 8, 16진수. 변환하는 원리도 대충 아실 듯 하지만... 16진수는 알파벳이 껴있어서 int로 변환이 안 되는 경우가 존재한다. 알파벳의 경우 알파벳 배열과 그에 상응하는 숫자 배열을 만들어서 인덱스 찾고 인덱싱해서 값 가져오게 했다. 16진수라 여섯개 고정이라 수동입력했고.

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

강해져서 돌아온 ChatGPT에게 코딩을 시켜보자 (번외편)

Coding/Python 2023. 4. 29. 02:01

아니 나 급 생각난건데 얘가 코딩한걸 보니까 변수명이 my_list 막 이렇더라고...


그래서 궁금해졌음. 과연 변수명을 지정해서 코딩할 수 있는가? 또 서버오류가 반기는거 아니냐 


일단 걍 리스트를 만들어보자.

 

전에는 my_list였는데? 아무튼 그럼 변수명을 내가 지정해주자. 변수명은 one_to_ten으로 할거다.

 

사실 여기에는 숨겨진 주문이 하나 더 있는데... 다들 알겠지만, 언어가 파이썬이 아니라 자바스크립트다. 리스트 이름을 지정한 변수명으로 하는 것도 무난하게 된다. 그런데... 자바스크립트 출력 방식이 console.log만 있는 게 아니란말이지... alert로 띄우게 할 건데, alert라고 직접적으로는 얘기를 안 할거다.

 

사실 이거 말고 HTML 요소의 내용을 바꾸는 방법도 있긴 함. 아무튼 그렇다. ...근데 이거 파이썬 카테고리인데 왜 자바스크립트가 나왔누...

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

강해져서 돌아온 ChatGPT에게 코딩을 시켜보자 (2)

Coding/Python 2023. 3. 20. 23:51

https://koreanraichu.tistory.com/226

 

강해져서 돌아온 ChatGPT에게 코딩을 시켜보자

아니 자기가 강해져서 돌아왔대잖아요... 일단 이번에 시켜볼 것은 매우 간단한 코딩들... 뭐 import 할 수는 있겠지만 패키지 설치를 요하는 건 아닌, 그런 것들을 시켜볼거다. 여담이지만 오늘 제

koreanraichu.tistory.com

1편은 여기로 모시겠습니다 고객님. 

 

저녁에는 좀 되는듯... 아까 서버 문제있었나? 근데 지금도 네트워크 에러가 간간이 일어나는게 얘네 서버실에 커피 엎은 것 같음.


(아까 시키려던거) 입력받은 문자열 출력하기

input_string = input("문자열을 입력하세요: ")
print("입력한 문자열은", input_string, "입니다.")

가장 간단한 방식은 input()이지만, 사실 내가 알고싶은 건 이게 아니였다... 그럼 본론으로 들어가서 물어봅시다.

 

import sys

input_string = sys.stdin.readline().rstrip()  # 입력받은 문자열에서 개행 문자 제거
print("입력한 문자열은", input_string, "입니다.")

설명까지 잘 보면 알겠지만 sys.stdin.readline()이 input보다 빠른 대신 포기한 두가지 중 한가지(개행문자 안뗌)에 대해 언급하고 있다. 또한 sys.stdin.readline()을 이용하려면 import sys가 우선시되어야 하는 것도 잘 알고 있다.

 

2차원 배열 만들기

1차원 배열은 1편에서 만들었던 리스트가 1차원 배열이고, 2차원 배열은 그거 여러개를 나열해둔 것이라고 보면 된다. 일반적으로 생각하는 점(0차원)->선(1차원)->면(2차원)->입체(3차원)로 확장하는 것과 비슷한데, 리스트를 쌓으면 2차원 배열, 2차원 배열을 쭉 쌓으면 3차원 배열이 된다.

 

일단 첫번째로는 1부터 25까지 순차적으로 들어가는 5*5 배열을 만들어보자.

네트워크 에러가 뜬 후 한번 다시 만들어서 출력이 다르다. 처음 만들어 준 코드는 아래 코드가 맞다.

# 5x5 크기의 2차원 배열 생성
array_2d = []
for i in range(5):
    row = []
    for j in range(5):
        row.append(i*5 + j + 1)
    array_2d.append(row)

# 2차원 배열 출력
for row in array_2d:
    print(row)

네트워크 에러가 떠서 확인해보려고 미리 코드만 복사했었는데 2차원 배열을 생성하는 것 뿐 아니라 보기 좋게 출력하는 방법까지 제시하고 있다. 이게 왜 중요하냐면 저 코드에서 그냥 print(array_2d)로 하게 되면

[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20], [21, 22, 23, 24, 25]]

솔직히 저거 5*5 배열이니까 스무스하게 넘어가는거지 8*8이나 9*9배열에서 이렇게 출력했다간 욕 바가지로 먹고 여러분들 불로장생 할 수도 있음... 진짜로.

 

그럼 이번에는 리스트 컴프리헨션으로 정사각형 배열이 아닌 직사각형 배열을 만들어보자.

array_2d = [[j + 1 + i * 8 for j in range(8)] for i in range(6)]
print(array_2d)

역시나 좀 더 깔끔하게 뽑고 싶다면 for문을 사용하면 된다. 이 방식은 위처럼 2차원 배열을 만드는 건 동일한데, for문 두개+몇줄을 차지하던 걸 리스트 컴프리헨션으로 한 줄로 깔끔하게 줄여버린 것.

 

함수 정의하기

함수 정의가 뭐냐면 def 어쩌고로 정의하는 그거다. 근데 얘네 서버실에 진짜 누가 커피라도 쏟은건가... 에러때문에 뭘 제대로 할 수가 없음.

def add_subtract(x, y):
    # 합 계산
    add = x + y
    # 차 계산
    subtract = x - y
    # 결과 출력
    print("합:", add)
    print("차:", subtract)

간단한 함수의 정의도 매우 잘 한다. 합, 차를 구하는 함수를 만들어달래서 print문까지 같이 준건데 합따로 차따로 하는거면 리턴으로 반환했을지도...?

 

별찍기

for i in range(1, 8):
    print("*" * i)

어... 이것도 별찍기 맞긴 맞는데... 그 가운데정렬은 뭐라고 해야 됨?

 

for i in range(1, 8):
    print(" " * (7-i) + "*" * (2*i-1))

정답: 피라미드

 

배열 탐색

이건 뭐냐면 난수 10개가 들어있는 1차원 배열에서 제일 큰 수를 찾는 방법을 묻는 것이다.

import random

# 1부터 100 사이의 랜덤한 숫자 10개를 가지는 리스트 생성
arr = [random.randint(1, 100) for _ in range(10)]

# 리스트에서 최댓값 찾기
max_num = max(arr)

print(arr)  # 리스트 출력
print("제일 큰 수:", max_num)  # 최댓값 출력

일단 여기서 두가지 짚고 넘어갈 게 있다. 첫번째로, 1편에서 리스트를 만들때는 리스트라고 했는데 이번에 질문할때는 랜덤한 숫자 10개가 들어간 1*10 '배열'이라고 했고 두번째로는 최댓값을 찾기 위해 적절한 모듈을 얘가 골라서 썼다는 것. 그럼 혹시 최댓값이 들어있는 '위치'를 출력할 수도 있는지 한번 보자. 이거 혹시 백준 빌드업? 

 

import random

# 1부터 100 사이의 랜덤한 숫자 10개를 가지는 리스트 생성
arr = [random.randint(1, 100) for _ in range(10)]

# 리스트에서 최댓값 찾기
max_num = max(arr)

# 최댓값이 있는 위치(인덱스) 찾기
max_index = arr.index(max_num)

print(arr)  # 리스트 출력
print("제일 큰 수:", max_num)  # 최댓값 출력
print("최댓값의 위치:", max_index+1)  # 최댓값의 위치(인덱스+1) 출력

2차원 배열에서 어떻게 하는지까지 물어보면 ㄹㅇ 백준 빌드업 되니까 패스... 근데 값을 넣고 인덱스 찾는 법이 있긴 있었구나... 했는데 저거 문자열에서 찾는거네???

 

정렬 알고리즘

이게 종류가 많은데 일일이 다 하다간 서버 뻑나서 내 혈압이 오를 것 같으니 병합정렬이랑 퀵, 힙, 트리(이진 트리를 만들어서 정렬한다는데 뭔지 궁금했음)만 해보자. (당연하지만 2차원 배열에는 안통함)

 

병합 정렬

import random

def merge_sort(arr):
    if len(arr) <= 1:
        return arr

    mid = len(arr) // 2
    left = arr[:mid]
    right = arr[mid:]

    left = merge_sort(left)
    right = merge_sort(right)

    return merge(left, right)

def merge(left, right):
    result = []
    i, j = 0, 0

    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1

    if i < len(left):
        result += left[i:]
    if j < len(right):
        result += right[j:]

    return result

arr = [random.randint(1, 100) for _ in range(10)]
print("Before sort:", arr)

sorted_arr = merge_sort(arr)
print("After sort:", sorted_arr)

본문

병합정렬(merge sort)은 분할정복(divide and conquer) 알고리즘 중 하나로, 배열을 반으로 나눈 뒤, 나눈 각 부분을 재귀적으로 정렬하고, 그 결과를 병합하여 전체를 정렬하는 알고리즘입니다.

 

파이썬에서는 sorted() 함수를 사용하면 간단하게 정렬할 수 있습니다.

하지만, 이번에는 병합정렬을 직접 구현하여 1부터 100까지 중 랜덤한 숫자 10개가 있는 1*10의 배열을 정렬해보겠습니다.

위 코드에서 merge_sort() 함수는 재귀적으로 호출하여 배열을 반으로 나누고, merge() 함수를 사용하여 각 부분 배열을 정렬하여 병합하는 과정을 거칩니다.

merge() 함수는 각 부분 배열을 정렬하여 병합하며, 두 배열을 비교하여 작은 값을 결과 리스트에 추가하고, 마지막에 남은 부분 배열을 추가합니다.

위 코드를 실행하면, 1부터 100까지 중 랜덤한 숫자 10개가 있는 배열이 생성되어 출력되고, 병합정렬을 거친 후 정렬된 배열이 출력됩니다.

이게 일단 길어서 화면 캡처가 안되고... 돌려봤는데 정렬이 깔-끔하다. 스크롤 캡처 해보려고 했는데 일단 전체샷만 찍히고(시종점을 정할수가 없음) 괴랄하게 찍혀서 차라리 내가 하는게 낫겠다 수준이었음.

 

퀵 정렬

import random

def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr)//2]
    less, equal, greater = [], [], []
    for num in arr:
        if num < pivot:
            less.append(num)
        elif num == pivot:
            equal.append(num)
        else:
            greater.append(num)
    return quick_sort(less) + equal + quick_sort(greater)

arr = [random.randint(1, 100) for _ in range(10)]
print("Before sorting:", arr)
arr = quick_sort(arr)
print("After sorting:", arr)

근데 이게 하다보니까 단점이라고 할 것까지는 아닌데, 보통 예시 코드로 설명해줄때는 중간과정을 출력하게끔 하는데 얘는 그런거 없다. 과정샷? 주문해야 나올듯...

 

힙 정렬

나도 뭔지는 모름... 힙 트리를 이용한다는데...

import heapq
import random

# 1부터 100까지 중 랜덤한 숫자 10개로 이루어진 리스트 생성
lst = random.sample(range(1, 101), 10)

# heapq 모듈을 사용하여 힙 정렬 실행
heapq.heapify(lst)
sorted_lst = []
for i in range(len(lst)):
    sorted_lst.append(heapq.heappop(lst))

print(sorted_lst)

이 힙이 두 종류인데 하나는 맥스 힙(최대 힙)이라고 해서 루트가 항상 제일 큰 거, 반대로 민 힙(최소 힙)이라고 해서 루트가 항상 제일 작은 게 있다. 근데 이렇게 얘기하면 루트? 트리 아래요? 아뇨 그 가운데 하나짜리. 맨 위에놈.

 

트리 정렬

배열로도 구현은 가능한데 배열이 커질수록 시간이 기하급수적으로 늘어나기때문에 비추라고 한다. (나도 이거 처음봤음)

 

총평의 총평

원하는 조건이나 알고리즘같은 것만 설명 잘 하면 쓸만한데 문제가 두 가지 있었다. 첫번째로 얘 종특인데 한글로 입력하면 응답이 느려서 그 시간에 차라리 내가 구글링하는게 더 빠르게 생겼고, 두번째로 오늘 전체적으로 서버가 개판인건지 누가 서버실에 커피를 엎었는지 느린 응답과 시너지를 이뤄서, 겨우겨우 응답하나 했더니 오류야. 야이씨 이럴바엔 내가 하고 말지가 되었다.

 

결론은 한국어가 좀 느린거 감수하면 쓸만한데 서버 상태가 멀쩡하기를 기도하고 쓰자.

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

강해져서 돌아온 ChatGPT에게 코딩을 시켜보자

Coding/Python 2023. 3. 20. 18:40

아니 자기가 강해져서 돌아왔대잖아요...


일단 이번에 시켜볼 것은 매우 간단한 코딩들... 뭐 import 할 수는 있겠지만 패키지 설치를 요하는 건 아닌, 그런 것들을 시켜볼거다.

여담이지만 오늘 제일 많이 본 것은... 

강해져서 돌아왔다며!!! 


Hello, World! 출력하기

 

print("Hello, World!")

프로그래밍 책에서도 첫빠따로 나오는 헬로월드다. 따옴표는 ""도 되고 ''도 되는데 아무튼 저 코드 자체는 잘 됐음.

 

일차원 배열 만들기

반복문을 사용하지 않고 a = [1,2,3,4,5] 이런 식으로 직접 할당하는 배열 말하는거다.

my_list = [i for i in range(1, 6)]
print(my_list)

오 고급기술... 원래 의도했던 건 a = [1,2,3,4,5]였는데 이것도 일단 맞는 방법이다. 컴프리헨션에 익숙해지면 이게 훨씬 더 편하기도 하고.

 

그럼 위에 있는 리스트 컴프리헨션을 조금 응용해보자. 이번에는 리스트 컴프리헨션으로 1부터 20까지의 수 중 소수만 배열에 소(별)장 해보도록 했다.

prime_list = [num for num in range(2, 21) if all(num % i != 0 for i in range(2, num))]
print(prime_list)

def로 따로 함수를 밖에서 정의하는 방식이 아니라 안에서 걍 함수까지 정의해버렸다. 예전에 본인이 예시로 했던 건

def isprime(a):
    sqrt = int(a ** 0.5)
    if a <= 1: 
        return False
    for i in range(2,sqrt+1):
        if a % i == 0:
            return False
    else: 
        return True
# a == 1을 a <= 1로 바꿨다. 
a = [i for i in range(100) if isprime(i)]
print(a)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

이런 식이었다. isprime이 소수 판별 함수이고 밖에서 정의를 해서 안에 굳이 정의 안했음.

 

반복문(for&while)

여기서는 더 재볼 것도 없이 2^1~2^10을 반복문을 이용해서 배열로 만들어 볼 예정이다. for랑 while 둘 다.

 

근데 내 질문에 뭐 문제 있나? 

 

my_list = []
for i in range(1, 11):
    my_list.append(2 ** i)
print(my_list)

for는 여부터 여까지 반복하슈라는 반복문이라 걍 이렇게 하면 2부터 1024까지 등비수열로 나온다. 그냥 배열로 만들어달라고 했을 때는 리스트 컴프리헨션을 썼었는데 지금은 내가 for문으로 해달라고 주문한 것임.

 

my_list = []
i = 1
while i <= 10:
    my_list.append(2 ** i)
    i += 1
print(my_list)

while문은 for문과 달리 어떤 조건을 만족할때까지 뺑뺑이를 도는거라고 보면 된다. 그리고 ChatGPT는 for와 while의 맥락이 서로 다른것도 이해하고 있었다. 근데 에러 슈밤...

 

그럼 마지막으로 while True:를 출동시켜봅시다. 에러 몇번뜨나 봐야지 

my_list = []
i = 1
while True:
    my_list.append(2 ** i)
    i += 1
    if i > 10:
        break
print(my_list)

와일트루에 콜론 다니까 에러뜨는거 실화냐... 5트만에 성공함 ㅋㅋㅋㅋㅋㅋ 아무튼... 아일트루는 무한뺑뺑이라 특정 조건을 만족하면 나가게끔 조건을 정해줘야 한다. 일단 세가지 코드는 다 이상 무.

 

입력 받기

입력 받고 문구 출력만 하면 땡인데, 파이썬에는 방법이 두 가지 있다. 바로 input()과 sys.stdin.readline(). 과연 ChatGPT는 import sys를 할 수 있을 것인가? (sys.stdin.readline() 하려면 필요함)

 

일단 결론부터 말하자면 못했다. 자꾸 에러가 뜨더니 접속이 아예 안되는데 서버가 터진건지;;

 

총평

일단 밥이 걸려있으니 저녁에 후속 질문할 것을 정리해보자면


1) 위에 4번
2) 2차원 배열 만들기
3) 함수 정의하기
4) 별찍기


이정도..

전에 ChatGPT vs Bing에서도 얘기했듯이 기본적으로 얘는 한글로 입력하면 느려진다. 근데 에러까지 떠서 실질적으로 걸리는 시간이 훨배 느려졌다. 심지어 이거 되게 기초적인 부분이라 구글링 하거나 책 찾아보고 해도 기본적인 응답 시간에 비해 빠르고 어느정도 백그라운드가 있다면 물어볼 시간에 직접 코딩하는 편이 더 빠르다. 배우는 입장에서 궁금해서 코딩 맡겨보는거면 몰라도 업무때문에 그러는거면 걍 구글링 하던가 수제로 코딩하자. 에러 자체는 ChatGPT의 문제라기보단 서버 문제로 보인다. (인공지능은 서버든 본인 컴퓨터든 어따 모셔놓고 쓴다)

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

Python으로 60갑자 뽑기

Coding/Python 2022. 9. 23. 02:31

참고로 60갑자가 뭔지 궁금하면 달력을 보자. 올해는 임인년이라 인월 인일 인시에 사인검 하나 나온다. (인년 인월 인일 인시 해서 사인이라 사인검이다)


60갑자는 천간 10개와 지지 12개로 이루어지는데... 어? 뭐임? 하나 할인해요? ㄴㄴ 10과 12의 최소공배수가 60임다.

천간: 갑을병정무기경신임계
지지: 자축인묘진사오미신유술해

이렇게 된다. 뒤에 있는 지지가 여러분의 띠이기도 하다. 내가 태어나는 해에도 당연히 갑자가 있고 이게 60년마다 한번씩 돌아오기 때문에 환갑 = 61세(만 60세)에 치른다. 또한 지지가 12개이기때문에 띠동갑은 12살이다.

 

cheongan = ['갑','을','병','정','무','기','경','신','임','계'] * 12
gigi = ['자','축','인','묘','진','사','오','미','신','유','술','해'] * 10
gabja_list = list()

for i in range(len(cheongan)):
  gabja = '{}{}'.format(cheongan[i],gigi[i])
  gabja_list.append(gabja)

print(gabja_list)

천간과 지지가 10개, 12개니까 120으로 잡고 각 배열을 곱했다. 이게 최선임...

['갑자', '을축', '병인', '정묘', '무진', '기사', '경오', '신미', '임신', '계유', '갑술', '을해', '병자', '정축', '무인', '기묘', '경진', '신사', '임오', '계미', '갑신', '을유', '병술', '정해', '무자', '기축', '경인', '신묘', '임진', '계사', '갑오', '을미', '병신', '정유', '무술', '기해', '경자', '신축', '임인', '계묘', '갑진', '을사', '병오', '정미', '무신', '기유', '경술', '신해', '임자', '계축', '갑인', '을묘', '병진', '정사', '무오', '기미', '경신', '신유', '임술', '계해', '갑자', '을축', '병인', '정묘', '무진', '기사', '경오', '신미', '임신', '계유', '갑술', '을해', '병자', '정축', '무인', '기묘', '경진', '신사', '임오', '계미', '갑신', '을유', '병술', '정해', '무자', '기축', '경인', '신묘', '임진', '계사', '갑오', '을미', '병신', '정유', '무술', '기해', '경자', '신축', '임인', '계묘', '갑진', '을사', '병오', '정미', '무신', '기유', '경술', '신해', '임자', '계축', '갑인', '을묘', '병진', '정사', '무오', '기미', '경신', '신유', '임술', '계해']

그러면 이렇게 나온다. 에이 60갑자라면서요?

['갑자', '을축', '병인', '정묘', '무진', '기사', '경오', '신미', '임신', '계유', '갑술', '을해', '병자', '정축', '무인', '기묘', '경진', '신사', '임오', '계미', '갑신', '을유', '병술', '정해', '무자', '기축', '경인', '신묘', '임진', '계사', '갑오', '을미', '병신', '정유', '무술', '기해', '경자', '신축', '임인', '계묘', '갑진', '을사', '병오', '정미', '무신', '기유', '경술', '신해', '임자', '계축', '갑인', '을묘', '병진', '정사', '무오', '기미', '경신', '신유', '임술', '계해'
'갑자', '을축', '병인', '정묘', '무진', '기사', '경오', '신미', '임신', '계유', '갑술', '을해', '병자', '정축', '무인', '기묘', '경진', '신사', '임오', '계미', '갑신', '을유', '병술', '정해', '무자', '기축', '경인', '신묘', '임진', '계사', '갑오', '을미', '병신', '정유', '무술', '기해', '경자', '신축', '임인', '계묘', '갑진', '을사', '병오', '정미', '무신', '기유', '경술', '신해', '임자', '계축', '갑인', '을묘', '병진', '정사', '무오', '기미', '경신', '신유', '임술', '계해']

1+1됐다. 

cheongan = ['갑','을','병','정','무','기','경','신','임','계'] * 12
gigi = ['자','축','인','묘','진','사','오','미','신','유','술','해'] * 10
gabja_list = list()

for i in range(len(cheongan)):
  gabja = '{}{}'.format(cheongan[i],gigi[i])
  gabja_list.append(gabja)

gabja_list = set(gabja_list)
gabja_list = list(gabja_list)
print(gabja_list)

그래서 이렇게 만들고 set->list로 변환하는 과정을 거치면

['신유', '기미', '무신', '병인', '기묘', '신묘', '갑진', '신사', '계사', '을해', '을묘', '경진', '경신', '갑술', '무자', '경자', '임오', '병신', '신축', '기사', '병진', '기해', '임진', '계해', '갑자', '신해', '임자', '경인', '을축', '정사', '계묘', '갑신', '계유', '을사', '갑인', '정유', '무인', '임술', '경오', '을미', '계미', '병술', '임신', '기축', '병자', '임인', '계축', '무오', '을유', '갑오', '경술', '신미', '정미', '정축', '정묘', '무진', '기유', '병오', '정해', '무술']

순서는 개판이지만 길이라 1/2로 줄어드는 기적을 볼 수 있다.

 

cheongan = ['갑','을','병','정','무','기','경','신','임','계'] * 6
gigi = ['자','축','인','묘','진','사','오','미','신','유','술','해'] * 5
gabja_list = list()

for i in range(len(cheongan)):
  gabja = '{}{}'.format(cheongan[i],gigi[i])
  gabja_list.append(gabja)

print(gabja_list)

근데 저렇게 하면 코드도 복잡하고 애초에 반으로 줄여서 하면 그럴 필요가 없잖음? set 만들었다가 하면 순서도 개판이고. 그럼 최소공배수가 60이니까 천간 배열은 6번, 지지 배열은 길이가 12니까 5번 곱하면 되잖음.

['갑자', '을축', '병인', '정묘', '무진', '기사', '경오', '신미', '임신', '계유', '갑술', '을해', '병자', '정축', '무인', '기묘', '경진', '신사', '임오', '계미', '갑신', '을유', '병술', '정해', '무자', '기축', '경인', '신묘', '임진', '계사', '갑오', '을미', '병신', '정유', '무술', '기해', '경자', '신축', '임인', '계묘', '갑진', '을사', '병오', '정미', '무신', '기유', '경술', '신해', '임자', '계축', '갑인', '을묘', '병진', '정사', '무오', '기미', '경신', '신유', '임술', '계해']

깔끔하죠? 

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

RE with FLASK-유효성 검사

Coding/Python 2022. 8. 24. 13:15

예전에 익스트림 CRUD에 나왔던 그거 맞다. 대신 익스트림 CRUD에 비해 입력받는 항목도 적고, 형식검사도 한 가지 부분에 대해서만 진행하면 되기때문에 코드가 비교적 간소하다.

 


입력인자 중 공백 여부를 체크할 것은

1. 시퀀스
2. 시퀀스 이름
3. 시퀀스 정보

이고, 형식을 체크할 것은 시퀀스 하나뿐이다. DNA는 다들 아시다시피 A, T, G, C로 구성되어 있고 DNA 시퀀스에도 당연히 A, T, G, C만 들어간다. 대소문자 입력을 감안해도 atgcATGC 이렇게 여덟개다.

 

어? 제한효소 인식 시퀀스에는 W나 N같은 것도 있잖아요! 그건 DNA 시퀀스가 문제가 아니라 그 제한효소가 인식하는 염기가 두 개 이상이라는 소리다. 예를 들어서 GGWCC라는 인식 시퀀스를 가지는 제한효소가 있다면, 이 효소는 GGACC나 GGTCC 둘 다 인식한다는 소리이다. 그래서 Cutter와 Finder에서도 효소의 인식 시퀀스에 있는 A, T, G, C 외의 알파벳은 해당 알파벳이 지정하는 염기에 맞게 정규식 처리를 한 다음 돌린다. GG[AT]CC 이런 식으로.


function cutFilter() {
    const checked_input = document.querySelectorAll('#cutter_select');
    const textarea = document.querySelectorAll('textarea');
    const checked_fasta = document.querySelectorAll('#FASTA');
    const checked_gen = document.querySelectorAll('#Genbank');
    const NEB_filter = document.getElementsByName('option_NEB');
    const cut_filter = document.getElementsByName('option_cut');
    const sequence_name = document.getElementById('sequence-name').value;
    const sequence_desc = document.getElementById('sequence-desc').value;
    const sequence_valid = RegExp(/[^atgcATGC]/g)
    let sequence = '';

    if (checked_input[0].checked == true) {
        sequence = textarea[0].value;
        if (sequence_valid.test(sequence)) {
            alert('시퀀스 형식이 올바르지 않습니다! ')
        }
    }
    for (let i = 0; i < NEB_filter.length; i++) {
        if (NEB_filter[i].checked == true) {
            NEB_filter_val = NEB_filter[i].value;
        }
    }
    for (let i = 0; i < cut_filter.length; i++) {
        if (cut_filter[i].checked == true) {
            cut_filter_val = cut_filter[i].value
        }
    }

    if (sequence_name.length == 0 || sequence_desc.length == 0 || sequence.length == 0) {
        alert('빈 칸을 채워주세요!')
    }
    if (sequence_name.length != 0 && sequence_desc.length != 0 && sequence.length != 0 && !sequence_valid.test(sequence)) {
        $.ajax({
            type: "POST",
            url: "/cutter",
            data: {
                NEB_give: NEB_filter_val,
                cut_give: cut_filter_val,
                sequence_give: sequence,
                sequence_name_give: sequence_name,
                sequence_desc_give: sequence_desc
            },
            success: function (response) {
                let head_msg = response['head_give']
                let result_msg = response['result_give']
                let end_message = response['end_give']
                let result = document.getElementById('cut_result');
                result.innerHTML = head_msg;
                for (let i = 0; i < result_msg.length; i++) {
                    result.innerHTML = result.innerHTML.concat("\n", result_msg[i])
                }
                result.innerHTML = result.innerHTML.concat("\n", end_message)
            }
        })
    }
}

Cutter의 경우 라디오버튼이 있어서 코드가 좀 더 길다.

 

function findFilter() {
    const input_enz = document.getElementById('enzyme').value;
    const textarea = document.querySelectorAll('textarea');
    const checked_fasta = document.querySelectorAll('#FASTA');
    const checked_gen = document.querySelectorAll('#Genbank');
    const sequence_name = document.getElementById('sequence-name-finder').value;
    const sequence_desc = document.getElementById('sequence-desc-finder').value;
    const sequence_valid = RegExp(/[^atgcATGC]/g)
    let sequence = textarea[2].value
    if (sequence_valid.test(sequence)) {
        alert('시퀀스 형식이 올바르지 않습니다! ')
    }

    if (sequence_name.length == 0 || sequence_desc.length == 0 || sequence.length == 0) {
        alert('빈 칸을 채워주세요!')
    }

    if (sequence_name.length != 0 && sequence_desc.length != 0 && sequence.length != 0 && !sequence_valid.test(sequence)) {
        $.ajax({
            type: "POST",
            url: "/finder",
            data: {
                sequence_give: sequence,
                enzyme_give: input_enz,
                sequence_name_give: sequence_name,
                sequence_desc_give: sequence_desc
            },
            success: function (response) {
                let msg = response['head_give']
                let result = document.getElementById('find_result');
                result.innerHTML = msg;
            }
        })
    }
}

Finder는 라디오버튼이 없기때문에 비교적 코드가 짧다.

 

공란이 있을 때
시퀀스 형식 불일치(소문자는 어차피 서버단에서 대문자로 바꾼다)

'Coding > Python' 카테고리의 다른 글

강해져서 돌아온 ChatGPT에게 코딩을 시켜보자  (0) 2023.03.20
Python으로 60갑자 뽑기  (0) 2022.09.23
RE with FLASK-시퀀스 정보  (0) 2022.08.23
RE with FLASK-Cutter/Finder  (0) 2022.08.22
RE with FLASK-Searcher 이식하기  (0) 2022.08.22
Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

RE with FLASK-시퀀스 정보

Coding/Python 2022. 8. 23. 01:26

FASTA, Genbank파일을 처리할때와 달리 ipynb일때부터 직접 입력하는 시퀀스 정보는 수기로 같이 받았다. 추가가 늦었을 뿐이지... 

 

Cutter
Finder

입력란 만들면서 제일 고생했던 건 CSS였음... 망할 그리드... ㅡㅡ 아무튼. 

추가한 순서는  
1. HTML
2. CSS(여기서 좀 고생함)
3. JS
4. app.py

JS나 Python파일은 크게 수정할 건 없고 Ajax로 주고받는 것만 추가하면 된다. 

checked_finder.forEach(function (i) {
    if (checked_finder[0].checked == true) {
        textarea[2].disabled = false;
        sequence_name.disabled = false;
        sequence_desc.disabled = false
        sequence_name.focus();
        textarea[2].value = ''
    } else if (checked_finder[1].checked == true) {
        upload_fasta[1].disabled = false;
    } else {
        upload_gen[1].disabled = false;
    }
})

대신 시퀀스 정보와 이름을 입력받는 란은 수기로 입력할때만 받으므로(FASTA, Genbank는 그 안에 정보가 다 있어서 Biopython으로 가져올 수 있다) 그 부분에 대한 처리가 별도로 필요하다. 어려운 건 아니고, 라디오버튼이 활성되었을 때만 입력할 수 있게 해 주면 된다. 

다음번에는 유효성 검사를 추가해야지… 


Cutter
Finder

그래서 여기까지 됐다. 

'Coding > Python' 카테고리의 다른 글

Python으로 60갑자 뽑기  (0) 2022.09.23
RE with FLASK-유효성 검사  (0) 2022.08.24
RE with FLASK-Cutter/Finder  (0) 2022.08.22
RE with FLASK-Searcher 이식하기  (0) 2022.08.22
RE with FLASK-뼈대 대공사  (0) 2022.08.22
Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

RE with FLASK-Cutter/Finder

Coding/Python 2022. 8. 22. 01:37

파일 관련 기능이 다 빠졌습니다. 아니 쓰는게 노가다여 아주. 


둘 다 이식 하긴 했는데 다른데서 개고생함… ㅋㅋㅋㅋㅋ 그래요 개고생이 끼어야 코딩이지… 

한번에 되면 그게 이상한거지… 

 

Cutter

그... 왜 Searcher에서 라디오버튼 선택하면 값 전송하는 건 다들 아실거고... 이걸 Cutter에도 적용해야 한다. 물론 Finder에도 적용할거다. 이게 왜 필요하냐면 입력 수단이 라디오버튼이기 때문. 그리고 라디오버튼에 각각 딸려오는 요소가 있어서, 연결된 라디오버튼이 선택되지 않았을 때 비활성화도 시켜줘야 한다. 

이거 근데 Finder 가면서 소스 갈아엎음. ㅇㅇ 

 

function activate() {
    const checked_input = document.querySelectorAll('#typing')
    const textarea = document.querySelectorAll('textarea')
    for (let i = 0; i < checked_input.length; i++) {
        if (checked_input[i].checked == true) {
            textarea[i].disabled = false;
            textarea[i].focus();
        } else {
            textarea[i].disabled = true;
        }
    }
}

function upfasta() {
    const checked_fasta = document.querySelectorAll('#FASTA')
    const upload_fasta = document.querySelectorAll('#input-FASTA')
    for (let i = 0;i < checked_fasta.length;i++) {
        if (checked_fasta[i].checked == true) {
            upload_fasta[i].disabled = false;
        }
        else {
            upload_fasta.disabled = true;
        }
    }
}

function upgen() {
    const checked_gen = document.querySelectorAll('#Genbank')
    const upload_gen = document.querySelectorAll('#input-Genbank')
    for (let i = 0;i < checked_fasta.length;i++) {
        if (checked_gen[i].checked == true) {
            upload_gen[i].disabled = false;
        }
        else {
            upload_gen.disabled = true;
        }
    }
}

소스가 왜 바꼈냐면 Finder 이식하면서 직접 입력/FASTA/Genbank가 아니라 커터/파인더로 나눴기 때문이다.

아무튼 Cutter에도 Searcher에 들어가는 라디오버튼이 일부 있다. NEB filter와 cut별 필터가 그거. 그니까 이번에 Ajax를 통해서 보내는 값은 

1. 입력한 시퀀스
2. NEB filter 선택값
3. Cut 엔딩 선택값

이렇게 세 개다. 

 

function cutFilter() {
    const NEB_filter = document.getElementsByName('option_NEB');
    const cut_filter = document.getElementsByName('option_cut');
    keyword_val = document.getElementById('keywd').value;

    for (let i = 0; i < NEB_filter.length; i++) {
        if (NEB_filter[i].checked == true) {
            NEB_filter_val = NEB_filter[i].value;
        }
    }
    for (let i = 0; i < cut_filter.length; i++) {
        if (cut_filter[i].checked == true) {
            cut_filter_val = cut_filter[i].value
        }
    }
}

그리고 필터값과 달리 시퀀스는 이미 직접 입력하겠다고 라디오버튼으로 정한거라 걍 텍스트에리어 값을 보내면 된다. 

 

$.ajax({
    type: "POST",
    url: "/cutter",
    data: {
        NEB_give: NEB_filter_val,
        cut_give: cut_filter_val,
        sequence_give: sequence
    },
    success: function (response) {
        alert(response['msg'])
    }
})

그럼 Ajax 드가자! 

참고로 얘는 로직 이식할 때 개고생했다. 값은 생각보다 수월하게 가져왔는데... Flask에 갖다놨더니 애가 전역변수를 인식을 못해서 함수로 뺐던거 다시 코드에 넣었다. 

 

Finder

​얘는 로직 이식은 생각보다 수월한데 반대로 JS쪽에서 개고생했다. 뭐가 불만인지 라디오버튼을 선택해도 세상에 활성이 안되잖어... 그래서 커터/파인더별로 묶었다. 용도별로 묶었더니 checked_input[i]가 체크 된 건 인식하는데 i번째 오브젝트 disabled가 안 풀렸거든... 

 

const checked_input = document.querySelectorAll('#typing');
const input_enz = document.getElementsByName('enzyme');
const textarea = document.querySelectorAll('textarea');
const checked_fasta = document.querySelectorAll('#FASTA');
const checked_gen = document.querySelectorAll('#Genbank');
const NEB_filter = document.getElementsByName('option_NEB');
const cut_filter = document.getElementsByName('option_cut');
let sequence = '';
if (checked_input[1].checked == true) {
    sequence = textarea[1].value;
}
for (let i = 0; i < NEB_filter.length; i++) {
    if (NEB_filter[i].checked == true) {
        NEB_filter_val = NEB_filter[i].value;
    }
}
for (let i = 0; i < cut_filter.length; i++) {
    if (cut_filter[i].checked == true) {
        cut_filter_val = cut_filter[i].value
    }
}

그것만 빼면 괜찮아서 입력 갈아엎고 스무th하게... 가긴 무슨... Finder는 이 효소가 이 시퀀스를 자르는가를 보는거라 저 필터들이 아예 없다. 그래서 저기 라디오버튼 걸려있는 필터들을 죄다 빼야 한다. 그러니까, 저기 있는 for문  두 개 얘기한거다. 

 

function findFilter() {
    const input_enz = document.getElementById('enzyme').value;
    const textarea = document.querySelectorAll('textarea');
    const checked_fasta = document.querySelectorAll('#FASTA');
    const checked_gen = document.querySelectorAll('#Genbank');
    let sequence = textarea[2].value
    console.log(input_enz,sequence)

    $.ajax({
        type: "POST",
        url: "/finder",
        data: {
            sequence_give: sequence,
            enzyme_give: input_enz
        },
        success: function (response) {
            console.log(response)
        }
    })

}

그래서 입력 박스 두 개의 값만 전달하면 된다. 참 쉽죠? 

참고로 저게 다라 이식 자체는 싱겁게 끝났다. 전역변수 없는건 커터덕에 알아서 바로 수정했고... 
근데 format땜시 {}준걸 왜 니가 나눠놓고 인식을 못하냐 파이참... 

 

완성작

Cutter
Finder

아니 눈누도 웹폰트가 되더라고 세상에... 

'Coding > Python' 카테고리의 다른 글

RE with FLASK-유효성 검사  (0) 2022.08.24
RE with FLASK-시퀀스 정보  (0) 2022.08.23
RE with FLASK-Searcher 이식하기  (0) 2022.08.22
RE with FLASK-뼈대 대공사  (0) 2022.08.22
Wordcloud with FLASK-뼈대 대공사 (3)  (0) 2022.08.22
Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

RE with FLASK-Searcher 이식하기

Coding/Python 2022. 8. 22. 01:32

들어가기 전에 중요한 게 하나 있다. 

Cutter와 Finder도 내일 이식하긴 할건데, 내일 이식하는 부분에서 FASTA/Genbank 파일 올리는거랑 결과 저장 기능은 빠진다. 그래서 원본 코드에 있던 with 어쩌고를 일단 작성 없이 서버로 보내서 텍스트 에리어에서 출력하는 걸 일차적으로 진행하고 저장-업로드 순으로 할 예정. FASTA/Genbank는 JS로 파일 받아서 파이썬으로 넘겨서 열 생각인데 그거 관련해서 로직 처리가 좀 필요하고(뼈대를 보면 라디오 버튼이다) 반대로 텍스트 파일은 파이썬에서 만들어서 JS로 넘길 생각이다. 텍스트 파일은 만들어준 거 받아서 버튼 누르면 다운로드 되게 하면 끝임. 


대공사 전에... 

일단 공사 전인 Searcher의 뼈대를 보자. 

원래 코드에서 입력으로 받던 걸 죄다 라디오버튼으로 박아버렸다. JS파일의 임무는 일차적으로 

1) 사용자가 입력한 검색어와 
2) 라디오버튼의 값을 app.py(파이썬)으로 전달해주는 

것이다. 로직은 뒤에서 돌 거니까 JS는 

1) 로직을 돌리기 위해 필요한 변수들을 주고
2) 결과물을 받아서 출력한다 

그리고 인자와 결과물의 전달을 Ajax가 한다. (얘때문에 jQuery 들어간거지 저거 빼고 어지간한 기능은 다 바닐라JS다)

 

function searchFilter() {
    const search_method = document.getElementsByName('search_val');
    console.log(search_method)
}

일단 이렇게 하면 값은 나오는데 문제는 뭐냐... 라디오버튼 중 선택된 값만 넘겨야 한다. 

 

function searchFilter() {
    const search_method = document.getElementsByName('search_val');
    for (let i = 0;i < search_method.length;i++) {
        if (search_method[i].checked == true) {
            console.log(search_method[i].value)
        }
    }
}

그러니까 이 if를 세 개 줘야 한다. 

 

function searchFilter() {
    const search_method = document.getElementsByName('search_val');
    const NEB_filter = document.getElementsByName('option_NEB');
    const cut_filter = document.getElementsByName('option_cut');

    for (let i = 0;i < search_method.length;i++) {
        if (search_method[i].checked == true) {
            console.log(search_method[i].value);
        }
    }
    for (let i = 0;i < NEB_filter.length;i++){
        if (NEB_filter[i].checked == true) {
            console.log(NEB_filter[i].value);
        }
    }
    for (let i = 0;i < cut_filter.length;i++){
        if (cut_filter[i].checked == true) {
            console.log(cut_filter[i].value)
        }
    }
}

왜 for+if가 3개인지 궁금하신 분들은 뼈대를 다시 보고 옵시다. 아무튼 그럼 Ajax를 불러보자. 

 

let search_method_val = '';
let NEB_filter_val = '';
let cut_filter_val = '';
function searchFilter() {
    const search_method = document.getElementsByName('search_val');
    const NEB_filter = document.getElementsByName('option_NEB');
    const cut_filter = document.getElementsByName('option_cut');

    for (let i = 0; i < search_method.length; i++) {
        if (search_method[i].checked == true) {
            search_method_val = search_method[i].value;
        }
    }
    for (let i = 0; i < NEB_filter.length; i++) {
        if (NEB_filter[i].checked == true) {
            NEB_filter_val = NEB_filter[i].value;
        }
    }
    for (let i = 0; i < cut_filter.length; i++) {
        if (cut_filter[i].checked == true) {
            cut_filter_val = cut_filter[i].value
        }
    }
    $.ajax({
    type: "POST",
    url: "/searcher",
    data: {NEB_give: NEB_filter_val, cut_give: cut_filter_val, search_give: search_method_val},
    success: function (response) {
        alert(response['msg'])
    }
})
}

여기다가 변수 하나만 추가하면 텍스트도 같이 넘길 수 있다. 

 

@app.route('/searcher', methods=['POST'])
def searcher():
    NEB_receive = request.form['NEB_give']
    cut_receive = request.form['cut_give']
    search_receive = request.form['search_give']
    message = '{},{},{}'.format(NEB_receive,cut_receive,search_receive)
    return jsonify({'msg': message})

그리고 받아오면 된다. 

 

로직의 변경점

위에서 기존 코드로 입력받던 것들을 라디오버튼으로 바꿨다고 했는데, 그거 말고도 변경점이 하나 더 있다. 원래 코드에서는 print문으로 출력해줬지만, 쟤는 app.py에서 다 만들고 나면 결과를 다시 JS에게 넘겨줘야 한다. 그러니까 단순히 print문으로 되어있던 걸 처리하는 과정이 필요하다.

 

@app.route('/searcher', methods=['POST'])
def searcher():
    enzyme_table = pd.read_csv('/home/koreanraichu/restriction_merge.csv')
    NEB_receive = request.form['NEB_give']
    cut_receive = request.form['cut_give']
    search_receive = request.form['search_give']
    keywd_receive = request.form['keywd_give']

    def SeqtoString(a):
        a = enzyme_table.sequence[(enzyme_table['Enzyme'] == keywd_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    def SitetoString(a):
        a = enzyme_table.restriction_site[(enzyme_table['Enzyme'] == keywd_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    def NEB_selling(a):
        a = enzyme_table.NEB_sell[(enzyme_table['Enzyme'] == keywd_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    # 함수 가즈아!!!

    if cut_receive == 'sticky':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Sticky']
        enzyme_table.reset_index(inplace=True)
        cut_feature = 'Sticky end'
    elif cut_receive == 'blunt':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Blunt']
        enzyme_table.reset_index(inplace=True)
        cut_feature = 'Blunt end'
    elif cut_receive == 'nicked':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Nicked']
        enzyme_table.reset_index(inplace=True)
        cut_feature = "Nicked"
    else:
        cut_feature = "W/O filter"
        pass
    if NEB_receive == 'NEB':
        enzyme_table = enzyme_table[enzyme_table['NEB_sell'] == 'Yes']
        enzyme_table.reset_index(inplace=True)
        NEB_filter = 'NEB only'
    else:
        NEB_filter = 'All'
        pass
    if search_receive == 'name':
        pass
    elif search_receive == 'sequence':
        pass
    else:
        pass
    return jsonify({'msg': '입력되었습니다!'})

근데 함수 그냥 이렇게 써도 됨? 

아무튼 그래서... print문을 전부 텍스트로 할당했다. 

@app.route('/searcher', methods=['POST'])
def searcher():
    enzyme_table = pd.read_csv('/home/koreanraichu/restriction_merge.csv')
    NEB_receive = request.form['NEB_give']
    cut_receive = request.form['cut_give']
    search_receive = request.form['search_give']
    keyword_receive = request.form['keyword_give']

    def SeqtoString(a):
        a = enzyme_table.sequence[(enzyme_table['Enzyme'] == keyword_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    def SitetoString(a):
        a = enzyme_table.restriction_site[(enzyme_table['Enzyme'] == keyword_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    def NEB_selling(a):
        a = enzyme_table.NEB_sell[(enzyme_table['Enzyme'] == keyword_receive)]
        a = a.to_string(index=False)
        a = str(a).strip()
        return a

    # 함수 가즈아!!!

    if cut_receive == 'sticky':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Sticky']
        enzyme_table.reset_index(inplace=True)
        cut_feature = 'Sticky end'
    elif cut_receive == 'blunt':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Blunt']
        enzyme_table.reset_index(inplace=True)
        cut_feature = 'Blunt end'
    elif cut_receive == 'nicked':
        enzyme_table = enzyme_table[enzyme_table['cut_feature'] == 'Nicked']
        enzyme_table.reset_index(inplace=True)
        cut_feature = "Nicked"
    else:
        cut_feature = "W/O filter"
        pass
    if NEB_receive == 'NEB':
        enzyme_table = enzyme_table[enzyme_table['NEB_sell'] == 'Yes']
        enzyme_table.reset_index(inplace=True)
        NEB_filter = 'NEB only'
    else:
        NEB_filter = 'All'
        pass

    if search_receive == 'name':
        find_seq = SeqtoString(keyword_receive)
        Site_seq = SitetoString(keyword_receive)
        NEB_sell = NEB_selling(keyword_receive)
        result_iso = ''
        result_neo = ''
        result_iso_list = []
        result_neo_list = []
        Iso = []
        Neo = []
        message_give =  "{0} | {1} | {2} | {3} | Input enzyme".format(keyword_receive, find_seq, Site_seq, NEB_sell)
        for i in range(len(enzyme_table)):
            DB_enzyme = str(enzyme_table['Enzyme'][i]).strip()
            DB_seq = str(enzyme_table['sequence'][i]).strip().upper()
            DB_site = str(enzyme_table['restriction_site'][i]).strip().upper()
            if find_seq == str(DB_seq) and DB_enzyme != keyword_receive:
                if Site_seq == DB_site:
                    Iso.append(DB_enzyme)
                    result_iso = "{0} | {1} | {2} | {3} | Isoschizomer".format(DB_enzyme, DB_seq, DB_site,
                                                                                   NEB_sell)
                    result_iso_list.append(result_iso)

                    # 인식하는 시퀀스와 자르는 방식이 같은 제한효소
                elif Site_seq != DB_site:
                    Neo.append(DB_enzyme)
                    result_neo = "{0} | {1} | {2} | {3} | Neoschizomer".format(DB_enzyme, DB_seq, DB_site,
                                                                                   NEB_sell)
                    result_neo_list.append(result_neo)
                    # 인식하는 시퀀스는 같으나 자르는 방식이 다른 제한효소
            elif find_seq == str(DB_seq) and DB_enzyme == keyword_receive:
                pass
            else:
                pass
    elif search_receive == 'sequence':
        find_seq = keyword_receive
        message_give = ("Searched by: {0}".format(keyword_receive))
        for i in range(len(enzyme_table)):
            DB_enzyme = str(enzyme_table['Enzyme'][i]).strip()
            DB_seq = str(enzyme_table['sequence'][i]).strip().upper()
            DB_site = str(enzyme_table['restriction_site'][i]).strip().upper()
            DB_NEB = str(str(enzyme_table['NEB_sell'][i]).strip())
            if find_seq == DB_seq:
                print("{0} | {1} | {2} | {3}".format(DB_enzyme, DB_seq, DB_site, DB_NEB))
        else:
            enzyme_RE = keyword_receive
            enzyme_RE = enzyme_RE.upper()
            enzyme_RE_2 = '^' + enzyme_RE
            message_give = ("Enzyme with start with {0}".format(enzyme_RE))
            for i in range(len(enzyme_table)):
                DB_enzyme = str(enzyme_table['Enzyme'][i]).strip()
                DB_seq = str(enzyme_table['sequence'][i]).strip().upper()
                DB_site = str(enzyme_table['restriction_site'][i]).strip().upper()
                DB_NEB = str(str(enzyme_table['NEB_sell'][i]).strip())
                if re.search(enzyme_RE_2, DB_enzyme):
                    print("{0} | {1} | {2} | {3}".format(DB_enzyme, DB_seq, DB_site, DB_NEB))
    return jsonify({'Message_give': message_give,'Result_iso':result_iso_list,'Result_neo':result_neo_list})

이건데(일단 이름 검색만 됨) 여기서 

if search_receive == 'name':
    find_seq = SeqtoString(keyword_receive)
    Site_seq = SitetoString(keyword_receive)
    NEB_sell = NEB_selling(keyword_receive)
    result_iso = ''
    result_neo = ''
    result_iso_list = []
    result_neo_list = []
    Iso = []
    Neo = []
    message_give =  "{0} | {1} | {2} | {3} | Input enzyme".format(keyword_receive, find_seq, Site_seq, NEB_sell)
    for i in range(len(enzyme_table)):
        DB_enzyme = str(enzyme_table['Enzyme'][i]).strip()
        DB_seq = str(enzyme_table['sequence'][i]).strip().upper()
        DB_site = str(enzyme_table['restriction_site'][i]).strip().upper()
        if find_seq == str(DB_seq) and DB_enzyme != keyword_receive:
            if Site_seq == DB_site:
                Iso.append(DB_enzyme)
                result_iso = "{0} | {1} | {2} | {3} | Isoschizomer".format(DB_enzyme, DB_seq, DB_site,
                                                                               NEB_sell)
                result_iso_list.append(result_iso)

                # 인식하는 시퀀스와 자르는 방식이 같은 제한효소
            elif Site_seq != DB_site:
                Neo.append(DB_enzyme)
                result_neo = "{0} | {1} | {2} | {3} | Neoschizomer".format(DB_enzyme, DB_seq, DB_site,
                                                                               NEB_sell)
                result_neo_list.append(result_neo)
                # 인식하는 시퀀스는 같으나 자르는 방식이 다른 제한효소

이 부분을 다시 보다. print문이 있어야 할 곳에 메세지, 리절트 이런 변수들이 있다. 왜 이렇게 했나고? 

return jsonify({'Message_give': message_give,'Result_iso':result_iso_list,'Result_neo':result_neo_list})

얘때문임. Ajax로 다시 JS로 보내려면 JSON파일로 만들어야 하거든… 그래서 결과를 딕셔너리로 만든 다름 JSON으로 넘길거다. 

 

success : function (response) {
    var message = response['Message_give']
    var iso = response['Result_iso']
    var neo = response['Result_neo']
    let result = document.getElementById('search_result');
    result.innerText = message;
    for (let i = 0; i < iso.length; i++) {
        console.log(iso[i])
        result.innerText = iso[i]
    }
    for (let i = 0; i < neo.length; i++) {
        console.log(neo[i])
        result.innerText = neo[i]
    }
}

근데 여기서 줄바꿈 안돼서 진짜 온갖가지 것들을 다 해봤음... 근데 이스케이프 문자 안먹지 백틱 안먹지 뭐 어쩌라는건지...ㅡㅡ 

 

success : function (response) {
    if (search_method_val == 'name') {
        let message = response['doc_result']['Message_give'];
        let iso = response['doc_result']['Result_iso'];
        let neo = response['doc_result']['Result_neo'];
        let result = document.getElementById('search_result');
        result.innerHTML = message;
        for (let i = 0; i < iso.length; i++) {
            result.innerHTML = result.innerHTML.concat("\n", iso[i])
        }
        for (let i = 0; i < neo.length; i++) {
            result.innerHTML = result.innerHTML.concat("\n", neo[i])
        }
    } else if (search_method_val == 'sequence') {
        let message = response['doc_result']['Message_give'];
        let same_seq = response['doc_result']['Result_seq'];
        let result = document.getElementById('search_result');
        result.innerHTML = message;
        for (let i = 0; i < same_seq.length; i++) {
            result.innerHTML = result.innerHTML.concat("\n", same_seq[i])
        }
    } else {
        let message = response['doc_result']['Message_give'];
        let spell = response['doc_result']['Result_spell'];
        let result = document.getElementById('search_result');
        result.innerHTML = message;
        for (let i = 0; i < spell.length; i++) {
            result.innerHTML = result.innerHTML.concat("\n", spell[i])
        }
    }
}

는 지나가던 분의 .concat()신공과 가만 이거 innerText말고 inner HTML도 있잖아?로 해⭐결! 

 

그래서 완성품

이름으로 검색
시퀀스로 검색
그 뭐더라 X로 시작하는 효소

 

이후 추가할 기능

검색어 없을 때 멘트랑 검색 방법별 도움말정도? 

'Coding > Python' 카테고리의 다른 글

RE with FLASK-시퀀스 정보  (0) 2022.08.23
RE with FLASK-Cutter/Finder  (0) 2022.08.22
RE with FLASK-뼈대 대공사  (0) 2022.08.22
Wordcloud with FLASK-뼈대 대공사 (3)  (0) 2022.08.22
경로때문에 개노가다 한 썰 푼다  (0) 2022.08.22
Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

RE with FLASK-뼈대 대공사

Coding/Python 2022. 8. 22. 01:22

아, RE는 Restriction enzyme이다. 


기본뼈대

app.py

from flask import Flask,render_template
import pandas as pd
import re
from datetime import datetime
from argparse import FileType
import tkinter
from tkinter import filedialog
from Bio import SeqIO
import os
import platform

app = Flask(__name__)


@app.route('/')
def hello_world():  # put application's code here
    return render_template('index.html')


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

벌써 모듈 정모 들어간거 실화냐. 

 

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/static/style.css">
    <title>Project restriction enzyme</title>
</head>
<body>
<div class="wrap">
<h1>Project restriction enzyme</h1>
    <div class="tab_re">
        <ul class="list">
            <li class="focus">
                <a href="#tab1" class="btn">About Project restriction enzyme</a>
                <div id="tab1" class="cont"></div>
            </li>
            <li>
                <a href="#tab2" class="btn">Restriction enzyme Cutter</a>
                <div id="tab2" class="cont"></div>
            </li>
            <li>
                <a href="#tab3" class="btn">Restriction enzyme Finder</a>
                <div id="tab3" class="cont"></div>
            </li>
            <li>
                <a href="#tab4" class="btn">Restriction enzyme searcher</a>
                <div id="tab4" class="cont"></div>
            </li>
        </ul>
    </div>
</div>
<script src="/static/script.js"></script>
</body>
</html>

 

CSS

@import url('https://fonts.googleapis.com/css2?family=Gamja+Flower&display=swap');

* {
    margin:0;
    padding:0;
    font-family: 'Gamja Flower', cursive;
    font-size:16pt;
    color:#02343F;
}

ul {
    list-style-type:none;
}

a{
    text-decoration:none;
    color:#02343F;
}

h1 {
    text-align:center;
    font-size:27pt;
    margin:15px auto;
}

h2 {
    font-size:18pt;
    margin-bottom:5px;
}

h3{
    margin-bottom:5px;
}

img {
    width:500px;
}

span {
    text-align:center;
    display:block;
    font-size:16pt;
}

p{
    margin-bottom:20px;
}

.image{
    margin:5px auto;
    width:500px;
}
.wrap {
    width:1200px;
    margin:0 auto;
    padding:15px;
    letter-spacing:-0.5px;
}

.tab_re {
    position:relative;
}

.tab_re .list {
    overflow:hidden;
}

.tab_re li {
    float:left;
}

.tab_re .list .btn {
    font-size:17pt;
    color:#02343F;
    width:300px;
    height:50px;
    display:inline-block;
    text-align:center;
    line-height:50px;
    background-color:#fefefe;
    border-bottom:2px solid #fefefe;
}

.tab_re .list .cont {
    font-size:15pt;
    display:none;
    position:absolute;
    left:0;
    background-color:white;
    color:#fff;
    width:1200px;
    height:auto;
    line-height:30px;
    padding:20px;
    box-sizing:border-box;
}

.tab_re .list li.focus .btn {
    background:linear-gradient(to bottom,#ffffff,#F0EDCC);
    border-bottom:2px solid #02343F;
    color:#02343F;
    display:block;
}

.tab_re .list li.focus .cont {
    display:block;
    background-color:#F0EDCC;
    color:#000;
}

 

JS

const tabList = document.querySelectorAll('.tab_re .list li');
console.log(tabList)

for(var i = 0; i < tabList.length; i++){
    tabList[i].querySelector('.btn').addEventListener('click', function(e){
      e.preventDefault();
      for(var j = 0; j < tabList.length; j++){
        tabList[j].classList.remove('focus');
      }
      this.parentNode.classList.add('focus');
    });
  }

얘는 이거 말고 크게 건드릴건 없... 아 있구나 데이터 넘겨야지... 

 

확장 뼈대

각 뼈대는 여기서 파생된다. 그러니까 이게 기본형. 

 

Cutter

시퀀스의 경우 라디오버튼으로, FASTA와 Genbank는 업로드할거고 위는 직접 입력이다. 기존에 코드에서 수기로 입력받던 게 라디오버튼화 됐다고 보면 된다. 아래쪽 텍스트에리어는 readonly를 줘서 편집은 안된다. 근데 결과 출력란이라 편집하면 안된다. 

결과 저장하기는 저기 보이는 결과를 텍스트파일로 저장할 수 있는 버튼. 그 텍스트파일로 나가는 그거 맞다. 

 

Finder

Finder는 이 효소가 이걸 자르나? 를 보는거기때문에 제한효소명도 입력받는다. 

 

Searcher

저 닉필터 저거 커터에 넣어야지... 아무튼 Searcher는 검색 필터라고 해야 하나... 그 라디오버튼 먹일 게 더럽게 많다. 

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

Wordcloud with FLASK-뼈대 대공사 (3)

Coding/Python 2022. 8. 22. 01:18

Entrez쪽 뼈대 만든거랑 버튼 얘기 있으니까 기둘려보시오 


Entrez with wordcloud 뼈대

이 뼈대가 완전한 건 아닌게 글꼴 선택란이 없음.. 지금 생각중인건 어비 스윗체/둘기마요/나눔고딕정도... 아무튼 Entrez with wordcloud 뼈대도 만들었음. 

 

입력부

출력부는 별 차이 없고, 얘는 입력 인자가 검색어랑 논문 갯수뿐이라 입력란이 간소하다. 지금은 논문 개수 입력하는 란이 없는데 그건 나중에 만들면 되고… 

 

Sample text 버튼

Text with wordcloud는 찍먹이나 해보자 하는 분들을 위한 샘플 텍스트를 제공하고 있다. 한글 2 영어 2 생각중인데 영어 하나 제보좀 해주세요… 

 

<button type="button" class="sample" id="sample1" onclick="starcount()">샘플 텍스트(윤동주-별 헤는 밤)</button>
<button type="button" class="sample" id="sample2">샘플 텍스트(이육사-청포도)</button>
<button type="button" class="sample" id="sample3">샘플 텍스트 3</button>
<button type="button" class="sample" id="sample4">샘플 텍스트 4</button>

일단 HTML에 온클릭을 넣는다.

 

function bluegrape() {
    let contents = document.querySelector('textarea')
    const text = `내 고장 칠월은
청포도가 익어가는 시절

이 마을 전설이 주절이주절이 열리고
먼데 하늘이 꿈꾸며 알알이 들어와 박혀

하늘 밑 푸른 바다가 가슴을 열고
흰 돛단배가 곱게 밀려서 오면

내가 바라는 손님은 고달픈 몸으로
청포를 입고 찾아온다고 했으니

내 그를 맞아 이 포도를 따먹으면
두 손은 함뿍 적셔도 좋으련

아이야 우리 식탁엔 은쟁반에
하이얀 모시 수건을 마련해두렴`
    contents.textContent = text
}

그 다음 자바스크립트(스크립트 파일)로 넘어가서 함수를 이렇게 짜 주면 된다. (길이 제일 짧은게 저거) textarea를 가져와서 해당 텍스트를 컨텐츠로 채우는 식. 

참고로 영문 샘플 텍스트 하나는 그 뭐지? 그 시 있었는데 네버모어 하는... 그거다. 

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

경로때문에 개노가다 한 썰 푼다

Coding/Python 2022. 8. 22. 01:16

일단 개고생한 이유를 축약해드리자면... 

1. 윈도우에서는 폰트 저장 경로(C:\Windows\Fonts)에 있는 걸 갖다 쓰는 게 아니라 TTF, OTF파일이 있는 경로를 직접 입력해야 갖다 쓸 수 있음. 
2. 근데 리눅스는 폰트 저장 경로(/usr/share/fonts)에서 선택해서 쓸 수 있음. 

그래서 개고생했습니다. 


OS = platform.platform()
if 'Linux' in OS: 
    default_dir = '/home'
    root = tkinter.Tk()
    root.withdraw()
    font_dir = '/usr/share/fonts'
    font_path = filedialog.askopenfilename(parent=root, initialdir=font_dir, title='Choose your fonts for Wordcloud',
                                           filetypes=(("*.ttf", "*ttf"), ("*.otf", "*otf")))
elif 'Windows' in OS:
    default_dir = 'C:\\'
    root = tkinter.Tk()
    root.withdraw()
    font_path = filedialog.askopenfilename(parent=root, initialdir=default_dir, title='Choose your fonts for Wordcloud',
                                           filetypes=(("*.ttf", "*ttf"), ("*.otf", "*otf")))

그래서 코드도 이걸로 수정했음. 아예 OS에 따라 폰트 파일을 여는 방식이 다르기때문에 리눅스는 폰트가 저장된 경로를 띄우고, 윈도우는 알아서 파일 갖다 여시라고 친절하게 C드라이브 띄워드림. 

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

Wordcloud with FLASK-뼈대 대공사 (2)

Coding/Python 2022. 8. 22. 01:16

워드클라우드부터 해서 진짜 얘까지 개 노가다의 연속이었음... 
그래도 이거 미리 해놔서 Entrez는 입력부만 조금 수정하면 됩니다. 

워드클라우드 경로 썰은 다른 포스트에서 풀어드림. 


이게 길어서 한번에 캡처 못했음다. 

입력부

입력부의 각 기능

1. 텍스트 입력란(샘플 텍스트도 있음): 샘플 텍스트는 현재 한글 두개(별 헤는 밤, 청포도)랑 영어 하나(미정)를 생각중이며, 버튼을 누르면 샘플 텍스트가 텍스트에리어에 입력된다. 길면 잘 뽑히긴 한데 영어는 뭘 해야 할 지 모르겠음. 아니 그렇다고 하이 잭 하이 마이크 하와유 이딴걸 할 순 없잖수. 논문 해 논문 
2. 컬러맵 선택(이따 이미지 올려드림): 이건 밑에 털어드림. 
3. 마스킹이미지 ㄱㄱ: 이미지 안 쓴다는 선택지는 없음. 
4. 언어 선택(한국어는 konlpy 한번 거쳐야 함)

즉 여기서 입력을 받아서 파이썬으로 전달하는 요소는 

1. 워드클라우드를 만들 텍스트
2. 컬러맵
3. 글꼴(...)
4. 마스킹 이미지
5. 한글이냐? (제일 간단)

이다. 

 

출력부

출력부는 개 심플하다. 저기에 워드클라우드 이미지가 뜨고 다운로드 버튼을 누르면 다운로드가 된다. 즉, 작업이 다 끝나서 이미지가 나오게 되면 파이썬에서 여기로 주면 된다. 

 

컬러맵

참고로 이거 일부분이다. matplotlib 컬러맵이 진짜 개많음... 살려주세요... 사랑해요 그리드뷰

워드클라우드를 만드는 소스 코드가 파이썬인데, 파이썬에서 워드클라우드를 만들 때 컬러맵은 matplotlib의 컬러맵을 가져온다. 그니까 저 컬러맵 matplotlib으로 그래프 그릴 때도 쓸 수 있다. 그래프만으로 논문이 컬러풀해지는 기적 저걸 근데 입력받으면 분명 오타냄... 그리고 오타나면 워드클라우드 에러뜸... 그래서 저걸 어쩔 수 없이 라디오버튼으로 박아놨다.

 

그리고 라디오버튼에 할당된 value가 저 이름 그대로 들어가기 때문에 선택하고 OK만 하면 value 그대로 넘겨서 하면 된다.

Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

Wordcloud/RE 경로 관련 코드 수정

Coding/Python 2022. 8. 22. 01:13

아니 나도 몰랐는데 파이썬으로 OS 정보를 볼 수 있더라? 근데 맥은 내가 가지고 있는 기기가 없어서 못봤음... 

import platform

일단 이놈을 데려온 다음 

print(platform.platform())

을 치면 자기 컴퓨터의 OS 정보를 볼 수 있다. 

 

그래서 이걸 어떻게 수정했냐면 

OS = platform.platform()
if 'Linux' in OS: 
    default_dir = '/home'
    font_dir = '/usr/share/fonts'
else:
    default_dir = 'C:\\'
    font_dir = 'C:\\Fonts'

OS 정보를 가져와서 리눅스면 기본 경로를 이렇게 하고, 아니면(윈도우면) 이렇게 해라 이렇게 했다. 위 코드는 워드클라우드고 제한효소쪽은 파일 불러오는것 말고 없어서 글꼴 경로는 생략. 

네? 맥이요? 기본경로 어케앎? 

'Coding > Python' 카테고리의 다른 글

경로때문에 개노가다 한 썰 푼다  (0) 2022.08.22
Wordcloud with FLASK-뼈대 대공사 (2)  (0) 2022.08.22
Wordcloud with FLASK-뼈대 대공사  (0) 2022.08.22
대형프로젝트 계획중  (0) 2022.08.22
input vs sys.stdin.readline()  (0) 2022.08.22
Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

Wordcloud with FLASK-뼈대 대공사

Coding/Python 2022. 8. 22. 01:12

일단... 현재 완성된 부분이 

여긴데 어바웃 페이지만 된다. 입력받는 란은 아직 안함. 

현재 구현된 기능

1) 탭 메뉴(어바웃 페이지/텍스트/엔트레즈 탭)
2) 어바웃페이지


app.py

from flask import Flask, render_template
from Bio import Entrez
from wordcloud import WordCloud
from wordcloud import STOPWORDS
import matplotlib.pyplot as plot
from PIL import Image
import numpy as np
from argparse import FileType
import tkinter
from tkinter import filedialog
import re
from konlpy.tag import Okt
import nltk
okt=Okt()

app = Flask(__name__)


@app.route('/')
def hello_world():  # put application's code here
    return render_template('index.html')


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

모듈 정모 들어간 것 같다면 정상… 차후 로직 만지면서 저기 말고 개별 코드에 들어갈수도 있다. 참고로 본인은 파이썬 모듈 중구난방인 거 싫어함. 

 

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/static/style.css">
    <title>Project wordcloud</title>
</head>
<body>

    <div class="wrap">
        <h1>Project wordcloud</h1>
        <div class="tab_wc">
            <ul class="list">
                <li class="focus">
                    <a href="#tab1" class="btn">About project wordcloud</a>
                    <div id="tab1" class="cont">어바웃 페이지입니다</div>
                </li>
                <li>
                    <a href="#tab2" class="btn">Wordcloud with text</a>
                    <div id="tab2" class="cont">Wordcloud with text</div>
                </li>
                <li>
                    <a href="#tab3" class="btn">Entrez with wordcloud</a>
                    <div id="tab3" class="cont">Entrez with wordcloud</div>
                </li>
            </ul>
        </div>
    </div>
<script src="/static/script.js"></script>
</body>
</html>

이제 코드단에서 손볼 건 내용말고 없다. ...없겠지? 

 

CSS

@import url('https://fonts.googleapis.com/css2?family=Yeon+Sung&display=swap');

* {
    margin:0;
    padding:0;
    font-family: 'Yeon Sung', cursive;
    font-size:15pt;
}

ul {
    list-style-type:none;
}

a{
    text-decoration:none;
}

h1 {
    text-align:center;
    font-size:25pt;
    margin:15px auto;
}

h2 {
    font-size:18pt;
    margin-bottom:5px;
}

h3{
    margin-bottom:5px;
}

img {
    width:500px;
}

span {
    text-align:center;
    display:block;
    font-size:15pt;
}

p{
    margin-bottom:20px;
}

.image{
    margin:5px auto;
    width:500px;
}
.wrap {
    width:1080px;
    margin:0 auto;
    padding:15px;
    letter-spacing:-0.5px;
}

.tab_wc {
    position:relative;
}

.tab_wc .list {
    overflow:hidden;
}

.tab_wc li {
    float:left;
}

.tab_wc .list .btn {
    font-size:16pt;
    color:#00498c;
    width:220px;
    height:50px;
    display:inline-block;
    text-align:center;
    line-height:50px;
    background-color:#fefefe;
    border-bottom:2px solid #fefefe;
}

.tab_wc .list .cont {
    font-size:14pt;
    display:none;
    position:absolute;
    left:0;
    background-color:white;
    color:#fff;
    width:1080px;
    height:auto;
    line-height:30px;
    padding:20px;
}

.tab_wc .list li.focus .btn {
    background-color:#f5f5f5;
    border-bottom:2px solid #00498c;
    color:#00498c;
    display:block;
}

.tab_wc .list li.focus .cont {
    display:block;
    background-color:#f5f5f5;
    color:#000;
}

input이나 라벨 등의 요소가 추가되면 뭔가 더 추가될 가능성이 있다. 

 

JS

const tabList = document.querySelectorAll('.tab_wc .list li');
console.log(tabList)

for(var i = 0; i < tabList.length; i++){
    tabList[i].querySelector('.btn').addEventListener('click', function(e){
      e.preventDefault();
      for(var j = 0; j < tabList.length; j++){
        tabList[j].classList.remove('focus');
      }
      this.parentNode.classList.add('focus');
    });
  }

탭 메뉴 관련 스크립트이다. 끝. 

'Coding > Python' 카테고리의 다른 글

Wordcloud with FLASK-뼈대 대공사 (2)  (0) 2022.08.22
Wordcloud/RE 경로 관련 코드 수정  (0) 2022.08.22
대형프로젝트 계획중  (0) 2022.08.22
input vs sys.stdin.readline()  (0) 2022.08.22
Python으로 JSON파일 읽기  (0) 2022.08.22
Lv. 35 라이츄

Lv. 35 라이츄

광고 매크로 없는 청정한 블로그를 위해 노력중입니다. 근데 나만 노력하는 것 같음… ㅡㅡ

방명록