(198)

백준 1427번 풀이

문제 https://www.acmicpc.net/problem/1427 1427번: 소트인사이드 첫째 줄에 정렬하려고 하는 수 N이 주어진다. N은 1,000,000,000보다 작거나 같은 자연수이다. www.acmicpc.net 숫자 정렬하는 문제인데 이제 입력이 192834729 막 이런식이다. 풀이 어? 내림차순? 그럼 정렬 알고리즘 수정해야 하나요??? 아니 그럴 필요는 없으시고요 고객님. 이거 진짜 핵 심플한 문제임. import sys N = sys.stdin.readline().rstrip() x = [] for i in N: x.append(i) x.sort(reverse=True) x = ''.join(x) print(x) 파이썬은 문자도 시퀀스형 데이터이기 때문에 반복문을 돌릴 수 있다..

백준 2108번 풀이

문제 https://www.acmicpc.net/problem/2108 2108번: 통계학 첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 단, N은 홀수이다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다. www.acmicpc.net 산술평균, 최빈값, 중앙값, 범위 출력하기 Reference https://jiwon-coding.tistory.com/8 [백준] 2108번 통계학 파이썬(python) # 문제 링크 www.acmicpc.net/problem/2108 2108번: 통계학 첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘..

백준 25305번 풀이

문제 https://www.acmicpc.net/problem/25305 25305번: 커트라인 시험 응시자들 가운데 1등은 100점, 2등은 98점, 3등은 93점이다. 2등까지 상을 받으므로 커트라인은 98점이다. www.acmicpc.net 참가자 인원 수와 상을 타는 인원 수, 그리고 점수가 주어졌을 때 점수가 가장 낮은 사람을 출력하시오 풀이 보통 커트라인이라고 하면 수능이나 모평때 많이 쓰는 말인데, 9월 모평 1등급 등급컷이 얼마더라~ 이런 식으로 쓴다. 수능이나 모평의 등급컷은 전체적인 난이도와 참여 인원에 따라 달라지기때문에 똑같이 50점을 받았어도 난이도가 핵불닭수능이면 등급이 높고, 물수능이면 등급 망한다. 아, 그거랑 별개로 이 문제는 대단히 쉽다. 입력받은 점수를 정렬하고 뒤에서 ..

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..

대형프로젝트 계획중

한가지 확실한 건 이건 진짜 개노가다가 맞음. 블로그를 좀 오래 전부터 보신 분들은 아시겠지만 깃헙에 유일하게 폴더로 분리된 대형 프로젝트가 두 개 있다. 첫번째가 프로젝트 제한효소, 두번째가 프로젝트 워드클라우드. 근데 이게 쌩코드가 올라와서 이걸 복사해서 수정해서 또 올려야되는데 귀찮아요... 그래서 Flask로 웹이랑 묶으려고 생각중이다. (프로젝트 제한효소는 DB로 쓰는 csv파일도 포함) 근데 또 고려할 게 생겼어...OTL 1) 코드 통합 문제 프로젝트 워드클라우드의 경우 한글/영어/Entrez 세 개의 코드가 있고, 프로젝트 제한효소에는 커터/파인더/서쳐 세 개의 코드가 있다. 프로젝트 제한효소는 세 코드가 사용 목적이 다 달라서 통합은 안되고, 한 페이지 안에서 세개를 다 띄우려면 아코디언..

input vs sys.stdin.readline()

예에에에에전에 백준 18108번 풀이를 올렸을 때 댓글로 질문이 하나 왔었다. input()대신 sys.stdin.realine()을 쓰는 이유를 알 수 있나요? 백준에서 빠르다고 해서 쓰고 있었음... 아니 농담 아니고 진짜다. 반복문 이런거 잘못 짜면 응애 나 애기시간초과! 가 반기는데 다른데서라도 시간 줄여야져... 일단 둘 다 입력 받을 때 쓰는 게 맞다. input() #input import sys sys.stdin.readline() #sys.stdin.readline() 각각 이렇게 쓰면 된다. 근데 이렇게만 해 두면 왜 쟤가 빠른지 체감이 잘 안 올 것이다. 우리가 input()을 쓸 때는 저렇게 쓰는 것 보단 input('메시지를 입력해주세요') 이런 식으로 쓴다. 이 때, 저 안에 있..

