Skip to content

Commit 6d3469f

Browse files
committed
Added ability to select and delete multiple particles, update dual-range slider boundaries when deleting particles
1 parent 8d4e806 commit 6d3469f

File tree

9 files changed

+308
-193
lines changed

9 files changed

+308
-193
lines changed
1020 KB
Binary file not shown.

particleanalyzer/core/ParticleAnalyzer.py

Lines changed: 52 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import os
88
import gc
99
from tqdm import tqdm
10-
from typing import Optional, Tuple
10+
from typing import Optional, Tuple, Dict
1111
from scipy.spatial.distance import pdist
1212
import random
1313
import re
@@ -260,41 +260,7 @@ def analyze_image(
260260
)
261261
stats_df = builder.build_stats_table()
262262

263-
d_max_max = round(
264-
stats_df.data.iloc[1, 3] + stats_df.data.iloc[0, 3] * 0.01,
265-
config["round_value"],
266-
)
267-
d_max_min = round(stats_df.data.iloc[1, 4], config["round_value"])
268-
d_min_max = round(
269-
stats_df.data.iloc[2, 3] + stats_df.data.iloc[1, 3] * 0.01,
270-
config["round_value"],
271-
)
272-
d_min_min = round(stats_df.data.iloc[2, 4], config["round_value"])
273-
theta_max_max = round(
274-
stats_df.data.iloc[4, 3] + stats_df.data.iloc[4, 3] * 0.01,
275-
config["round_value"],
276-
)
277-
theta_max_min = round(stats_df.data.iloc[4, 4], config["round_value"])
278-
theta_min_max = round(
279-
stats_df.data.iloc[5, 3] + stats_df.data.iloc[5, 3] * 0.01,
280-
config["round_value"],
281-
)
282-
theta_min_min = round(stats_df.data.iloc[5, 4], config["round_value"])
283-
S_max = round(
284-
stats_df.data.iloc[6, 3] + stats_df.data.iloc[6, 3] * 0.01,
285-
config["round_value"],
286-
)
287-
S_min = round(stats_df.data.iloc[6, 4], config["round_value"])
288-
P_max = round(
289-
stats_df.data.iloc[7, 3] + stats_df.data.iloc[7, 3] * 0.01,
290-
config["round_value"],
291-
)
292-
P_min = round(stats_df.data.iloc[7, 4], config["round_value"])
293-
I_max = round(
294-
stats_df.data.iloc[9, 3] + stats_df.data.iloc[9, 3] * 0.01,
295-
config["round_value"],
296-
)
297-
I_min = round(stats_df.data.iloc[9, 4], config["round_value"])
263+
limits = self.calculate_limits(df, config["round_value"])
298264

299265
pbar.update(1)
300266

