Dmtlant commited on
Commit
ec3010d
·
verified ·
1 Parent(s): 6a1b049

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +81 -68
app.py CHANGED
@@ -1,21 +1,17 @@
1
- import streamlit as st
2
  import numpy as np
3
  import matplotlib.pyplot as plt
 
4
  import random
5
  from scipy.stats import entropy as scipy_entropy
6
- import time
7
- import imageio
8
- from datetime import datetime
9
-
10
- st.set_page_config(layout="wide")
11
 
12
- # --- ПАРАМЕТРЫ ---
13
- seqlen = 60
14
- min_run, max_run = 1, 2
 
15
  ANGLE_MAP = {'A': 60.0, 'C': 180.0, 'G': -60.0, 'T': -180.0, 'N': 0.0}
16
  bases = ['A', 'C', 'G', 'T']
17
 
18
- # --- ФУНКЦИИ ---
19
  def find_local_min_runs(profile, min_run=1, max_run=2):
20
  result = []
21
  N = len(profile)
@@ -30,6 +26,7 @@ def find_local_min_runs(profile, min_run=1, max_run=2):
30
  i += run_length
31
  return result
32
 
 
33
  def bio_mutate(seq):
34
  r = random.random()
35
  if r < 0.70:
@@ -42,88 +39,104 @@ def bio_mutate(seq):
42
  newbase = 'G' if prob < 0.65 else random.choice(['A', 'G'])
43
  else:
44
  newbase = random.choice([b for b in bases if b != orig])
45
- seq = ''.join(seq[:idx]) + newbase + ''.join(seq[idx+1:])
46
  elif r < 0.80:
47
  idx = random.randint(0, len(seq)-1)
48
  ins = ''.join(random.choices(bases, k=random.randint(1, 3)))
49
- seq = ''.join(seq[:idx]) + ins + ''.join(seq[idx:])
50
  if len(seq) > seqlen:
51
  seq = seq[:seqlen]
52
  elif r < 0.90:
53
  if len(seq) > 4:
54
  idx = random.randint(0, len(seq)-2)
55
  dell = random.randint(1, min(3, len(seq)-idx))
56
- seq = ''.join(seq[:idx]) + ''.join(seq[idx+dell:])
57
  else:
58
  if len(seq) > 10:
59
  start = random.randint(0, len(seq)-6)
60
  end = start + random.randint(3,6)
61
- subseq = seq[start:end][::-1]
62
- seq = ''.join(seq[:start]) + ''.join(subseq) + ''.join(seq[end:])
 
63
  while len(seq) < seqlen:
64
  seq += random.choice(bases)
65
- return seq[:seqlen]
 
 
66
 
67
  def compute_autocorr(profile):
68
  profile = profile - np.mean(profile)
69
  result = np.correlate(profile, profile, mode='full')