Python으로 JSON파일 읽기

JSON은 JavaScript Object Notation을 줄인 것으로, 보통 제이슨으로 읽는다. 일반적으로 클라이언트가 서버에서 가져오는 데이터는 이 형식이고, 현재 표준 형식으로 많이 쓰이고 있다. 원류는 자바스크립트지만 현재는 언어 독립적인 개별 포맷. 그러니까 누가 제이슨 파일 주세요 하면 JSON파일 달라는거지 제이슨씨 파일 주세요가 아니다 남의 파일을 왜 달라고 해 ​ 키-값 쌍으로 이루어진 데이터를 텍스트 형태로 기록해둔 것이라 휴먼 가독성은 좋다. 오늘의 도우미 { "Water": { "molecular weight": "18.016", "molecular formula": "H2O" }, "Ethanol": { "molecular weight": "46.07", "molecular fo..

백준 1427번 풀이

BOJ/[BOJ] Python 2022. 8. 23. 17:33

문제

https://www.acmicpc.net/problem/1427

 

1427번: 소트인사이드

첫째 줄에 정렬하려고 하는 수 N이 주어진다. N은 1,000,000,000보다 작거나 같은 자연수이다.

www.acmicpc.net

숫자 정렬하는 문제인데 이제 입력이 192834729 막 이런식이다.

 

풀이

어? 내림차순? 그럼 정렬 알고리즘 수정해야 하나요??? 아니 그럴 필요는 없으시고요 고객님. 이거 진짜 핵 심플한 문제임.

 

import sys

N = sys.stdin.readline().rstrip()
x = []

for i in N:
    x.append(i)

x.sort(reverse=True)
x = ''.join(x)

print(x)

파이썬은 문자도 시퀀스형 데이터이기 때문에 반복문을 돌릴 수 있다. 그래서 문자로 들어온 숫자를 for문 돌려서 하나씩 배열에 넣고(별도로 나눌 필요도 없고 그냥 for문 돌리면 하나씩 들어간다) sort를 하면 된다. 뭘 주고? reverse=True를 주고. 다음은 그걸 내림차순으로 정렬한 다음 join으로 묶어서 출력하면 끝이다.

'BOJ > [BOJ] Python' 카테고리의 다른 글

백준 11650, 11651번 풀이  (0) 2022.09.19
백준 25501번 풀이  (0) 2022.09.13
백준 2108번 풀이  (0) 2022.08.23
백준 25305번 풀이  (0) 2022.08.23
백준 10989번 풀이  (0) 2022.08.20
Lv. 35 라이츄

Lv. 35 라이츄

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

백준 2108번 풀이

BOJ/[BOJ] Python 2022. 8. 23. 01:30

문제

https://www.acmicpc.net/problem/2108

 

2108번: 통계학

첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 단, N은 홀수이다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.

www.acmicpc.net

산술평균, 최빈값, 중앙값, 범위 출력하기

 

Reference

https://jiwon-coding.tistory.com/8

 

[백준] 2108번 통계학 파이썬(python)

# 문제 링크 www.acmicpc.net/problem/2108 2108번: 통계학 첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다. www..

jiwon-coding.tistory.com

 

풀이

아니 R이랑 엑셀 냅두고 왜... 걔네는 장식인가 

여기서 얘기하는 산술평균이 우리가 일반적으로 얘기하는 평균이다. 평균은 산술/기하/조화평균이 있는데 이건 나중에 얘기하도록 하자... 아무튼, 그래서 4가지 요소를 어떻게 구하느냐... 평균은 일반적인 그 평균이 '맞다'. 중앙값은 말 그대로 정렬된 배열의 가운데에 있는 값이고, 최빈값은 배열에서 제일 많은 값(단, 여러개일 경우 두번째로 작은거), 범위는 최대-최소 하면 된다. 

근데 여기서 최빈값이 끝판왕임. 

 

import sys
from collections import Counter

N = int(sys.stdin.readline())
arr = []

for _ in range(N):
    arr.append(int(sys.stdin.readline()))

average = round(sum(arr)/N)
print(average)
# Average

arr.sort()
median = arr[N // 2]
print(median)
# Median

count_array = Counter(arr).most_common()
if len(count_array) > 1 and count_array[0][1] == count_array[1][1]:
    print(count_array[1][0])
else: 
    print(count_array[0][0])

range = max(arr) - min(arr)
print(range)

저 콜렉션 저거는 더 찾아보고 알려드림. 한가지 확실한건 저게 있어서 그나마 코드가 저렇게 짧은겁니다. ㄹㅇ임. 

평균: 다 더해서 배열 길이로 나눈다
중앙값: 배열을 정렬한 다음 배열 길이 // 2의 값을 가져온다. (길이가 5면 2, 7이면 3 이런 식. 파이썬은 0부터 센다)
최빈값: 어레이를 하나 만들건데 배열 안에 들어있는 값과 몇개인지가 들어가게 된다. 이 배열을 비교해서 옆에 있는 애랑 개수가 같으면 두번째 놈을 출력한다. 
범위: 최댓값-최솟값(개심플)

엥? 배열이 어떻게 나오길래 그래요? 

[(-2, 2), (-1, 2), (-3, 1)]

이렇게 나온다. 오른쪽 값이 개수인데, 그게 같은 것끼리 정렬하고 큰 그림을 그리는 식이라 저걸로 처리된 것. 

결론: 엑셀 쓰자 결론 에반데 

'BOJ > [BOJ] Python' 카테고리의 다른 글

백준 25501번 풀이  (0) 2022.09.13
백준 1427번 풀이  (0) 2022.08.23
백준 25305번 풀이  (0) 2022.08.23
백준 10989번 풀이  (0) 2022.08.20
백준 2750번 풀이  (0) 2022.08.20
Lv. 35 라이츄

Lv. 35 라이츄

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

백준 25305번 풀이

BOJ/[BOJ] Python 2022. 8. 23. 01:27

문제

https://www.acmicpc.net/problem/25305

 

25305번: 커트라인

시험 응시자들 가운데 1등은 100점, 2등은 98점, 3등은 93점이다. 2등까지 상을 받으므로 커트라인은 98점이다.

www.acmicpc.net

참가자 인원 수와 상을 타는 인원 수, 그리고 점수가 주어졌을 때 점수가 가장 낮은 사람을 출력하시오

 

풀이

보통 커트라인이라고 하면 수능이나 모평때 많이 쓰는 말인데, 9월 모평 1등급 등급컷이 얼마더라~ 이런 식으로 쓴다. 수능이나 모평의 등급컷은 전체적인 난이도와 참여 인원에 따라 달라지기때문에 똑같이 50점을 받았어도 난이도가 핵불닭수능이면 등급이 높고, 물수능이면 등급 망한다. 

아, 그거랑 별개로 이 문제는 대단히 쉽다. 입력받은 점수를 정렬하고 뒤에서 k번째인 원소를 뽑으면 되거든. 

import sys
N, k = map(int,sys.stdin.readline().split())

x = list(map(int,sys.stdin.readline().split()))

def merge_sort(array):
	if len(array) < 2:
		return array
	mid = len(array) // 2
	low_arr = merge_sort(array[:mid])
	high_arr = merge_sort(array[mid:])
    # 일단 짼다

	merged_arr = []
	l = h = 0
	while l < len(low_arr) and h < len(high_arr):
		if low_arr[l] < high_arr[h]:
			merged_arr.append(low_arr[l])
			l += 1
		else:
			merged_arr.append(high_arr[h])
			h += 1
	merged_arr += low_arr[l:]
	merged_arr += high_arr[h:]
	return merged_arr
    # 그리고 비교한다

print(merge_sort(x))

일단 잘못하면 응애 나 애기시간초과! 가 반길수도 있으니 빠름 빠름 빠름 LTE-빠름! 이라는 병합정렬을 가져와보자. 그리고 예시를 저기에 돌려보면 

5 2
100 76 85 93 98
[76, 85, 93, 98, 100]

정답이 98인데... 뒤에서 두번째에 있다. 

 

import sys
N, k = map(int,sys.stdin.readline().split())

x = list(map(int,sys.stdin.readline().split()))

def merge_sort(array):
	if len(array) < 2:
		return array
	mid = len(array) // 2
	low_arr = merge_sort(array[:mid])
	high_arr = merge_sort(array[mid:])
    # 일단 짼다

	merged_arr = []
	l = h = 0
	while l < len(low_arr) and h < len(high_arr):
		if low_arr[l] < high_arr[h]:
			merged_arr.append(low_arr[l])
			l += 1
		else:
			merged_arr.append(high_arr[h])
			h += 1
	merged_arr += low_arr[l:]
	merged_arr += high_arr[h:]
	return merged_arr
    # 그리고 비교한다

print(merge_sort(x)[-k])

그래서 정렬하고 뒤에서 k번째인 수를 뽑으면 되기 때문에 -k로 인덱싱 해 주면 된다. (-1이 뒤에서 첫번째)

'BOJ > [BOJ] Python' 카테고리의 다른 글

백준 1427번 풀이  (0) 2022.08.23
백준 2108번 풀이  (0) 2022.08.23
백준 10989번 풀이  (0) 2022.08.20
백준 2750번 풀이  (0) 2022.08.20
백준 1436번 풀이  (0) 2022.08.20
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 라이츄

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

대형프로젝트 계획중

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

한가지 확실한 건 이건 진짜 개노가다가 맞음. 


블로그를 좀 오래 전부터 보신 분들은 아시겠지만 깃헙에 유일하게 폴더로 분리된 대형 프로젝트가 두 개 있다. 첫번째가 프로젝트 제한효소, 두번째가 프로젝트 워드클라우드. 근데 이게 쌩코드가 올라와서 이걸 복사해서 수정해서 또 올려야되는데 귀찮아요... 그래서 Flask로 웹이랑 묶으려고 생각중이다. (프로젝트 제한효소는 DB로 쓰는 csv파일도 포함)

근데 또 고려할 게 생겼어...OTL 

1) 코드 통합 문제
프로젝트 워드클라우드의 경우 한글/영어/Entrez 세 개의 코드가 있고, 프로젝트 제한효소에는 커터/파인더/서쳐 세 개의 코드가 있다. 프로젝트 제한효소는 세 코드가 사용 목적이 다 달라서 통합은 안되고, 한 페이지 안에서 세개를 다 띄우려면 아코디언 패널이나 탭 메뉴가 있어야 한다. 워드클라우드도 Entrez는 입력 인자가 달라서 분리해야 하고, 한글과 영어는 언어에 따른 처리 인자만 달라서 코드를 통합하고 언어 선택을 라디오버튼으로 줄 수 있다. (페이지를 합칠거면 역시나 탭이나 아코디언 패널이 필요하다)

사실 이 부분은 별로 고민을 안한게 우리에겐 개쩌는 부트스트랩이 있다. 

2) 파일 브라우징 문제
내가 저걸 돌리는 OS가 리눅스라 이미지 브라우저나 글꼴 폴더를 다 고정해놓고 쓰고 있는데, 일단 이게 왜 문제냐면, 코드를 돌리는 OS가 리눅스라 저장 경로가 리눅스 위주이다. (윈도우는 홈이 없음) 리눅스는 글꼴도 저장해두는 폴더 가서 ttf나 otf 선택해서 쓰면 된다. 그럼 윈도우는요? 윈도우는 글꼴 어떻게 고르는지 모른다. 

프로젝트 제한효소도 FASTA, Genbank파일때문에 브라우저를 띄워야 하고, 워드클라우드는 마스킹 이미지때문에 브라우저를 띄워야 한다. OS 정보를 가져올 수 있으면 거기에 맞춰서 home이건 C드라이브건 띄우면 장땡. 저장은 브라우저 설정 따라가게 하면 된다. 

3) 입력 인자
여기서부터는 프로젝트 워드클라우드의 문제. (제한효소는 저 두개만 처리하면 일단 끝난다) 