@@ -312,45 +278,45 @@ def analyze_image(
312278
gr.update(visible=api_key),
313279
gr.update(visible=True),
314280
gr.update(
315-
minimum=d_max_min,
316-
maximum=d_max_max,
317-
value=(d_max_min, d_max_max),
318-
step=d_max_max * 0.01,
281+
minimum=limits["d_max_min"],
282+
maximum=limits["d_max_max"],
283+
value=(limits["d_max_min"], limits["d_max_max"]),
284+
step=limits["d_max_max"] * 0.01,
319285
label=f"Dₘₐₓ [{self._get_translation(scale_selector['unit'])}]",
320286
),
321287
gr.update(
322-
minimum=d_min_min,
323-
maximum=d_min_max,
324-
value=(d_min_min, d_min_max),
325-
step=d_min_max * 0.01,
288+
minimum=limits["d_min_min"],
289+
maximum=limits["d_min_max"] ,
290+
value=(limits["d_min_min"], limits["d_min_max"] ),
291+
step=limits["d_min_max"] * 0.01,
326292
label=f"Dₘᵢₙ [{self._get_translation(scale_selector['unit'])}]",
327293
),
328294
gr.update(
329-
minimum=theta_max_min,
330-
maximum=theta_max_max,
331-
value=(theta_max_min, theta_max_max),
295+
minimum=limits["theta_max_min"],
296+
maximum=limits["theta_max_max"],
297+
value=(limits["theta_max_min"], limits["theta_max_max"]),
332298
),
333299
gr.update(
334-
minimum=theta_min_min,
335-
maximum=theta_min_max,
336-
value=(theta_min_min, theta_min_max),
300+
minimum=limits["theta_min_min"],
301+
maximum=limits["theta_min_max"],
302+
value=(limits["theta_min_min"], limits["theta_min_max"]),
337303
),
338304
gr.update(minimum=0, maximum=1, value=(0, 1)),
339305
gr.update(
340-
minimum=S_min,
341-
maximum=S_max,
342-
value=(S_min, S_max),
343-
step=S_max * 0.01,
306+
minimum=limits["S_min"],
307+
maximum=limits["S_max"],
308+
value=(limits["S_min"], limits["S_max"]),
309+
step=limits["S_max"] * 0.01,
344310
label=f"S [{self._get_translation(scale_selector['unit'])}²]",
345311
),
346312
gr.update(
347-
minimum=P_min,
348-
maximum=P_max,
349-
value=(P_min, P_max),
350-
step=P_max * 0.01,
313+
minimum=limits["P_min"],
314+
maximum=limits["P_max"],
315+
value=(limits["P_min"], limits["P_max"]),
316+
step=limits["P_max"] * 0.01,
351317
label=f"P [{self._get_translation(scale_selector['unit'])}]",
352318
),
353-
gr.update(minimum=I_min, maximum=I_max, value=(I_min, I_max)),
319+
gr.update(minimum=limits["I_min"], maximum=limits["I_max"], value=(limits["I_min"], limits["I_max"])),
354320
gr.update(visible=True),
355321
)
356322
except Exception as e:
@@ -795,6 +761,33 @@ def rgba_to_bgr(rgba_str):
795761

796762
return (b, g, r)
797763

764+
765+
@staticmethod
766+
def calculate_limits(df: pd.DataFrame, round_value: int) -> Dict[str, float]:
767+
768+
results = {}
769+
770+
results["d_max_max"] = round(df.iloc[:, 2].max() + df.iloc[:, 2].max() * 0.01, round_value)
771+
results["d_max_min"] = round(df.iloc[:, 2].min(), round_value)
772+
results["d_min_max"] = round(df.iloc[:, 3].max() + df.iloc[:, 3].max() * 0.01, round_value)
773+
results["d_min_min"] = round(df.iloc[:, 3].min(), round_value)
774+
775+
results["theta_max_max"] = round(df.iloc[:, 5].max() + df.iloc[:, 5].max() * 0.01, round_value)
776+
results["theta_max_min"] = round(df.iloc[:, 5].min(), round_value)
777+
results["theta_min_max"] = round(df.iloc[:, 6].max() + df.iloc[:, 6].max() * 0.01, round_value)
778+
results["theta_min_min"] = round(df.iloc[:, 6].min(), round_value)
779+
780+
results["S_max"] = round(df.iloc[:, 7].max() + df.iloc[:, 7].max() * 0.01, round_value)
781+
results["S_min"] = round(df.iloc[:, 7].min(), round_value)
782+
783+
results["P_max"] = round(df.iloc[:, 8].max() + df.iloc[:, 8].max() * 0.01, round_value)
784+
results["P_min"] = round(df.iloc[:, 8].min(), round_value)
785+
786+
results["I_max"] = round(df.iloc[:, 10].max() + df.iloc[:, 10].max() * 0.01, round_value)
787+
results["I_min"] = round(df.iloc[:, 10].min(), round_value)
788+
789+
return results
790+
798791
def _cleanup(self, pbar: Optional[tqdm] = None):
799792
"""Очистка ресурсов"""
800793
if pbar:

particleanalyzer/core/about.py

