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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamlit_launcher
3
- Version: 2.5.0
3
+ Version: 2.5.2
4
4
  Summary: Analisis Date Scient Simple and Instant Streamlit Launcher AI Complite analisis Model
5
5
  Home-page: https://github.com/royhtml
6
6
  Author: Dwi Bakti N Dev
@@ -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.0",
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", # DIUBAH NAMA DI SINI
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": # DIUBAH DI SINI
334
- create_responsive_histogram(df, numeric_cols) # PASTIKAN NAMA FUNGSI SESUAI
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.success("Model 3D berhasil dibuat!")
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}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamlit_launcher
3
- Version: 2.5.0
3
+ Version: 2.5.2
4
4
  Summary: Analisis Date Scient Simple and Instant Streamlit Launcher AI Complite analisis Model
5
5
  Home-page: https://github.com/royhtml
6
6
  Author: Dwi Bakti N Dev