Dmtlant commited on
Commit
ce76895
·
verified ·
1 Parent(s): 396e0c2

Update app.py

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