Lines changed: 62 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,15 @@
3434
border-bottom:1px solid var(--border-color-primary);
3535
box-shadow:var(--block-shadow)
3636
">
37-
<div style="display:flex;align-items:center;gap:15px;margin-bottom:15px;">
38-
<svg width="250" height="55" viewBox="0 0 250 55" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
39-
<image x="2" y="0" width="46" height="46" preserveAspectRatio="xMidYMid meet"
40-
xlink:href="https://svgsilh.com/svg/305079-2196f3.svg"/>
41-
<g font-family="'Segoe UI', 'Helvetica Neue', Arial, sans-serif" text-rendering="optimizeLegibility">
42-
<text x="55" y="25" font-size="22" font-weight="600" letter-spacing="-0.3">
43-
<tspan fill="#3b82f6">ParticleAnalyzer</tspan>
44-
</text>
45-
<text x="56" y="40" font-size="11" fill="#64748b" font-weight="500">
46-
SEM Image Analysis Tool
47-
</text>
48-
</g>
49-
<line x1="49" y1="0" x2="49" y2="50" stroke="#e2e8f0" stroke-width="2" stroke-dasharray="3,2"/>
50-
</svg>
37+
<div style="display: inline-block; margin-left: 7px; overflow: hidden;">
38+
<a href="https://particleanalyzer.ru" target="_blank">
39+
<img
40+
src="https://rybakov-k.ru/assets/icon/Logo2.png"
41+
alt="ParticleAnalyzer"
42+
style="max-height: 50px; width: auto; height: auto;"
43+
class="logo-image"
44+
>
45+
</a>
5146
</div>
5247
<p style="font-size:16px;line-height:1.6;margin-bottom:0;color:var(--text-color)">
5348
Инструмент для <strong style="color:var(--block-label-text-color)">автоматической сегментации</strong>
@@ -59,14 +54,13 @@
5954
<!-- Video Demo Block -->
6055
<div style="background:var(--block-background-fill);padding:20px;border-radius:8px;margin-bottom:20px;border:1px solid var(--border-color-primary);box-shadow:var(--block-shadow);text-align:center">
6156
<h3 style="margin-top:0;color:var(--header-text-color);font-weight:600">🎥 Видео-демонстрация работы</h3>
62-
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;margin-top:15px;border-radius:6px">
63-
<iframe src="https://rutube.ru/play/embed/1f879a0e65c95168704ba53b94f9109a"
64-
style="position:absolute;top:0;left:0;width:100%;height:100%;border:none"
65-
frameborder="0"
66-
allow="cross-origin-isolated; accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
67-
allowfullscreen>
68-
</iframe>
69-
</div>
57+
<div style="margin-top:15px;">
58+
<a href="https://rutube.ru/play/embed/1f879a0e65c95168704ba53b94f9109a"
59+
style="color:var(--link-color);text-decoration:underline;font-size:16px;"
60+
target="_blank">
61+
Ссылка на видео-демонстрацию
62+
</a>
63+
</div>
7064
<p style="font-size:14px;color:var(--text-color-secondary);margin-top:10px">
7165
Посмотрите, как работает ParticleAnalyzer на реальных примерах
7266
</p>
@@ -136,20 +130,15 @@
136130
border-bottom:1px solid var(--border-color-primary);
137131
box-shadow:var(--block-shadow)
138132
">
139-
<div style="display:flex;align-items:center;gap:15px;margin-bottom:15px;">
140-
<svg width="250" height="55" viewBox="0 0 250 55" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
141-
<image x="2" y="0" width="46" height="46" preserveAspectRatio="xMidYMid meet"
142-
xlink:href="https://svgsilh.com/svg/305079-2196f3.svg"/>
143-
<g font-family="'Segoe UI', 'Helvetica Neue', Arial, sans-serif" text-rendering="optimizeLegibility">
144-
<text x="55" y="25" font-size="22" font-weight="600" letter-spacing="-0.3">
145-
<tspan fill="#3b82f6">ParticleAnalyzer</tspan>
146-
</text>
147-
<text x="56" y="40" font-size="11" fill="#64748b" font-weight="500">
148-
SEM Image Analysis Tool
149-
</text>
150-
</g>
151-
<line x1="49" y1="0" x2="49" y2="50" stroke="#e2e8f0" stroke-width="2" stroke-dasharray="3,2"/>
152-
</svg>
133+
<div style="display: inline-block; margin-left: 7px; overflow: hidden;">
134+
<a href="https://particleanalyzer.ru" target="_blank">
135+
<img
136+
src="https://rybakov-k.ru/assets/icon/Logo2.png"
137+
alt="ParticleAnalyzer"
138+
style="max-height: 50px; width: auto; height: auto;"
139+
class="logo-image"
140+
>
141+
</a>
153142
</div>
154143
<p style="font-size:16px;line-height:1.6;margin-bottom:0;color:var(--text-color)">
155144
A tool for analyzing <strong style="color:var(--block-label-text-color)">particle size characteristics</strong>
@@ -161,13 +150,12 @@
161150
<!-- Video Demo Block -->
162151
<div style="background:var(--block-background-fill);padding:20px;border-radius:8px;margin-bottom:20px;border:1px solid var(--border-color-primary);box-shadow:var(--block-shadow);text-align:center">
163152
<h3 style="margin-top:0;color:var(--header-text-color);font-weight:600">🎥 Video Demonstration</h3>
164-
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;margin-top:15px;border-radius:6px">
165-
<iframe src="https://www.youtube.com/embed/qlCuZDjDyqk"
166-
style="position:absolute;top:0;left:0;width:100%;height:100%;border:none"
167-
frameborder="0"
168-
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
169-
allowfullscreen>
170-
</iframe>
153+
<div style="margin-top:15px;">
154+
<a href="https://www.youtube.com/embed/qlCuZDjDyqk"
155+
style="color:var(--link-color);text-decoration:underline;font-size:16px;"
156+
target="_blank">
157+
Link to video demonstration
158+
</a>
171159
</div>
172160
<p style="font-size:14px;color:var(--text-color-secondary);margin-top:10px">
173161
See how ParticleAnalyzer works with real examples
@@ -238,20 +226,15 @@
238226
border-bottom:1px solid var(--border-color-primary);
239227
box-shadow:var(--block-shadow)
240228
">
241-
<div style="display:flex;align-items:center;gap:15px;margin-bottom:15px;">
242-
<svg width="250" height="55" viewBox="0 0 250 55" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
243-
<image x="2" y="0" width="46" height="46" preserveAspectRatio="xMidYMid meet"
244-
xlink:href="https://svgsilh.com/svg/305079-2196f3.svg"/>
245-
<g font-family="'Segoe UI', 'Helvetica Neue', Arial, sans-serif" text-rendering="optimizeLegibility">
246-
<text x="55" y="25" font-size="22" font-weight="600" letter-spacing="-0.3">
247-
<tspan fill="#3b82f6">ParticleAnalyzer</tspan>
248-
</text>
249-
<text x="56" y="40" font-size="11" fill="#64748b" font-weight="500">
250-
SEM Image Analysis Tool
251-
</text>
252-
</g>
253-
<line x1="49" y1="0" x2="49" y2="50" stroke="#e2e8f0" stroke-width="2" stroke-dasharray="3,2"/>
254-
</svg>
229+
<div style="display: inline-block; margin-left: 7px; overflow: hidden;">
230+
<a href="https://particleanalyzer.ru" target="_blank">
231+
<img
232+
src="https://rybakov-k.ru/assets/icon/Logo2.png"
233+
alt="ParticleAnalyzer"
234+
style="max-height: 50px; width: auto; height: auto;"
235+
class="logo-image"
236+
>
237+
</a>
255238
</div>
256239
<p style="font-size:16px;line-height:1.6;margin-bottom:0;color:var(--text-color)">
257240
一款用于分析<strong style="color:var(--block-label-text-color)">颗粒尺寸特征</strong>的工具,
@@ -262,13 +245,12 @@
262245
<!-- 视频演示 -->
263246
<div style="background:var(--block-background-fill);padding:20px;border-radius:8px;margin-bottom:20px;border:1px solid var(--border-color-primary);box-shadow:var(--block-shadow);text-align:center">
264247
<h3 style="margin-top:0;color:var(--header-text-color);font-weight:600">🎥 视频演示</h3>
265-
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;margin-top:15px;border-radius:6px">
266-
<iframe src="https://www.youtube.com/embed/qlCuZDjDyqk"
267-
style="position:absolute;top:0;left:0;width:100%;height:100%;border:none"
268-
frameborder="0"
269-
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
270-
allowfullscreen>
271-
</iframe>
248+
<div style="margin-top:15px;">
249+
<a href="https://www.youtube.com/embed/qlCuZDjDyqk"
250+
style="color:var(--link-color);text-decoration:underline;font-size:16px;"
251+
target="_blank">
252+
影片示範連結
253+
</a>
272254
</div>
273255
<p style="font-size:14px;color:var(--text-color-secondary);margin-top:10px">
274256
观看颗粒分析器在实际案例中的应用
@@ -339,20 +321,15 @@
339321
border-bottom:1px solid var(--border-color-primary);
340322
box-shadow:var(--block-shadow)
341323
">
342-
<div style="display:flex;align-items:center;gap:15px;margin-bottom:15px;">
343-
<svg width="250" height="55" viewBox="0 0 250 55" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
344-
<image x="2" y="0" width="46" height="46" preserveAspectRatio="xMidYMid meet"
345-
xlink:href="https://svgsilh.com/svg/305079-2196f3.svg"/>
346-
<g font-family="'Segoe UI', 'Helvetica Neue', Arial, sans-serif" text-rendering="optimizeLegibility">
347-
<text x="55" y="25" font-size="22" font-weight="600" letter-spacing="-0.3">
348-
<tspan fill="#3b82f6">ParticleAnalyzer</tspan>
349-
</text>
350-
<text x="56" y="40" font-size="11" fill="#64748b" font-weight="500">
351-
SEM Image Analysis Tool
352-
</text>
353-
</g>
354-
<line x1="49" y1="0" x2="49" y2="50" stroke="#e2e8f0" stroke-width="2" stroke-dasharray="3,2"/>
355-
</svg>
324+
<div style="display: inline-block; margin-left: 7px; overflow: hidden;">
325+
<a href="https://particleanalyzer.ru" target="_blank">
326+
<img
327+
src="https://rybakov-k.ru/assets/icon/Logo2.png"
328+
alt="ParticleAnalyzer"
329+
style="max-height: 50px; width: auto; height: auto;"
330+
class="logo-image"
331+
>
332+
</a>
356333
</div>
357334
<p style="font-size:16px;line-height:1.6;margin-bottom:0;color:var(--text-color)">
358335
用於分析<strong style="color:var(--block-label-text-color)">粒子尺寸特徵</strong>的工具,
@@ -363,16 +340,15 @@
363340
<!-- 影片示範 -->
364341
<div style="background:var(--block-background-fill);padding:20px;border-radius:8px;margin-bottom:20px;border:1px solid var(--border-color-primary);box-shadow:var(--block-shadow);text-align:center">
365342
<h3 style="margin-top:0;color:var(--header-text-color);font-weight:600">🎥 影片示範</h3>
366-
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;margin-top:15px;border-radius:6px">
367-
<iframe src="https://www.youtube.com/embed/qlCuZDjDyqk"
368-
style="position:absolute;top:0;left:0;width:100%;height:100%;border:none"
369-
frameborder="0"
370-
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
371-
allowfullscreen>
372-
</iframe>
343+
<div style="margin-top:15px;">
344+
<a href="https://www.youtube.com/embed/qlCuZDjDyqk"
345+
style="color:var(--link-color);text-decoration:underline;font-size:16px;"
346+
target="_blank">
347+
影片示範連結
348+
</a>
373349
</div>
374350
<p style="font-size:14px;color:var(--text-color-secondary);margin-top:10px">
375-
觀看粒子分析器的實際操作範例
351+
影片示範連結
376352
</p>
377353
</div>
378354

0 commit comments

Comments
 (0)