File size: 4,924 Bytes
e250773 cab60db 3ffebe8 599d710 3ffebe8 ce76895 cab60db 599d710 70faa9c 3ffebe8 cab60db 70faa9c 3ffebe8 cab60db 3ffebe8 e250773 f1e60b9 3ffebe8 e250773 f1e60b9 3ffebe8 396e0c2 e250773 f1e60b9 3ffebe8 e250773 3ffebe8 e250773 f1e60b9 3ffebe8 e250773 3ffebe8 e250773 cab60db 396e0c2 30998ff 396e0c2 cab60db ce76895 70faa9c ce76895 599d710 e250773 599d710 70faa9c 3ffebe8 ce76895 70faa9c 0bc0cd3 e250773 70faa9c 0bc0cd3 f1e60b9 599d710 70faa9c 599d710 396e0c2 599d710 30998ff 599d710 30998ff 599d710 30998ff e250773 70faa9c 599d710 |
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
import random
from scipy.stats import entropy as scipy_entropy
import time
st.set_page_config(layout="wide")
# --- ПАРАМЕТРЫ ---
seqlen = 60
min_run, max_run = 1, 2
ANGLE_MAP = {'A': 60.0, 'C': 180.0, 'G': -60.0, 'T': -180.0, 'N': 0.0}
bases = ['A', 'C', 'G', 'T']
# --- ФУНКЦИИ ---
def find_local_min_runs(profile, min_run=1, max_run=2):
result = []
N = len(profile)
i = 0
while i < N:
run_val = profile[i]
run_length = 1
while i + run_length < N and profile[i + run_length] == run_val:
run_length += 1
if min_run <= run_length <= max_run:
result.append((i, i + run_length - 1, run_val))
i += run_length
return result
def bio_mutate(seq):
r = random.random()
mutation_type = "None"
if r < 0.70:
idx = random.randint(0, len(seq)-1)
orig = seq[idx]
prob = random.random()
if orig in 'AG':
newbase = 'C' if prob < 0.65 else random.choice(['T', 'C'])
elif orig in 'CT':
newbase = 'G' if prob < 0.65 else random.choice(['A', 'G'])
else:
newbase = random.choice([b for b in bases if b != orig])
seq = seq[:idx] + newbase + seq[idx+1:]
mutation_type = f"Substitution at {idx}: {orig} → {newbase}"
elif r < 0.80:
idx = random.randint(0, len(seq)-1)
ins = ''.join(random.choices(bases, k=random.randint(1, 3)))
seq = seq[:idx] + ins + seq[idx:]
if len(seq) > seqlen:
seq = seq[:seqlen]
mutation_type = f"Insertion at {idx}: {ins}"
elif r < 0.90:
if len(seq) > 4:
idx = random.randint(0, len(seq)-2)
dell = random.randint(1, min(3, len(seq)-idx))
deleted = seq[idx:idx+dell]
seq = seq[:idx] + seq[idx+dell:]
mutation_type = f"Deletion at {idx}: {deleted}"
else:
if len(seq) > 10:
start = random.randint(0, len(seq)-6)
end = start + random.randint(3,6)
subseq = seq[start:end]
seq = seq[:start] + subseq[::-1] + seq[end:]
mutation_type = f"Inversion from {start} to {end}: {subseq} → {subseq[::-1]}"
while len(seq) < seqlen:
seq += random.choice(bases)
return seq[:seqlen], mutation_type
def compute_autocorr(profile):
profile = profile - np.mean(profile)
result = np.correlate(profile, profile, mode='full')
result = result[result.size // 2:]
norm = np.max(result) if np.max(result) != 0 else 1
return result[:10]/norm
def compute_entropy(profile):
vals, counts = np.unique(profile, return_counts=True)
p = counts / counts.sum()
return scipy_entropy(p, base=2)
# --- UI ---
st.title("🔴 Живой эфир мутаций ДНК")
start = st.button("▶️ Старт эфира")
stop = st.checkbox("⏹️ Остановить")
plot_placeholder = st.empty()
status_placeholder = st.sidebar.empty()
entropy_placeholder = st.sidebar.empty()
mutation_type_placeholder = st.sidebar.empty()
if start:
seq = ''.join(random.choices(bases, k=seqlen))
stat_bist_counts = []
stat_entropy = []
step = 0
while True:
if stop:
st.warning("⏹️ Эфир остановлен пользователем.")
break
if step != 0:
seq, mut_type = bio_mutate(seq)
else:
mut_type = "Initial sequence"
torsion_profile = np.array([ANGLE_MAP.get(nt, 0.0) for nt in seq])
runs = find_local_min_runs(torsion_profile, min_run, max_run)
stat_bist_counts.append(len(runs))
ent = compute_entropy(torsion_profile)
stat_entropy.append(ent)
acorr = compute_autocorr(torsion_profile)
fig, axs = plt.subplots(3, 1, figsize=(10, 8))
plt.subplots_adjust(hspace=0.45)
axs[0].plot(torsion_profile, color='royalblue')
for start_, end_, val in runs:
axs[0].axvspan(start_, end_, color="red", alpha=0.3)
axs[0].set_ylim(-200, 200)
axs[0].set_title(f"Шаг {step}: {seq}")
axs[0].set_ylabel("Торсионный угол")
axs[1].plot(stat_bist_counts, '-o', color='crimson', markersize=4)
axs[1].set_ylabel("Биомашины")
axs[1].set_title("Количество машин")
axs[2].bar(np.arange(6), acorr[:6], color='teal')
axs[2].set_title(f"Автокорреляция / Энтропия: {ent:.2f}")
axs[2].set_xlabel("Лаг")
plot_placeholder.pyplot(fig)
plt.close(fig)
status_placeholder.markdown(f"### ℹ️ Шаг: {step}")
entropy_placeholder.metric("Энтропия", f"{ent:.2f}")
mutation_type_placeholder.markdown(f"**Мутация:** {mut_type}")
step += 1
time.sleep(0.3)
|