Entrez는 Pubmed에서 논문 검색할 때 쓰는 검색어(A[TITLE] and B[TITLE])를 입력받기 때문에 그 부분에 대한 안내만 하면 된다. 문제는 그냥 워드클라우드인데, 이쪽은 현재 While True로 여러개 입력을 받고 있다. (하나만 써도 되긴 된다) IDE에서는 텍스트 편집이 어려워서 이렇게 했다. 

현재 가장 좋은 방법은 textarea를 크게 주고 하나만 입력받는 걸로 제한하는 것. While True 걸어놓고 거기에 대해 안내하는것보단 이게 나을 듯 하다. 샘플 텍스트로 한글 워드클라우드는 윤동주-별 헤는 밤을 제공할 예정. 그게 제일 이쁘게 나왔다. 

4) 글꼴
현재 워드클라우드 코드는 내가 보유한 글꼴을 선택해서 적용하고 있다. 그런데 다른 사람들이 내 글꼴을 쓸 수는 없고... 구글 웹폰트나 텍스트 에디터의 글꼴 선택 메뉴같은 게 있으면 좋을 것 같은데 그걸 어떻게 하는지를 몰라서, 이쪽으로는 더 알아봐야 할 듯 하다. 

Lv. 35 라이츄

Lv. 35 라이츄

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

