Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1441,7 +1441,7 @@ setTimeout(() => {
|
|
| 1441 |
""", unsafe_allow_html=True)
|
| 1442 |
|
| 1443 |
#bloob line
|
| 1444 |
-
def
|
| 1445 |
if not data or len(data) == 0:
|
| 1446 |
return "<span class='spark' style='color:#999;'>—</span>"
|
| 1447 |
|
|
@@ -1449,9 +1449,29 @@ def ascii_sparkline_pln(data):
|
|
| 1449 |
data = [float(x) for x in data]
|
| 1450 |
n = len(data)
|
| 1451 |
if n == 1:
|
| 1452 |
-
return "<span class='spark' style='color:#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1453 |
|
| 1454 |
-
# Normalisasi ke [
|
| 1455 |
min_y, max_y = min(data), max(data)
|
| 1456 |
height = 16
|
| 1457 |
margin = 2
|
|
@@ -1465,16 +1485,20 @@ def ascii_sparkline_pln(data):
|
|
| 1465 |
for v in data
|
| 1466 |
]
|
| 1467 |
|
| 1468 |
-
#
|
| 1469 |
points = " ".join(f"{i * 8},{y:.1f}" for i, y in enumerate(y_coords))
|
| 1470 |
width = max(24, (n - 1) * 8 + 4)
|
| 1471 |
|
|
|
|
| 1472 |
svg = (
|
| 1473 |
-
f'<svg class="sparkline" width="{width}" height="{height}" '
|
| 1474 |
-
f'viewBox="-2 0 {width} {height}" style="vertical-align:middle" '
|
| 1475 |
f'xmlns="http://www.w3.org/2000/svg">'
|
| 1476 |
-
f'<polyline points="{points}" fill="none" stroke="
|
| 1477 |
-
f'stroke-width="1.
|
|
|
|
|
|
|
|
|
|
| 1478 |
f'</svg>'
|
| 1479 |
)
|
| 1480 |
return svg
|
|
|
|
| 1441 |
""", unsafe_allow_html=True)
|
| 1442 |
|
| 1443 |
#bloob line
|
| 1444 |
+
def sparkline_trend_pln(data):
|
| 1445 |
if not data or len(data) == 0:
|
| 1446 |
return "<span class='spark' style='color:#999;'>—</span>"
|
| 1447 |
|
|
|
|
| 1449 |
data = [float(x) for x in data]
|
| 1450 |
n = len(data)
|
| 1451 |
if n == 1:
|
| 1452 |
+
return "<span class='spark' style='color:#666;'>•</span>"
|
| 1453 |
+
|
| 1454 |
+
# Hitung slope linear (regresi sederhana: y = a + b*x)
|
| 1455 |
+
# b = slope → menentukan warna
|
| 1456 |
+
xs = list(range(n))
|
| 1457 |
+
x_mean = sum(xs) / n
|
| 1458 |
+
y_mean = sum(data) / n
|
| 1459 |
+
numerator = sum((x - x_mean) * (y - y_mean) for x, y in zip(xs, data))
|
| 1460 |
+
denominator = sum((x - x_mean) ** 2 for x in xs)
|
| 1461 |
+
slope = numerator / (denominator + 1e-12) # hindari div-0
|
| 1462 |
+
|
| 1463 |
+
# Tentukan warna berdasarkan slope
|
| 1464 |
+
if slope > 0.001:
|
| 1465 |
+
color = "#2E7D32" # Hijau gelap (material green 800) — improvement
|
| 1466 |
+
label = "↑"
|
| 1467 |
+
elif slope < -0.001:
|
| 1468 |
+
color = "#C62828" # Merah gelap (material red 800) — worsening
|
| 1469 |
+
label = "↓"
|
| 1470 |
+
else:
|
| 1471 |
+
color = "#546E7A" # Abu-abu biru (material blue-gray 600) — flat
|
| 1472 |
+
label = "→"
|
| 1473 |
|
| 1474 |
+
# Normalisasi y ke [margin, height-margin]
|
| 1475 |
min_y, max_y = min(data), max(data)
|
| 1476 |
height = 16
|
| 1477 |
margin = 2
|
|
|
|
| 1485 |
for v in data
|
| 1486 |
]
|
| 1487 |
|
| 1488 |
+
# Koordinat polyline (jarak horizontal: 8px per titik)
|
| 1489 |
points = " ".join(f"{i * 8},{y:.1f}" for i, y in enumerate(y_coords))
|
| 1490 |
width = max(24, (n - 1) * 8 + 4)
|
| 1491 |
|
| 1492 |
+
# SVG dengan garis + panah kecil di akhir (opsional)
|
| 1493 |
svg = (
|
| 1494 |
+
f'<svg class="sparkline" width="{width + 6}" height="{height}" '
|
| 1495 |
+
f'viewBox="-2 0 {width + 6} {height}" style="vertical-align:middle" '
|
| 1496 |
f'xmlns="http://www.w3.org/2000/svg">'
|
| 1497 |
+
f'<polyline points="{points}" fill="none" stroke="{color}" '
|
| 1498 |
+
f'stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>'
|
| 1499 |
+
# Opsional: panah kecil di ujung (hanya jika cukup lebar)
|
| 1500 |
+
f'<text x="{(n-1)*8 + 2}" y="14" font-size="10" fill="{color}" '
|
| 1501 |
+
f'dominant-baseline="middle">{label}</text>'
|
| 1502 |
f'</svg>'
|
| 1503 |
)
|
| 1504 |
return svg
|