Dmtlant commited on
Commit
0bc0cd3
·
verified ·
1 Parent(s): 71515bf

Update app.py

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