input vs sys.stdin.readline()

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

예에에에에전에 백준 18108번 풀이를 올렸을 때 댓글로 질문이 하나 왔었다. 

input()대신 sys.stdin.realine()을 쓰는 이유를 알 수 있나요?

백준에서 빠르다고 해서 쓰고 있었음... 아니 농담 아니고 진짜다. 반복문 이런거 잘못 짜면 응애 나 애기시간초과! 가 반기는데 다른데서라도 시간 줄여야져... 


일단 둘 다 입력 받을 때 쓰는 게 맞다. 

input()
#input

import sys
sys.stdin.readline()
#sys.stdin.readline()

각각 이렇게 쓰면 된다. 근데 이렇게만 해 두면 왜 쟤가 빠른지 체감이 잘 안 올 것이다. 

 

우리가 input()을 쓸 때는 저렇게 쓰는 것 보단 

input('메시지를 입력해주세요')

이런 식으로 쓴다. 이 때, 저 안에 있는 텍스트를 '프롬프트 메시지'라고 한다. 그럼 sys.stdin.readline()도 프롬프트 메시지가 있나요? 놉. 이게 sys.stdin.readline()이 input()보다 빠른 이유 중 하나다. 엥? 이유가 또 있어요? 예. 

파이썬에서는 입력을 받을 때 개행 문자(\n)가 같이 딸려온다. input()은 개행 문자를 떼버리는데 sys.stdin.readline()은 개행문자를 안 떼고 그냥 받는다. 그래서 sys.stdin.readline()으로 받고 나면 항상 rstrip()이나 strip() 메소드가 따라와야 한다. 