70
  result = result[result.size // 2:]
71
- norm = np.max(result) if np.max(result) != 0 else 1
72
- return result[:10]/norm
73
 
74
  def compute_entropy(profile):
75
  vals, counts = np.unique(profile, return_counts=True)
76
  p = counts / counts.sum()
77
  return scipy_entropy(p, base=2)
78
 
79
- # --- UI ---
80
- st.title("🔴 Живой эфир мутаций ДНК")
81
- start = st.button("▶️ Старт эфира")
82
- stop = st.checkbox("⏹️ Остановить")
83
-
84
- plot_placeholder = st.empty()
85
-
86
- if start:
87
- seq = ''.join(random.choices(bases, k=seqlen))
88
- stat_bist_counts = []
89
- stat_entropy = []
90
-
91
- step = 0
92
- while True:
93
- if stop:
94
- st.warning("⏹️ Эфир остановлен пользователем.")
95
- break
96
-
97
- if step != 0:
98
- seq = bio_mutate(seq)
99
-
100
- torsion_profile = np.array([ANGLE_MAP.get(nt, 0.0) for nt in seq])
101
- runs = find_local_min_runs(torsion_profile, min_run, max_run)
102
- stat_bist_counts.append(len(runs))
103
- ent = compute_entropy(torsion_profile)
104
- stat_entropy.append(ent)
105
- acorr = compute_autocorr(torsion_profile)
106
-
107
- fig, axs = plt.subplots(3, 1, figsize=(10, 8))
108
- plt.subplots_adjust(hspace=0.45)
109
-
110
- axs[0].plot(torsion_profile, color='royalblue')
111
- for start_, end_, val in runs:
112
- axs[0].axvspan(start_, end_, color="red", alpha=0.3)
113
- axs[0].set_ylim(-200, 200)
114
- axs[0].set_title(f"Шаг {step}: {seq}")
115
- axs[0].set_ylabel("Торсионный угол")
116
-
117
- axs[1].plot(stat_bist_counts, '-o', color='crimson', markersize=4)
118
- axs[1].set_ylabel("Биомашины")
119
- axs[1].set_title("Количество машин")
120
-
121
- axs[2].bar(np.arange(6), acorr[:6], color='teal')
122
- axs[2].set_title(f"Автокорреляция / Энтропия: {ent:.2f}")
123
- axs[2].set_xlabel("Лаг")
124
-
125
- plot_placeholder.pyplot(fig)
126
- plt.close(fig)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
- step += 1
129
- time.sleep(0.3)
 
 
1
  import numpy as np
2
  import matplotlib.pyplot as plt
3
+ from matplotlib.animation import FuncAnimation
4
  import random
5
  from scipy.stats import entropy as scipy_entropy
6
+ import streamlit as st
 
 
 
 
7
 
8
+ # --- НАСТРОЙКИ ---
9
+ seqlen = st.slider("Длина последовательности", 10, 100, 60)
10
+ steps = st.slider("Количество шагов", 10, 200, 120)
11
+ min_run, max_run = st.slider("Длина машин", 1, 10, 1), st.slider("Максимальная длина машин", 2, 10, 2)
12
  ANGLE_MAP = {'A': 60.0, 'C': 180.0, 'G': -60.0, 'T': -180.0, 'N': 0.0}
13
  bases = ['A', 'C', 'G', 'T']
14
 
 
15
  def find_local_min_runs(profile, min_run=1, max_run=2):
16
  result = []
17
  N = len(profile)
 
26
  i += run_length
27
  return result
28
 
29
+ # --- Более биологичные мутации ---
30
  def bio_mutate(seq):
31
  r = random.random()
32
  if r < 0.70:
 
39
  newbase = 'G' if prob < 0.65 else random.choice(['A', 'G'])
40
  else:
41
  newbase = random.choice([b for b in bases if b != orig])
42
+ seq = seq[:idx] + newbase + seq[idx+1:]
43
  elif r < 0.80:
44
  idx = random.randint(0, len(seq)-1)
45
  ins = ''.join(random.choices(bases, k=random.randint(1, 3)))
46
+ seq = seq[:idx] + ins + seq[idx:]
47
  if len(seq) > seqlen:
48
  seq = seq[:seqlen]
49
  elif r < 0.90:
50
  if len(seq) > 4:
51
  idx = random.randint(0, len(seq)-2)
52
  dell = random.randint(1, min(3, len(seq)-idx))
53
+ seq = seq[:idx] + seq[idx+dell:]
54
  else:
55
  if len(seq) > 10:
56
  start = random.randint(0, len(seq)-6)
57
  end = start + random.randint(3,6)
58
+ subseq = seq[start:end]
59
+ subseq = subseq[::-1]
60
+ seq = seq[:start] + subseq + seq[end:]
61
  while len(seq) < seqlen:
62
  seq += random.choice(bases)
63
+ if len(seq) > seqlen:
64
+ seq = seq[:seqlen]
65
+ return seq
66
 
67
  def compute_autocorr(profile):
68
  profile = profile - np.mean(profile)
69
  result = np.correlate(profile, profile, mode='full')
70
  result = result[result.size // 2:]
71
+ norm = np.max(result) if np.max(result)!=0 else 1
72
+ return result[:10]/norm # только лаги 0..9
73
 
74
  def compute_entropy(profile):
75
  vals, counts = np.unique(profile, return_counts=True)
76
  p = counts / counts.sum()
77
  return scipy_entropy(p, base=2)
78
 
79
+ # --- Начальная цепь ---
80
+ seq = ''.join(random.choices(bases, k=seqlen))
81
+ stat_bist_counts = []
82
+ stat_entropy = []
83
+ stat_autocorr = []
84
+
85
+ fig, axs = plt.subplots(3, 1, figsize=(10, 8))
86
+ plt.subplots_adjust(hspace=0.45)
87
+ lags_shown = 6
88
+
89
+ def draw_world(seq, axs, step, cnt_hist, ent_hist, ac_hist):
90
+ torsion_profile = np.array([ANGLE_MAP.get(nt, 0.0) for nt in seq])
91
+ runs = find_local_min_runs(torsion_profile, min_run, max_run)
92
+ axs[0].cla()
93
+ axs[1].cla()
94
+ axs[2].cla()
95
+
96
+ axs[0].plot(torsion_profile, color='royalblue', label="Торсионный угол")
97
+ for start, end, val in runs:
98
+ axs[0].axvspan(start, end, color="red", alpha=0.3)
99
+ axs[0].plot(range(start, end+1), torsion_profile[start:end+1], 'ro', markersize=5)
100
+ axs[0].set_ylim(-200, 200)
101
+ axs[0].set_xlabel("Позиция")
102
+ axs[0].set_ylabel("Торсионный угол (град.)")
103
+ axs[0].set_title(f"Шаг {step}: {seq}\nЧисло машин: {len(runs)}, энтропия: {ent_hist[-1]:.2f}")
104
+ axs[0].legend()
105
+
106
+ axs[1].plot(cnt_hist, '-o', color='crimson', markersize=4)
107
+ axs[1].set_xlabel("Шаг")
108
+ axs[1].set_ylabel("Число машин")
109
+ axs[1].set_ylim(0, max(10, max(cnt_hist)+1))
110
+ axs[1].set_title("Динамика: число 'биомашин'")
111
+
112
+ axs[2].bar(np.arange(lags_shown), ac_hist[-1][:lags_shown], color='teal', alpha=0.7)
113
+ axs[2].set_xlabel("Лаг")
114
+ axs[2].set_ylabel("Автокорреляция")
115
+ axs[2].set_title("Автокорреляция углового профиля (структурность) и энтропия")
116
+ axs[2].text(0.70,0.70, f"Энтропия: {ent_hist[-1]:.2f}", transform=axs[2].transAxes)
117
+
118
+ def animate(i):
119
+ global seq, stat_bist_counts, stat_entropy, stat_autocorr
120
+ if i == 0:
121
+ stat_bist_counts.clear()
122
+ stat_entropy.clear()
123
+ stat_autocorr.clear()
124
+ else:
125
+ seq = bio_mutate(seq)
126
+ torsion_profile = np.array([ANGLE_MAP.get(nt, 0.0) for nt in seq])
127
+ runs = find_local_min_runs(torsion_profile, min_run, max_run)
128
+ stat_bist_counts.append(len(runs))
129
+ ent = compute_entropy(torsion_profile)
130
+ stat_entropy.append(ent)
131
+ acorr = compute_autocorr(torsion_profile)
132
+ stat_autocorr.append(acorr)
133
+ draw_world(seq, axs, i, stat_bist_counts, stat_entropy, stat_autocorr)
134
+ return axs
135
+
136
+ # --- Запуск анимации в Streamlit ---
137
+ if st.button("Начать анимацию"):
138
+ anim = FuncAnimation(
139
+ fig, animate, frames=steps, interval=600, repeat=False, blit=False
140
+ )
141
+ st.pyplot(fig)
142