streamlit-launcher 2.5.0__tar.gz → 2.5.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {streamlit_launcher-2.5.0/streamlit_launcher.egg-info → streamlit_launcher-2.5.2}/PKG-INFO +1 -1
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/setup.py +1 -1
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/streamlit_launcher/dashboard.py +512 -4
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2/streamlit_launcher.egg-info}/PKG-INFO +1 -1
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/LICENSE +0 -0
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/README.md +0 -0
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/license.txt +0 -0
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/setup.cfg +0 -0
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/streamlit_launcher/__init__.py +0 -0
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/streamlit_launcher/cli.py +0 -0
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/streamlit_launcher/gui.py +0 -0
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/streamlit_launcher.egg-info/SOURCES.txt +0 -0
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/streamlit_launcher.egg-info/dependency_links.txt +0 -0
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/streamlit_launcher.egg-info/entry_points.txt +0 -0
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/streamlit_launcher.egg-info/requires.txt +0 -0
- {streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/streamlit_launcher.egg-info/top_level.txt +0 -0
@@ -8,7 +8,7 @@ with open(os.path.join(here, 'README.md'), 'r', encoding='utf-8') as f:
|
|
8
8
|
|
9
9
|
setup(
|
10
10
|
name="streamlit_launcher",
|
11
|
-
version="2.5.
|
11
|
+
version="2.5.2",
|
12
12
|
author="Dwi Bakti N Dev",
|
13
13
|
author_email="dwibakti76@gmail.com",
|
14
14
|
description="Analisis Date Scient Simple and Instant Streamlit Launcher AI Complite analisis Model",
|
@@ -295,8 +295,9 @@ def create_all_visualizations(df):
|
|
295
295
|
chart_types = [
|
296
296
|
"📈 Grafik Garis (Line Chart)",
|
297
297
|
"📊 Grafik Batang (Bar Chart)",
|
298
|
-
"📋 Histogram Responsif Berwarna",
|
298
|
+
"📋 Histogram Responsif Berwarna",
|
299
299
|
"🔄 Diamond Chart",
|
300
|
+
"🛜 Network Diagram",
|
300
301
|
"🔵 Scatter Plot",
|
301
302
|
"🫧 Grafik Gelembung (Bubble Chart)",
|
302
303
|
"🎯 Grafik Gauge (Speedometer)",
|
@@ -330,8 +331,11 @@ def create_all_visualizations(df):
|
|
330
331
|
elif chart_type == "📊 Grafik Batang (Bar Chart)":
|
331
332
|
create_bar_chart(df, numeric_cols, non_numeric_cols)
|
332
333
|
|
333
|
-
elif chart_type == "📋 Histogram Responsif Berwarna":
|
334
|
-
create_responsive_histogram(df, numeric_cols)
|
334
|
+
elif chart_type == "📋 Histogram Responsif Berwarna":
|
335
|
+
create_responsive_histogram(df, numeric_cols)
|
336
|
+
|
337
|
+
elif chart_type == "🛜 Network Diagram":
|
338
|
+
create_network_diagram(df, numeric_cols, non_numeric_cols)
|
335
339
|
|
336
340
|
elif chart_type == "🔄 Diamond Chart":
|
337
341
|
create_diamond_chart(df, numeric_cols, non_numeric_cols)
|
@@ -2380,6 +2384,251 @@ def create_bar_chart(df, numeric_cols, non_numeric_cols):
|
|
2380
2384
|
✅ Aggregasi yang efisien
|
2381
2385
|
""")
|
2382
2386
|
|
2387
|
+
|
2388
|
+
def create_network_diagram(df, numeric_cols, non_numeric_cols):
|
2389
|
+
col1, col2, col3 = st.columns(3)
|
2390
|
+
|
2391
|
+
with col1:
|
2392
|
+
source_col = st.selectbox("Pilih kolom untuk sumber (Source)",
|
2393
|
+
non_numeric_cols if non_numeric_cols else df.columns.tolist(),
|
2394
|
+
key="network_source")
|
2395
|
+
with col2:
|
2396
|
+
target_col = st.selectbox("Pilih kolom untuk target (Target)",
|
2397
|
+
non_numeric_cols if non_numeric_cols else df.columns.tolist(),
|
2398
|
+
key="network_target")
|
2399
|
+
with col3:
|
2400
|
+
value_col = st.selectbox("Pilih kolom untuk nilai hubungan (Value)",
|
2401
|
+
numeric_cols,
|
2402
|
+
key="network_value")
|
2403
|
+
|
2404
|
+
# Optimasi: Pengaturan performa
|
2405
|
+
col4, col5 = st.columns(2)
|
2406
|
+
with col4:
|
2407
|
+
max_nodes = st.slider("Maksimum node ditampilkan",
|
2408
|
+
min_value=10, max_value=200, value=50, key="network_max_nodes")
|
2409
|
+
with col5:
|
2410
|
+
min_connections = st.slider("Minimum koneksi per node",
|
2411
|
+
min_value=1, max_value=10, value=2, key="network_min_conn")
|
2412
|
+
use_sampling = st.checkbox("Gunakan sampling untuk data besar", value=True, key="network_sampling")
|
2413
|
+
|
2414
|
+
if source_col and target_col and value_col:
|
2415
|
+
with st.spinner("Membangun diagram jaringan..."):
|
2416
|
+
# Optimasi 1: Sampling untuk data besar
|
2417
|
+
processed_df = df.copy()
|
2418
|
+
if use_sampling and len(df) > 5000:
|
2419
|
+
sample_size = min(5000, len(df))
|
2420
|
+
processed_df = df.sample(n=sample_size, random_state=42)
|
2421
|
+
st.info(f"📊 Data disampling: {sample_size:,} dari {len(df):,} records")
|
2422
|
+
|
2423
|
+
# Optimasi 2: Filter data berdasarkan threshold
|
2424
|
+
connection_counts = processed_df.groupby(source_col)[target_col].count()
|
2425
|
+
valid_sources = connection_counts[connection_counts >= min_connections].index
|
2426
|
+
|
2427
|
+
filtered_df = processed_df[processed_df[source_col].isin(valid_sources)]
|
2428
|
+
|
2429
|
+
# Batasi jumlah node unik
|
2430
|
+
top_sources = filtered_df[source_col].value_counts().head(max_nodes//2).index
|
2431
|
+
top_targets = filtered_df[target_col].value_counts().head(max_nodes//2).index
|
2432
|
+
|
2433
|
+
final_df = filtered_df[
|
2434
|
+
filtered_df[source_col].isin(top_sources) &
|
2435
|
+
filtered_df[target_col].isin(top_targets)
|
2436
|
+
]
|
2437
|
+
|
2438
|
+
if len(final_df) == 0:
|
2439
|
+
st.warning("Tidak ada data yang memenuhi kriteria filter. Coba kurangi minimum koneksi.")
|
2440
|
+
return
|
2441
|
+
|
2442
|
+
# Buat data nodes dan links
|
2443
|
+
@st.cache_data(ttl=300)
|
2444
|
+
def create_network_data(df, source_col, target_col, value_col):
|
2445
|
+
# Kumpulkan semua node unik
|
2446
|
+
sources = df[source_col].unique()
|
2447
|
+
targets = df[target_col].unique()
|
2448
|
+
all_nodes = list(set(list(sources) + list(targets)))
|
2449
|
+
|
2450
|
+
# Buat mapping node ke index
|
2451
|
+
node_dict = {node: i for i, node in enumerate(all_nodes)}
|
2452
|
+
|
2453
|
+
# Buat links
|
2454
|
+
links_df = df.groupby([source_col, target_col])[value_col].sum().reset_index()
|
2455
|
+
|
2456
|
+
links = []
|
2457
|
+
for _, row in links_df.iterrows():
|
2458
|
+
links.append({
|
2459
|
+
'source': node_dict[row[source_col]],
|
2460
|
+
'target': node_dict[row[target_col]],
|
2461
|
+
'value': row[value_col]
|
2462
|
+
})
|
2463
|
+
|
2464
|
+
# Buat nodes dengan properties
|
2465
|
+
node_degrees = {}
|
2466
|
+
node_values = {}
|
2467
|
+
|
2468
|
+
for link in links:
|
2469
|
+
node_degrees[link['source']] = node_degrees.get(link['source'], 0) + 1
|
2470
|
+
node_degrees[link['target']] = node_degrees.get(link['target'], 0) + 1
|
2471
|
+
node_values[link['source']] = node_values.get(link['source'], 0) + link['value']
|
2472
|
+
node_values[link['target']] = node_values.get(link['target'], 0) + link['value']
|
2473
|
+
|
2474
|
+
nodes = []
|
2475
|
+
for node_name, node_id in node_dict.items():
|
2476
|
+
nodes.append({
|
2477
|
+
'id': node_id,
|
2478
|
+
'name': str(node_name),
|
2479
|
+
'degree': node_degrees.get(node_id, 0),
|
2480
|
+
'value': node_values.get(node_id, 0),
|
2481
|
+
'group': 0 if node_id in [link['source'] for link in links] else 1
|
2482
|
+
})
|
2483
|
+
|
2484
|
+
return nodes, links
|
2485
|
+
|
2486
|
+
nodes, links = create_network_data(final_df, source_col, target_col, value_col)
|
2487
|
+
|
2488
|
+
# Optimasi 3: Cache figure creation
|
2489
|
+
@st.cache_data(ttl=300)
|
2490
|
+
def create_network_figure(nodes, links, title):
|
2491
|
+
# Buat graph dengan networkx untuk layout
|
2492
|
+
import networkx as nx
|
2493
|
+
|
2494
|
+
G = nx.Graph()
|
2495
|
+
|
2496
|
+
# Tambahkan nodes
|
2497
|
+
for node in nodes:
|
2498
|
+
G.add_node(node['id'], name=node['name'], degree=node['degree'], value=node['value'])
|
2499
|
+
|
2500
|
+
# Tambahkan edges
|
2501
|
+
for link in links:
|
2502
|
+
G.add_edge(link['source'], link['target'], weight=link['value'])
|
2503
|
+
|
2504
|
+
# Gunakan spring layout
|
2505
|
+
pos = nx.spring_layout(G, k=1, iterations=50)
|
2506
|
+
|
2507
|
+
# Siapkan data untuk plotly
|
2508
|
+
edge_x = []
|
2509
|
+
edge_y = []
|
2510
|
+
for link in links:
|
2511
|
+
x0, y0 = pos[link['source']]
|
2512
|
+
x1, y1 = pos[link['target']]
|
2513
|
+
edge_x.extend([x0, x1, None])
|
2514
|
+
edge_y.extend([y0, y1, None])
|
2515
|
+
|
2516
|
+
node_x = [pos[node['id']][0] for node in nodes]
|
2517
|
+
node_y = [pos[node['id']][1] for node in nodes]
|
2518
|
+
node_text = [f"{node['name']}<br>Connections: {node['degree']}<br>Value: {node['value']:.2f}"
|
2519
|
+
for node in nodes]
|
2520
|
+
node_size = [max(10, min(50, node['degree'] * 5)) for node in nodes]
|
2521
|
+
node_color = [node['value'] for node in nodes]
|
2522
|
+
|
2523
|
+
# Buat figure
|
2524
|
+
fig = go.Figure()
|
2525
|
+
|
2526
|
+
# Tambahkan edges
|
2527
|
+
fig.add_trace(go.Scatter(
|
2528
|
+
x=edge_x, y=edge_y,
|
2529
|
+
line=dict(width=0.5, color='#888'),
|
2530
|
+
hoverinfo='none',
|
2531
|
+
mode='lines',
|
2532
|
+
showlegend=False
|
2533
|
+
))
|
2534
|
+
|
2535
|
+
# Tambahkan nodes
|
2536
|
+
fig.add_trace(go.Scatter(
|
2537
|
+
x=node_x, y=node_y,
|
2538
|
+
mode='markers',
|
2539
|
+
hoverinfo='text',
|
2540
|
+
text=node_text,
|
2541
|
+
marker=dict(
|
2542
|
+
size=node_size,
|
2543
|
+
color=node_color,
|
2544
|
+
colorscale='Viridis',
|
2545
|
+
line=dict(width=2, color='darkblue')
|
2546
|
+
),
|
2547
|
+
showlegend=False
|
2548
|
+
))
|
2549
|
+
|
2550
|
+
# Update layout
|
2551
|
+
fig.update_layout(
|
2552
|
+
title=title,
|
2553
|
+
title_x=0.5,
|
2554
|
+
height=600,
|
2555
|
+
showlegend=False,
|
2556
|
+
margin=dict(l=50, r=50, t=60, b=50),
|
2557
|
+
hovermode='closest',
|
2558
|
+
plot_bgcolor='rgba(0,0,0,0)',
|
2559
|
+
xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
|
2560
|
+
yaxis=dict(showgrid=False, zeroline=False, showticklabels=False)
|
2561
|
+
)
|
2562
|
+
|
2563
|
+
return fig
|
2564
|
+
|
2565
|
+
title = f"Diagram Jaringan: {source_col} → {target_col} (Nilai: {value_col})"
|
2566
|
+
fig = create_network_figure(nodes, links, title)
|
2567
|
+
|
2568
|
+
# Optimasi 4: Plotly config yang ringan
|
2569
|
+
config = {
|
2570
|
+
'displayModeBar': True,
|
2571
|
+
'displaylogo': False,
|
2572
|
+
'modeBarButtonsToRemove': ['lasso2d', 'select2d', 'autoScale2d'],
|
2573
|
+
'responsive': True
|
2574
|
+
}
|
2575
|
+
|
2576
|
+
st.plotly_chart(fig, use_container_width=True, config=config)
|
2577
|
+
|
2578
|
+
# Tampilkan data summary
|
2579
|
+
with st.expander("📊 Lihat Data Jaringan"):
|
2580
|
+
col1, col2, col3 = st.columns(3)
|
2581
|
+
with col1:
|
2582
|
+
st.metric("Total Node", len(nodes))
|
2583
|
+
with col2:
|
2584
|
+
st.metric("Total Koneksi", len(links))
|
2585
|
+
with col3:
|
2586
|
+
avg_degree = sum(node['degree'] for node in nodes) / len(nodes) if nodes else 0
|
2587
|
+
st.metric("Rata-rata Koneksi", f"{avg_degree:.1f}")
|
2588
|
+
|
2589
|
+
# Tampilkan node dengan koneksi terbanyak
|
2590
|
+
top_nodes = sorted(nodes, key=lambda x: x['degree'], reverse=True)[:10]
|
2591
|
+
node_data = []
|
2592
|
+
for node in top_nodes:
|
2593
|
+
node_data.append({
|
2594
|
+
'Node': node['name'],
|
2595
|
+
'Koneksi': node['degree'],
|
2596
|
+
'Total Nilai': node['value']
|
2597
|
+
})
|
2598
|
+
|
2599
|
+
st.subheader("Node dengan Koneksi Terbanyak")
|
2600
|
+
st.dataframe(node_data, use_container_width=True)
|
2601
|
+
|
2602
|
+
with st.expander("ℹ️ Keterangan Diagram Jaringan"):
|
2603
|
+
st.markdown(f"""
|
2604
|
+
**Diagram Jaringan (Network Diagram)** digunakan untuk memvisualisasikan hubungan dan koneksi antar entitas.
|
2605
|
+
|
2606
|
+
**Statistik Jaringan:**
|
2607
|
+
- Total node: **{len(nodes)}**
|
2608
|
+
- Total koneksi: **{len(links)}**
|
2609
|
+
- Rata-rata koneksi per node: **{avg_degree:.1f}**
|
2610
|
+
- Node dengan koneksi terbanyak: **{top_nodes[0]['name'] if top_nodes else 'N/A'}** ({top_nodes[0]['degree'] if top_nodes else 0} koneksi)
|
2611
|
+
|
2612
|
+
**Kelebihan**:
|
2613
|
+
- Menunjukkan hubungan kompleks antar entitas
|
2614
|
+
- Mengidentifikasi node penting (highly connected)
|
2615
|
+
- Visualisasi pola koneksi dan cluster
|
2616
|
+
|
2617
|
+
**Kekurangan**:
|
2618
|
+
- Dapat menjadi berantakan dengan banyak node
|
2619
|
+
- Membutuhkan pemrosesan yang intensif
|
2620
|
+
- Interpretasi bisa kompleks
|
2621
|
+
|
2622
|
+
**Penggunaan**: Analisis jaringan sosial, hubungan bisnis, dependencies sistem
|
2623
|
+
|
2624
|
+
**Optimasi yang diterapkan:**
|
2625
|
+
✅ Sampling otomatis untuk data besar
|
2626
|
+
✅ Filter node berdasarkan minimum koneksi
|
2627
|
+
✅ Batasan jumlah node maksimum
|
2628
|
+
✅ Caching untuk performa
|
2629
|
+
✅ Layout algoritma yang efisien
|
2630
|
+
""")
|
2631
|
+
|
2383
2632
|
# Alternatif: Versi ultra-ringan untuk data sangat besar
|
2384
2633
|
def create_bar_chart_lightweight(df, numeric_cols, non_numeric_cols):
|
2385
2634
|
"""Versi yang lebih ringan untuk dataset sangat besar"""
|
@@ -5748,6 +5997,239 @@ def create_map_chart(df):
|
|
5748
5997
|
- Kolom longitude (contoh: lon, long, longitude)
|
5749
5998
|
- Opsional: Kolom nama lokasi (country, state, city, region, etc.)
|
5750
5999
|
""")
|
6000
|
+
|
6001
|
+
|
6002
|
+
def create_choropleth_map(df, numeric_cols, non_numeric_cols):
|
6003
|
+
col1, col2 = st.columns(2)
|
6004
|
+
|
6005
|
+
with col1:
|
6006
|
+
location_col = st.selectbox("Pilih kolom untuk lokasi",
|
6007
|
+
non_numeric_cols,
|
6008
|
+
key="choropleth_location")
|
6009
|
+
with col2:
|
6010
|
+
value_col = st.selectbox("Pilih kolom untuk nilai",
|
6011
|
+
numeric_cols,
|
6012
|
+
key="choropleth_value")
|
6013
|
+
|
6014
|
+
# Pilihan tipe peta
|
6015
|
+
map_type = st.selectbox("Pilih tipe peta",
|
6016
|
+
["World Countries", "Indonesia Provinces", "USA States", "Custom GeoJSON"],
|
6017
|
+
key="choropleth_maptype")
|
6018
|
+
|
6019
|
+
# Optimasi: Pengaturan performa
|
6020
|
+
col3, col4 = st.columns(2)
|
6021
|
+
with col3:
|
6022
|
+
use_sampling = st.checkbox("Gunakan sampling untuk data besar", value=True, key="choropleth_sampling")
|
6023
|
+
with col4:
|
6024
|
+
animation_col = st.selectbox("Kolom animasi (opsional)",
|
6025
|
+
[""] + non_numeric_cols,
|
6026
|
+
key="choropleth_animation")
|
6027
|
+
|
6028
|
+
if location_col and value_col:
|
6029
|
+
with st.spinner("Membuat peta choropleth..."):
|
6030
|
+
# Optimasi 1: Sampling untuk data besar
|
6031
|
+
processed_df = df.copy()
|
6032
|
+
if use_sampling and len(df) > 10000:
|
6033
|
+
sample_size = min(10000, len(df))
|
6034
|
+
processed_df = df.sample(n=sample_size, random_state=42)
|
6035
|
+
st.info(f"📊 Data disampling: {sample_size:,} dari {len(df):,} records")
|
6036
|
+
|
6037
|
+
# Aggregasi data berdasarkan lokasi
|
6038
|
+
if animation_col:
|
6039
|
+
# Jika menggunakan animasi, group by location dan animation column
|
6040
|
+
map_data = (processed_df.groupby([location_col, animation_col])[value_col]
|
6041
|
+
.mean()
|
6042
|
+
.reset_index())
|
6043
|
+
else:
|
6044
|
+
# Jika tidak menggunakan animasi, group by location saja
|
6045
|
+
map_data = (processed_df.groupby(location_col)[value_col]
|
6046
|
+
.agg(['mean', 'count', 'std'])
|
6047
|
+
.round(2)
|
6048
|
+
.reset_index())
|
6049
|
+
map_data.columns = [location_col, value_col, 'count', 'std']
|
6050
|
+
|
6051
|
+
# Optimasi 2: Cache figure creation
|
6052
|
+
@st.cache_data(ttl=300)
|
6053
|
+
def create_choropleth_figure(data, location_col, value_col, map_type, animation_col=None):
|
6054
|
+
fig = px.choropleth(
|
6055
|
+
data,
|
6056
|
+
locations=location_col,
|
6057
|
+
locationmode='country names' if map_type == "World Countries" else None,
|
6058
|
+
color=value_col,
|
6059
|
+
hover_name=location_col,
|
6060
|
+
hover_data={
|
6061
|
+
value_col: ':.2f',
|
6062
|
+
'count': True,
|
6063
|
+
'std': ':.2f'
|
6064
|
+
} if not animation_col else {value_col: ':.2f'},
|
6065
|
+
animation_frame=animation_col if animation_col else None,
|
6066
|
+
color_continuous_scale="Viridis",
|
6067
|
+
title=f"Peta Choropleth: {value_col} per {location_col}",
|
6068
|
+
height=600
|
6069
|
+
)
|
6070
|
+
|
6071
|
+
# Update layout untuk tampilan yang lebih baik
|
6072
|
+
fig.update_layout(
|
6073
|
+
margin=dict(l=50, r=50, t=60, b=50),
|
6074
|
+
geo=dict(
|
6075
|
+
showframe=False,
|
6076
|
+
showcoastlines=True,
|
6077
|
+
projection_type='equirectangular'
|
6078
|
+
),
|
6079
|
+
coloraxis_colorbar=dict(
|
6080
|
+
title=value_col,
|
6081
|
+
thickness=20,
|
6082
|
+
len=0.75
|
6083
|
+
)
|
6084
|
+
)
|
6085
|
+
|
6086
|
+
return fig
|
6087
|
+
|
6088
|
+
# Handle different map types
|
6089
|
+
if map_type == "World Countries":
|
6090
|
+
# Untuk peta dunia, asumsikan location_col berisi nama negara
|
6091
|
+
fig = create_choropleth_figure(
|
6092
|
+
map_data, location_col, value_col, map_type, animation_col if animation_col != "" else None
|
6093
|
+
)
|
6094
|
+
|
6095
|
+
elif map_type == "Indonesia Provinces":
|
6096
|
+
# Custom untuk provinsi Indonesia
|
6097
|
+
indonesia_provinces = {
|
6098
|
+
'Aceh': 'ID-AC', 'Bali': 'ID-BA', 'Banten': 'ID-BT', 'Bengkulu': 'ID-BE',
|
6099
|
+
'Gorontalo': 'ID-GO', 'Jakarta': 'ID-JK', 'Jambi': 'ID-JA', 'Jawa Barat': 'ID-JB',
|
6100
|
+
'Jawa Tengah': 'ID-JT', 'Jawa Timur': 'ID-JI', 'Kalimantan Barat': 'ID-KB',
|
6101
|
+
'Kalimantan Selatan': 'ID-KS', 'Kalimantan Tengah': 'ID-KT', 'Kalimantan Timur': 'ID-KI',
|
6102
|
+
'Kalimantan Utara': 'ID-KU', 'Kepulauan Bangka Belitung': 'ID-BB',
|
6103
|
+
'Kepulauan Riau': 'ID-KR', 'Lampung': 'ID-LA', 'Maluku': 'ID-MA',
|
6104
|
+
'Maluku Utara': 'ID-MU', 'Nusa Tenggara Barat': 'ID-NB',
|
6105
|
+
'Nusa Tenggara Timur': 'ID-NT', 'Papua': 'ID-PA', 'Papua Barat': 'ID-PB',
|
6106
|
+
'Riau': 'ID-RI', 'Sulawesi Barat': 'ID-SR', 'Sulawesi Selatan': 'ID-SN',
|
6107
|
+
'Sulawesi Tengah': 'ID-ST', 'Sulawesi Tenggara': 'ID-SG', 'Sulawesi Utara': 'ID-SA',
|
6108
|
+
'Sumatera Barat': 'ID-SB', 'Sumatera Selatan': 'ID-SS', 'Sumatera Utara': 'ID-SU',
|
6109
|
+
'Yogyakarta': 'ID-YO'
|
6110
|
+
}
|
6111
|
+
|
6112
|
+
# Map province names to codes
|
6113
|
+
map_data['province_code'] = map_data[location_col].map(indonesia_provinces)
|
6114
|
+
|
6115
|
+
fig = px.choropleth(
|
6116
|
+
map_data,
|
6117
|
+
geojson="https://raw.githubusercontent.com/superpikar/indonesia-geojson/master/indonesia.geojson",
|
6118
|
+
locations='province_code',
|
6119
|
+
color=value_col,
|
6120
|
+
hover_name=location_col,
|
6121
|
+
hover_data={value_col: ':.2f', 'count': True} if not animation_col else {value_col: ':.2f'},
|
6122
|
+
animation_frame=animation_col if animation_col else None,
|
6123
|
+
color_continuous_scale="Blues",
|
6124
|
+
title=f"Peta Indonesia: {value_col} per Provinsi",
|
6125
|
+
height=600
|
6126
|
+
)
|
6127
|
+
|
6128
|
+
fig.update_geos(fitbounds="locations", visible=False)
|
6129
|
+
|
6130
|
+
elif map_type == "USA States":
|
6131
|
+
# Untuk peta USA states
|
6132
|
+
fig = px.choropleth(
|
6133
|
+
map_data,
|
6134
|
+
locations=location_col,
|
6135
|
+
locationmode="USA-states",
|
6136
|
+
color=value_col,
|
6137
|
+
scope="usa",
|
6138
|
+
hover_name=location_col,
|
6139
|
+
hover_data={value_col: ':.2f', 'count': True} if not animation_col else {value_col: ':.2f'},
|
6140
|
+
animation_frame=animation_col if animation_col else None,
|
6141
|
+
color_continuous_scale="Reds",
|
6142
|
+
title=f"Peta USA: {value_col} per State",
|
6143
|
+
height=600
|
6144
|
+
)
|
6145
|
+
|
6146
|
+
else: # Custom GeoJSON
|
6147
|
+
st.info("Untuk Custom GeoJSON, silakan upload file GeoJSON Anda")
|
6148
|
+
uploaded_geojson = st.file_uploader("Upload GeoJSON file", type=['json', 'geojson'])
|
6149
|
+
|
6150
|
+
if uploaded_geojson:
|
6151
|
+
import json
|
6152
|
+
geojson_data = json.load(uploaded_geojson)
|
6153
|
+
|
6154
|
+
fig = px.choropleth(
|
6155
|
+
map_data,
|
6156
|
+
geojson=geojson_data,
|
6157
|
+
locations=location_col,
|
6158
|
+
color=value_col,
|
6159
|
+
hover_name=location_col,
|
6160
|
+
hover_data={value_col: ':.2f', 'count': True} if not animation_col else {value_col: ':.2f'},
|
6161
|
+
animation_frame=animation_col if animation_col else None,
|
6162
|
+
color_continuous_scale="Greens",
|
6163
|
+
title=f"Peta Kustom: {value_col} per {location_col}",
|
6164
|
+
height=600
|
6165
|
+
)
|
6166
|
+
|
6167
|
+
fig.update_geos(fitbounds="locations", visible=False)
|
6168
|
+
else:
|
6169
|
+
st.warning("Silakan upload file GeoJSON untuk melanjutkan")
|
6170
|
+
return
|
6171
|
+
|
6172
|
+
# Optimasi 3: Plotly config yang ringan
|
6173
|
+
config = {
|
6174
|
+
'displayModeBar': True,
|
6175
|
+
'displaylogo': False,
|
6176
|
+
'modeBarButtonsToRemove': ['lasso2d', 'select2d', 'autoScale2d'],
|
6177
|
+
'responsive': True
|
6178
|
+
}
|
6179
|
+
|
6180
|
+
st.plotly_chart(fig, use_container_width=True, config=config)
|
6181
|
+
|
6182
|
+
# Tampilkan data summary
|
6183
|
+
with st.expander("📊 Lihat Data Peta"):
|
6184
|
+
col1, col2, col3 = st.columns(3)
|
6185
|
+
with col1:
|
6186
|
+
st.metric("Total Lokasi", len(map_data))
|
6187
|
+
with col2:
|
6188
|
+
st.metric(f"Rata-rata {value_col}", f"{map_data[value_col].mean():.2f}")
|
6189
|
+
with col3:
|
6190
|
+
max_loc = map_data.loc[map_data[value_col].idxmax()][location_col]
|
6191
|
+
st.metric("Lokasi Tertinggi", str(max_loc)[:20] + "...")
|
6192
|
+
|
6193
|
+
# Tampilkan data teratas
|
6194
|
+
st.subheader("Data per Lokasi")
|
6195
|
+
display_data = map_data.sort_values(value_col, ascending=False).head(10)
|
6196
|
+
st.dataframe(display_data.style.format({value_col: "{:.2f}"}), use_container_width=True)
|
6197
|
+
|
6198
|
+
with st.expander("ℹ️ Keterangan Peta Choropleth"):
|
6199
|
+
st.markdown(f"""
|
6200
|
+
**Peta Choropleth** digunakan untuk memvisualisasikan data geografis dengan variasi warna.
|
6201
|
+
|
6202
|
+
**Statistik Data:**
|
6203
|
+
- Total lokasi: **{len(map_data)}**
|
6204
|
+
- Rentang nilai: **{map_data[value_col].min():.2f}** hingga **{map_data[value_col].max():.2f}**
|
6205
|
+
- Standar deviasi: **{map_data[value_col].std():.2f if 'std' in map_data.columns else 'N/A'}**
|
6206
|
+
|
6207
|
+
**Kelebihan**:
|
6208
|
+
- Visualisasi spasial yang intuitif
|
6209
|
+
- Mudah mengidentifikasi pola geografis
|
6210
|
+
- Efektif untuk data regional/geografis
|
6211
|
+
|
6212
|
+
**Kekurangan**:
|
6213
|
+
- Membutuhkan data lokasi yang akurat
|
6214
|
+
- Dapat misleading jika tidak dinormalisasi
|
6215
|
+
- Terbatas pada wilayah yang tersedia di GeoJSON
|
6216
|
+
|
6217
|
+
**Penggunaan**: Analisis regional, data demografis, distribusi geografis
|
6218
|
+
|
6219
|
+
**Tips Interpretasi:**
|
6220
|
+
- Area dengan warna lebih gelap menunjukkan nilai lebih tinggi
|
6221
|
+
- Perhatikan skala warna untuk interpretasi yang tepat
|
6222
|
+
- Gunakan hover untuk melihat nilai detail
|
6223
|
+
|
6224
|
+
**Optimasi yang diterapkan:**
|
6225
|
+
✅ Sampling otomatis untuk data besar
|
6226
|
+
✅ Aggregasi data yang efisien
|
6227
|
+
✅ Caching untuk performa
|
6228
|
+
✅ Multiple map types support
|
6229
|
+
✅ Animasi timeline (opsional)
|
6230
|
+
""")
|
6231
|
+
|
6232
|
+
|
5751
6233
|
|
5752
6234
|
def create_flow_map(df):
|
5753
6235
|
|
@@ -9924,7 +10406,33 @@ if df is not None:
|
|
9924
10406
|
# Clean up temporary file
|
9925
10407
|
os.unlink(tmp_file.name)
|
9926
10408
|
|
9927
|
-
st.
|
10409
|
+
with st.status("Model 3D Running...", expanded=True) as status:
|
10410
|
+
st.write("✅ Converting Model 3D...")
|
10411
|
+
time.sleep(2)
|
10412
|
+
st.write("✅ Data Mining 3D...")
|
10413
|
+
time.sleep(1)
|
10414
|
+
st.write("✅ Data mining Converting 3D...")
|
10415
|
+
time.sleep(1)
|
10416
|
+
st.write("✅ Model 3D tipe: STL...")
|
10417
|
+
time.sleep(1)
|
10418
|
+
st.write("✅ Resolusi...")
|
10419
|
+
time.sleep(1)
|
10420
|
+
st.write("✅ Dimensi Mesh...")
|
10421
|
+
time.sleep(1)
|
10422
|
+
st.write("✅ Skala Tinggi...")
|
10423
|
+
time.sleep(1)
|
10424
|
+
st.write("✅ Model Sasha AI...")
|
10425
|
+
time.sleep(1)
|
10426
|
+
st.write("✅ Model Alisa AI...")
|
10427
|
+
time.sleep(1)
|
10428
|
+
st.write("✅ Model dwibaktindev AI...")
|
10429
|
+
time.sleep(1)
|
10430
|
+
|
10431
|
+
status.update(
|
10432
|
+
label="✅ Model 3D Converted!",
|
10433
|
+
state="complete",
|
10434
|
+
expanded=False
|
10435
|
+
)
|
9928
10436
|
|
9929
10437
|
# Display results
|
9930
10438
|
st.info(f"**Model 3D tipe:** {conversion_type}")
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/streamlit_launcher.egg-info/SOURCES.txt
RENAMED
File without changes
|
File without changes
|
{streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/streamlit_launcher.egg-info/entry_points.txt
RENAMED
File without changes
|
{streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/streamlit_launcher.egg-info/requires.txt
RENAMED
File without changes
|
{streamlit_launcher-2.5.0 → streamlit_launcher-2.5.2}/streamlit_launcher.egg-info/top_level.txt
RENAMED
File without changes
|