a = sys.stdin.readline().rstrip() 
a = sys.stdin.readline().strip()

그러니까 이렇게 써야 개행 문자를 떼고 입력을 받는다. 정확히 말하자면 rstrip()은 개행문자를 떼 주고, strip()은 공백을 떼버린다.

 

즉, sys.stdin.readline()이 빠른 이유는

1. 개행문자를 안 떼고

2. 프롬프트 메시지도 안 받기 때문

이라고 할 수 있다.

참고로 일부 IDE나 에디터에서 sys.stdin.readline()은 안먹으니 시간이 정말 급한거다 잘못하면 응애 나 애기시간초과! 가 반긴다 이런거 아님 걍 인풋 쓰자. 대표적인 예로 Jupyter에서는 sys.stdin.readline()이 입력을 안 받고(그냥 안받음) Spyder에서는 형변환 에러가 뜬다. 그냥 런던올림픽 펜싱심판 데려오면 안되나 아니 그냥 파이참을 써 파이참은 안해봤는데 VScode는 sys.stdin.readline()이 먹힌다.

Lv. 35 라이츄

Lv. 35 라이츄

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

Python으로 JSON파일 읽기

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

JSON은 JavaScript Object Notation을 줄인 것으로, 보통 제이슨으로 읽는다. 일반적으로 클라이언트가 서버에서 가져오는 데이터는 이 형식이고, 현재 표준 형식으로 많이 쓰이고 있다. 원류는 자바스크립트지만 현재는 언어 독립적인 개별 포맷. 그러니까 누가 제이슨 파일 주세요 하면 JSON파일 달라는거지 제이슨씨 파일 주세요가 아니다 남의 파일을 왜 달라고 해

키-값 쌍으로 이루어진 데이터를 텍스트 형태로 기록해둔 것이라 휴먼 가독성은 좋다.


오늘의 도우미

{
	"Water": {
		"molecular weight": "18.016",
		"molecular formula": "H2O"
	},
	"Ethanol": {
		"molecular weight": "46.07",
		"molecular formula": "C2H5OH"
	},
	"Glucose": {
		"molecular weight": "180.156",
		"molecular formula": "C6H12O6"
	},
	"Sucrose": {
		"molecular weight": "342.3",
		"molecular formula": "C12H22O11"
	}
}

짜잔 이래뵈도 수제다 

그리고 이거 하려면 모듈 불러야 한다. 별도로 설치는 안해도 되고 

import json

이거 한줄만 추가합시다. 

 

JSON파일 읽기

with open('/home/koreanraichu/test.json') as f:
    json_data = json.load(f)
print(json.dumps(json_data))

그냥 이렇게 쓰면 알아서 불러온다. 

 

{"Water": {"molecular weight": "18.016", "molecular formula": "H2O"}, "Ethanol": {"molecular weight": "46.07", "molecular formula": "C2H5OH"}, "Glucose": {"molecular weight": "180.156", "molecular formula": "C6H12O6"}, "Sucrose": {"molecular weight": "342.3", "molecular formula": "C12H22O11"}}

형식에서 그렇게 큰 기대는 하지 말자. (참고로 VScode가 가끔 키보드 먹통이 되는 문제가 있어서 spyder로 함...)

그럼 저기서 특정 데이터만 볼 수 있어요? 예, 됩니다. 

{"Water": {"molecular weight": "18.016", "molecular formula": "H2O"}

형식이 잘 보면 딕셔너리다. 파이썬은 JSON파일을 불러올 때 딕셔너리로 불러오는데, 이 파일의 경우 다중 딕셔너리(2중)이다. 그리고 딕셔너리는 뭐다? 키-밸류로 되어 있고 키값으로 픽이 된다 그죠? 

 

print(json_data['Water'])
print(json_data['Water']['molecular formula'])

걍 이렇게 부르면 된다. 정렬도 가능하다. 

 

JSON파일 수정하기

{"Water": {"molecular weight": "18.016", "molecular formula": "H2O"}, "Ethanol": {"molecular weight": "46.07", "molecular formula": "C2H5OH"}, "Glucose": {"molecular weight": "180.156", "molecular formula": "C6H12O6"}, "Sucrose": {"molecular weight": "342.3", "molecular formula": "C12H22O11"}, "Methanol": {"molecular weight": "", "molecular formula": ""}}

여기에 메탄올에 대한 정보를 새로 추가했는데, 문제가 하나 있다. 

"Methanol": {"molecular weight": "", "molecular formula": ""}

뭐야 메탄올 정보 어디갔어요? 

이거 그럼 raw file 수정해야 하나요? ㄴㄴ 파이썬에서 커버칠 수 있다. 

json_data['Methanol']['molecular weight'] = '32.04'
json_data['Methanol']['molecular formula'] = 'CH3OH'

이런 식으로 키값을 픽해서 밸류를 수정하고 

with open ('/home/koreanraichu/test.json','w', encoding='utf-8') as s:
    json.dump(json_data,s)

이렇게 하면 들여쓰기가 가출한다. 

 

with open ('/home/koreanraichu/test.json','w', encoding='utf-8') as s:
    json.dump(json_data,s,indent = '\t')

indent = \t를 주자. 

 

JSON파일 쓰기

JSON파일을 읽고 수정해봤으면 이제 쓸 시간이다. 아니 거기 에디터 꺼요... 

 

cellphone = dict()
cellphone['Samsung'] = "Galaxy Z flip"
cellphone['Apple'] = "iPhone"
tabletpc = dict()
tabletpc['Samsung'] = 'Galaxy tab'
tabletpc['Apple'] = 'iPad'

핸드폰과 태블릿PC에 대한 딕셔너리를 생성해준다. (핸드폰 영어로 cellphone임)

 

mobile_device = dict()
mobile_device['Cellphone'] = cellphone
mobile_device['Tablet PC'] = tabletpc

그리고 두 개의 딕셔너리를 밸류로 갖는 큰 딕셔너리(모바일 기기)를 하나 만든다. 

 

with open ('/home/koreanraichu/test2.json','w', encoding='utf-8') as s:
    json.dump(mobile_device,s,indent = '\t')

그리고 묶은 딕셔너리를 그대로 JSON파일로 쓰면 이렇게 된다. 참 쉽죠? 

Lv. 35 라이츄

Lv. 35 라이츄

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

방명록