kececilayout 0.5.8__py3-none-any.whl → 0.6.0__py3-none-any.whl

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.
@@ -21,6 +21,8 @@ layouts = ['2d', 'cylindrical', 'cubic', 'spherical', 'elliptical', 'toric']
21
21
  styles = ['standard', 'default', 'curved', 'helix', '3d', 'weighted', 'colored']
22
22
 
23
23
  **v0.5.1:** edge (kececi_layout_edge)
24
+
25
+ **v0.6.0:** periodic table
24
26
  """
25
27
 
26
28
  from collections import defaultdict
@@ -29,6 +31,7 @@ import igraph as ig
29
31
  import itertools # Graphillion için eklendi
30
32
  import math
31
33
  import matplotlib.pyplot as plt
34
+ from matplotlib.colors import hsv_to_rgb
32
35
  from mpl_toolkits.mplot3d import Axes3D
33
36
  import networkit as nk
34
37
  import networkx as nx
@@ -2085,6 +2088,148 @@ def kececi_layout_toric(
2085
2088
  return pos_3d
2086
2089
 
2087
2090
  # Ağırlıklı Çizim (draw_kececi_weighted)
2091
+ def draw_kececi_weighted(
2092
+ nx_graph: nx.Graph,
2093
+ pos: Dict[int, Tuple[float, ...]],
2094
+ ax: Optional[plt.Axes] = None,
2095
+ node_size: int = 300,
2096
+ edge_width_scale: float = 2.0,
2097
+ with_labels: bool = True,
2098
+ font_weight: str = 'bold',
2099
+ **kwargs
2100
+ ) -> plt.Axes:
2101
+ """
2102
+ 2D/3D Weighted edges ile Keçeci layout çizimi.
2103
+ """
2104
+ if ax is None:
2105
+ # 2D mi 3D mi kontrol et
2106
+ is_3d = len(pos[next(iter(pos))]) == 3
2107
+ fig = plt.figure(figsize=(10, 8))
2108
+ if is_3d:
2109
+ ax = fig.add_subplot(111, projection='3d')
2110
+ else:
2111
+ ax = fig.add_subplot(111)
2112
+
2113
+ # Node'ları çiz
2114
+ node_color = kwargs.get('node_color', 'lightblue')
2115
+ nx.draw_networkx_nodes(nx_graph, pos, ax=ax, node_size=node_size,
2116
+ node_color=node_color, **kwargs)
2117
+
2118
+ # Etiketleri çiz
2119
+ if with_labels:
2120
+ is_3d = len(pos[next(iter(pos))]) == 3
2121
+ if is_3d:
2122
+ # 3D için özel etiket çizimi
2123
+ for node, coord in pos.items():
2124
+ ax.text(coord[0], coord[1], coord[2], # 3D koordinatlar
2125
+ str(node), # 's' parametresi - etiket metni
2126
+ size=10,
2127
+ zorder=1,
2128
+ color='black',
2129
+ fontweight=font_weight)
2130
+ else:
2131
+ # 2D için NetworkX etiket çizimi
2132
+ nx.draw_networkx_labels(nx_graph, pos, ax=ax, font_weight=font_weight)
2133
+
2134
+ # Edge'leri çiz (weight'e göre)
2135
+ weights = nx.get_edge_attributes(nx_graph, 'weight')
2136
+ if not weights:
2137
+ weights = {edge: 1.0 for edge in nx_graph.edges()}
2138
+
2139
+ is_3d = len(pos[next(iter(pos))]) == 3
2140
+ for (u, v), weight in weights.items():
2141
+ width = weight * edge_width_scale
2142
+ if is_3d:
2143
+ # 3D edge çizimi
2144
+ ax.plot(
2145
+ [pos[u][0], pos[v][0]],
2146
+ [pos[u][1], pos[v][1]],
2147
+ [pos[u][2], pos[v][2]],
2148
+ linewidth=width,
2149
+ color='gray',
2150
+ alpha=0.7
2151
+ )
2152
+ else:
2153
+ # 2D edge çizimi
2154
+ ax.plot(
2155
+ [pos[u][0], pos[v][0]],
2156
+ [pos[u][1], pos[v][1]],
2157
+ linewidth=width,
2158
+ color='gray',
2159
+ alpha=0.7
2160
+ )
2161
+
2162
+ ax.set_title("Keçeci Layout: Weighted Edges")
2163
+ return ax
2164
+
2165
+ def draw_kececi_colored(
2166
+ nx_graph: nx.Graph,
2167
+ pos: Dict[int, Tuple[float, ...]],
2168
+ ax: Optional[plt.Axes] = None,
2169
+ node_size: int = 300,
2170
+ with_labels: bool = True,
2171
+ font_weight: str = 'bold',
2172
+ **kwargs
2173
+ ) -> plt.Axes:
2174
+ """
2175
+ 2D/3D Renkli node'lar ile Keçeci layout çizimi.
2176
+ """
2177
+ if ax is None:
2178
+ # 2D mi 3D mi kontrol et
2179
+ is_3d = len(pos[next(iter(pos))]) == 3
2180
+ fig = plt.figure(figsize=(10, 8))
2181
+ if is_3d:
2182
+ ax = fig.add_subplot(111, projection='3d')
2183
+ else:
2184
+ ax = fig.add_subplot(111)
2185
+
2186
+ # Dereceye göre renk hesapla
2187
+ degrees = dict(nx_graph.degree())
2188
+ max_degree = max(degrees.values()) if degrees else 1
2189
+ node_colors = [plt.cm.viridis(deg / max_degree) for deg in degrees.values()]
2190
+
2191
+ # Node'ları çiz
2192
+ nx.draw_networkx_nodes(
2193
+ nx_graph, pos, ax=ax,
2194
+ node_color=node_colors,
2195
+ node_size=node_size,
2196
+ **kwargs
2197
+ )
2198
+
2199
+ # Etiketleri çiz
2200
+ if with_labels:
2201
+ is_3d = len(pos[next(iter(pos))]) == 3
2202
+ if is_3d:
2203
+ # 3D için özel etiket çizimi
2204
+ for node, coord in pos.items():
2205
+ ax.text(coord[0], coord[1], coord[2], # 3D koordinatlar
2206
+ str(node), # 's' parametresi - etiket metni
2207
+ size=10,
2208
+ zorder=1,
2209
+ color='black',
2210
+ fontweight=font_weight)
2211
+ else:
2212
+ # 2D için NetworkX etiket çizimi
2213
+ nx.draw_networkx_labels(nx_graph, pos, ax=ax, font_weight=font_weight)
2214
+
2215
+ # Edge'leri çiz
2216
+ is_3d = len(pos[next(iter(pos))]) == 3
2217
+ if is_3d:
2218
+ for u, v in nx_graph.edges():
2219
+ ax.plot(
2220
+ [pos[u][0], pos[v][0]],
2221
+ [pos[u][1], pos[v][1]],
2222
+ [pos[u][2], pos[v][2]],
2223
+ color='gray',
2224
+ alpha=0.5
2225
+ )
2226
+ else:
2227
+ nx.draw_networkx_edges(nx_graph, pos, ax=ax, alpha=0.5)
2228
+
2229
+ ax.set_title("Keçeci Layout: Colored Nodes")
2230
+ return ax
2231
+
2232
+ """
2088
2233
  def draw_kececi_weighted(
2089
2234
  nx_graph: nx.Graph,
2090
2235
  pos: Dict[int, Tuple[float, ...]],
@@ -2132,7 +2277,8 @@ def draw_kececi_weighted(
2132
2277
 
2133
2278
  ax.set_title("Keçeci Layout: Weighted Edges")
2134
2279
  return ax
2135
-
2280
+ """
2281
+ """
2136
2282
  # Renkli Çizim (draw_kececi_colored)
2137
2283
  def draw_kececi_colored(
2138
2284
  nx_graph: nx.Graph,
@@ -2177,6 +2323,7 @@ def draw_kececi_colored(
2177
2323
 
2178
2324
  ax.set_title("Keçeci Layout: Colored Nodes")
2179
2325
  return ax
2326
+ """
2180
2327
 
2181
2328
  # =============================================================================
2182
2329
  # 3. INTERNAL DRAWING STYLE IMPLEMENTATIONS
@@ -2288,13 +2435,16 @@ def draw_kececi(
2288
2435
  style: str = 'default',
2289
2436
  ax: Optional[plt.Axes] = None,
2290
2437
  with_labels: bool = True,
2291
- node_color: str = 'lightblue',
2438
+ node_color: Union[str, List] = 'lightblue',
2292
2439
  node_size: int = 500,
2293
2440
  font_weight: str = 'bold',
2441
+ edge_color: str = 'gray',
2442
+ edge_alpha: float = 0.5,
2443
+ edge_width: float = 1.0,
2294
2444
  **kwargs
2295
2445
  ) -> plt.Axes:
2296
2446
  """
2297
- Keçeci Layout ile graf çizimi.
2447
+ Keçeci Layout ile 2D/3D uyumlu graf çizimi.
2298
2448
 
2299
2449
  Args:
2300
2450
  graph: Graf objesi (NetworkX, igraph, vb.).
@@ -2303,9 +2453,12 @@ def draw_kececi(
2303
2453
  style: 'default', 'weighted', 'colored'.
2304
2454
  ax: Matplotlib ekseni.
2305
2455
  with_labels: Düğüm etiketlerini göster.
2306
- node_color: Düğüm rengi.
2456
+ node_color: Düğüm rengi (tek renk veya renk listesi).
2307
2457
  node_size: Düğüm boyutu.
2308
2458
  font_weight: Yazı kalınlığı.
2459
+ edge_color: Kenar rengi.
2460
+ edge_alpha: Kenar şeffaflığı.
2461
+ edge_width: Kenar kalınlığı.
2309
2462
  **kwargs: Ek parametreler.
2310
2463
 
2311
2464
  Returns:
@@ -2313,6 +2466,209 @@ def draw_kececi(
2313
2466
  """
2314
2467
  nx_graph = to_networkx(graph)
2315
2468
 
2469
+ # Eğer pos verilmemişse, layout'a göre hesapla
2470
+ if pos is None:
2471
+ if layout is None:
2472
+ layout = '2d' # Varsayılan layout
2473
+
2474
+ if layout == '2d':
2475
+ pos = kececi_layout_2d(nx_graph, **kwargs)
2476
+ elif layout == 'cylindrical':
2477
+ pos = kececi_layout_cylindrical(nx_graph, **kwargs)
2478
+ elif layout == 'cubic':
2479
+ pos = kececi_layout_cubic(nx_graph, **kwargs)
2480
+ elif layout == 'spherical':
2481
+ pos = kececi_layout_spherical(nx_graph, **kwargs)
2482
+ elif layout == 'elliptical':
2483
+ pos = kececi_layout_elliptical(nx_graph, **kwargs)
2484
+ elif layout == 'toric':
2485
+ pos = kececi_layout_toric(nx_graph, **kwargs)
2486
+ else:
2487
+ raise ValueError(f"Geçersiz layout: {layout}")
2488
+
2489
+ # 2D mi 3D mi kontrol et
2490
+ is_3d = len(pos[next(iter(pos))]) == 3
2491
+
2492
+ # Eksen oluştur (eğer verilmemişse)
2493
+ if ax is None:
2494
+ fig = plt.figure(figsize=(10, 8))
2495
+ if is_3d:
2496
+ ax = fig.add_subplot(111, projection='3d')
2497
+ else:
2498
+ ax = fig.add_subplot(111)
2499
+
2500
+ # Stile göre çizim yap
2501
+ if style == 'weighted':
2502
+ draw_kececi_weighted(nx_graph, pos, ax, node_size=node_size,
2503
+ with_labels=with_labels, font_weight=font_weight, **kwargs)
2504
+ elif style == 'colored':
2505
+ draw_kececi_colored(nx_graph, pos, ax, node_size=node_size,
2506
+ with_labels=with_labels, font_weight=font_weight, **kwargs)
2507
+ else: # 'default'
2508
+ # Node'ları çiz
2509
+ nx.draw_networkx_nodes(nx_graph, pos, ax=ax,
2510
+ node_color=node_color,
2511
+ node_size=node_size,
2512
+ **kwargs)
2513
+
2514
+ # Etiketleri çiz
2515
+ if with_labels:
2516
+ if is_3d:
2517
+ # 3D için özel etiket çizimi
2518
+ for node, coord in pos.items():
2519
+ ax.text(coord[0], coord[1], coord[2], # 3D koordinatlar
2520
+ str(node), # 's' parametresi - etiket metni
2521
+ size=10,
2522
+ zorder=1,
2523
+ color='black',
2524
+ fontweight=font_weight,
2525
+ ha='center', # Yatayda ortala
2526
+ va='center') # Dikeyde ortala
2527
+ else:
2528
+ # 2D için NetworkX etiket çizimi
2529
+ nx.draw_networkx_labels(nx_graph, pos, ax=ax, font_weight=font_weight)
2530
+
2531
+ # Edge'leri çiz
2532
+ if is_3d:
2533
+ for u, v in nx_graph.edges():
2534
+ ax.plot(
2535
+ [pos[u][0], pos[v][0]],
2536
+ [pos[u][1], pos[v][1]],
2537
+ [pos[u][2], pos[v][2]],
2538
+ color=edge_color,
2539
+ alpha=edge_alpha,
2540
+ linewidth=edge_width
2541
+ )
2542
+ else:
2543
+ nx.draw_networkx_edges(nx_graph, pos, ax=ax,
2544
+ alpha=edge_alpha,
2545
+ edge_color=edge_color,
2546
+ width=edge_width)
2547
+
2548
+ title = f"Keçeci Layout: {layout.capitalize() if layout else 'Custom'} ({style})"
2549
+ ax.set_title(title)
2550
+
2551
+ # Eksenleri kapat
2552
+ ax.set_axis_off()
2553
+
2554
+ return ax
2555
+
2556
+ def draw_kececi_custom_labels(
2557
+ graph,
2558
+ pos: Dict[int, Tuple[float, ...]],
2559
+ labels: Dict[int, str],
2560
+ ax: Optional[plt.Axes] = None,
2561
+ node_size: int = 500,
2562
+ node_color: Union[str, List] = 'lightblue',
2563
+ font_size: int = 10,
2564
+ font_color: Union[str, List] = 'black',
2565
+ font_weight: str = 'bold',
2566
+ **kwargs
2567
+ ) -> plt.Axes:
2568
+ """
2569
+ Özel etiketlerle Keçeci layout çizimi (2D/3D uyumlu).
2570
+
2571
+ Args:
2572
+ graph: Graf objesi
2573
+ pos: Node pozisyonları
2574
+ labels: Özel etiketler (node_id: label_text)
2575
+ ax: Matplotlib ekseni
2576
+ node_size: Node boyutu
2577
+ node_color: Node rengi
2578
+ font_size: Yazı boyutu
2579
+ font_color: Yazı rengi
2580
+ font_weight: Yazı kalınlığı
2581
+ **kwargs: Ek parametreler
2582
+
2583
+ Returns:
2584
+ Matplotlib ekseni
2585
+ """
2586
+ nx_graph = to_networkx(graph)
2587
+
2588
+ # 2D mi 3D mi kontrol et
2589
+ is_3d = len(pos[next(iter(pos))]) == 3
2590
+
2591
+ # Eksen oluştur (eğer verilmemişse)
2592
+ if ax is None:
2593
+ fig = plt.figure(figsize=(10, 8))
2594
+ if is_3d:
2595
+ ax = fig.add_subplot(111, projection='3d')
2596
+ else:
2597
+ ax = fig.add_subplot(111)
2598
+
2599
+ # Node'ları çiz
2600
+ nx.draw_networkx_nodes(nx_graph, pos, ax=ax,
2601
+ node_color=node_color,
2602
+ node_size=node_size,
2603
+ **kwargs)
2604
+
2605
+ # Edge'leri çiz
2606
+ if is_3d:
2607
+ for u, v in nx_graph.edges():
2608
+ ax.plot(
2609
+ [pos[u][0], pos[v][0]],
2610
+ [pos[u][1], pos[v][1]],
2611
+ [pos[u][2], pos[v][2]],
2612
+ color='gray',
2613
+ alpha=0.5
2614
+ )
2615
+ else:
2616
+ nx.draw_networkx_edges(nx_graph, pos, ax=ax, alpha=0.5)
2617
+
2618
+ # Özel etiketleri çiz
2619
+ if is_3d:
2620
+ for node, coord in pos.items():
2621
+ if node in labels:
2622
+ ax.text(coord[0], coord[1], coord[2],
2623
+ labels[node],
2624
+ fontsize=font_size,
2625
+ fontweight=font_weight,
2626
+ color=font_color if isinstance(font_color, str) else font_color[node-1],
2627
+ ha='center',
2628
+ va='center',
2629
+ zorder=10)
2630
+ else:
2631
+ # 2D için NetworkX etiket çizimi
2632
+ nx.draw_networkx_labels(nx_graph, pos, labels=labels, ax=ax,
2633
+ font_size=font_size,
2634
+ font_color=font_color,
2635
+ font_weight=font_weight)
2636
+
2637
+ ax.set_title("Keçeci Layout with Custom Labels")
2638
+ ax.set_axis_off()
2639
+
2640
+ return ax
2641
+ """
2642
+ def draw_kececi(
2643
+ graph,
2644
+ pos: Optional[Dict[int, Tuple[float, ...]]] = None,
2645
+ layout: Optional[str] = None,
2646
+ style: str = 'default',
2647
+ ax: Optional[plt.Axes] = None,
2648
+ with_labels: bool = True,
2649
+ node_color: str = 'lightblue',
2650
+ node_size: int = 500,
2651
+ font_weight: str = 'bold',
2652
+ **kwargs
2653
+ ) -> plt.Axes:
2654
+
2655
+ Keçeci Layout ile graf çizimi.
2656
+ Args:
2657
+ graph: Graf objesi (NetworkX, igraph, vb.).
2658
+ pos: Önceden hesaplanmış koordinatlar (opsiyonel).
2659
+ layout: '2d', 'cylindrical', 'cubic', 'spherical', 'elliptical', 'toric' (opsiyonel).
2660
+ style: 'default', 'weighted', 'colored'.
2661
+ ax: Matplotlib ekseni.
2662
+ with_labels: Düğüm etiketlerini göster.
2663
+ node_color: Düğüm rengi.
2664
+ node_size: Düğüm boyutu.
2665
+ font_weight: Yazı kalınlığı.
2666
+ **kwargs: Ek parametreler.
2667
+ Returns:
2668
+ Matplotlib ekseni.
2669
+
2670
+ nx_graph = to_networkx(graph)
2671
+
2316
2672
  # Eğer pos verilmemişse, layout'a göre hesapla
2317
2673
  if pos is None:
2318
2674
  if layout is None:
@@ -2374,6 +2730,7 @@ def draw_kececi(
2374
2730
  ax.set_title(f"Keçeci Layout: {layout.capitalize() if layout else 'Custom'} ({style})")
2375
2731
  return ax
2376
2732
  """
2733
+ """
2377
2734
  def draw_kececi(
2378
2735
  graph,
2379
2736
  layout: str = '2d',
@@ -2383,14 +2740,12 @@ def draw_kececi(
2383
2740
  ) -> plt.Axes:
2384
2741
 
2385
2742
  Keçeci Layout ile graf çizimi.
2386
-
2387
2743
  Args:
2388
2744
  graph: Graf objesi (NetworkX, igraph, vb.).
2389
2745
  layout: '2d', 'cylindrical', 'cubic', 'spherical', 'elliptical', 'toric'.
2390
2746
  style: 'default', 'weighted', 'colored'.
2391
2747
  ax: Matplotlib ekseni.
2392
2748
  **kwargs: Ek parametreler.
2393
-
2394
2749
  Returns:
2395
2750
  Matplotlib ekseni.
2396
2751
 
@@ -2491,23 +2846,1398 @@ def draw_kececi(graph, style='curved', ax=None, **kwargs):
2491
2846
  return ax
2492
2847
  """
2493
2848
 
2494
- # =============================================================================
2495
- # MODULE TEST CODE
2496
- # =============================================================================
2497
-
2498
- if __name__ == '__main__':
2499
- print("Testing kececilayout.py module...")
2500
- G_test = nx.gnp_random_graph(12, 0.3, seed=42)
2501
-
2502
- # graph-tool grafi oluşturma ve test etme
2503
- if gt:
2504
- g = gt.Graph()
2505
- g.add_vertex(12)
2506
- for u, v in G_test.edges():
2507
- g.add_edge(g.vertex(u), g.vertex(v))
2508
- fig_gt = plt.figure(figsize=(10, 8))
2509
- draw_kececi(g, ax=fig_gt.add_subplot(111), style='curved')
2510
- plt.title("Keçeci Layout: graph-tool Graph")
2849
+ def draw_kececi_periodic_table(
2850
+ graph,
2851
+ periodic_elements: Dict[int, Tuple[str, int]],
2852
+ layout_type: str = '3d_helix',
2853
+ layout_params: Optional[Dict] = None,
2854
+ ax: Optional[plt.Axes] = None,
2855
+ dimension: str = 'auto', # '2d', '3d', or 'auto'
2856
+ color_scheme: str = 'vibrant', # 'vibrant', 'distinct', 'pastel', 'group', 'period', 'block', 'electronegativity'
2857
+ node_size: Union[int, List[int]] = 1600,
2858
+ font_size: Union[int, List[int]] = 10,
2859
+ edge_style: str = 'standard', # 'standard', 'light', 'bold', 'hidden'
2860
+ label_position: str = 'center', # 'center', 'above', 'below', 'right', 'left'
2861
+ zorder_strategy: str = 'smart', # 'smart', 'fixed', 'z_based'
2862
+ show_legend: bool = False,
2863
+ title: Optional[str] = None,
2864
+ **kwargs
2865
+ ) -> Tuple[plt.Axes, Dict]:
2866
+ """
2867
+ Gelişmiş periyodik tablo çizimi - Hem 2D hem 3D uyumlu.
2868
+ """
2869
+ # Graph'ı NetworkX'e çevir
2870
+ nx_graph = to_networkx(graph)
2871
+ node_count = len(periodic_elements)
2872
+
2873
+ # Dimension belirleme
2874
+ if dimension == 'auto':
2875
+ if '3d' in layout_type.lower():
2876
+ dimension = '3d'
2877
+ else:
2878
+ dimension = '2d'
2879
+
2880
+ # Layout parametreleri
2881
+ if layout_params is None:
2882
+ layout_params = {}
2883
+
2884
+ # Layout hesapla
2885
+ pos = _calculate_layout(nx_graph, layout_type, layout_params, dimension, node_count)
2886
+
2887
+ # Renkleri oluştur
2888
+ node_colors = _generate_colors(node_count, color_scheme, periodic_elements)
2889
+
2890
+ # Etiketleri oluştur
2891
+ custom_labels = _generate_labels(nx_graph, periodic_elements)
2892
+
2893
+ # Eksen oluştur (eğer verilmemişse)
2894
+ if ax is None:
2895
+ fig_size = kwargs.get('figsize', (20, 20) if dimension == '3d' else (16, 16))
2896
+ fig = plt.figure(figsize=fig_size)
2897
+ if dimension == '3d':
2898
+ ax = fig.add_subplot(111, projection='3d')
2899
+ else:
2900
+ ax = fig.add_subplot(111)
2901
+
2902
+ # Çizim sırasını belirle
2903
+ draw_order = _get_draw_order(nx_graph, pos, zorder_strategy, dimension)
2904
+
2905
+ # Edge stilleri
2906
+ edge_config = _get_edge_config(edge_style)
2907
+
2908
+ # Edge'leri çiz (ilk sırada)
2909
+ _draw_edges(nx_graph, pos, ax, edge_config, dimension)
2910
+
2911
+ # Node'ları çiz (çizim sırasına göre)
2912
+ _draw_nodes(nx_graph, pos, node_colors, ax, node_size, draw_order, dimension, **kwargs)
2913
+
2914
+ # Etiketleri çiz
2915
+ _draw_labels(nx_graph, pos, custom_labels, node_colors, ax, font_size,
2916
+ label_position, dimension, **kwargs)
2917
+
2918
+ # Başlık
2919
+ if title is None:
2920
+ title = _generate_title(layout_type, node_count, color_scheme, dimension)
2921
+ ax.set_title(title, fontsize=20, fontweight='bold', pad=25)
2922
+
2923
+ # Eksen ayarları
2924
+ _configure_axes(ax, pos, dimension, layout_params, **kwargs)
2925
+
2926
+ # Açıklama (legend)
2927
+ if show_legend and color_scheme in ['group', 'period', 'block']:
2928
+ _add_legend(ax, color_scheme, dimension, periodic_elements)
2929
+
2930
+ return ax, pos
2931
+
2932
+
2933
+ # Yardımcı fonksiyonlar (öncekiyle aynı)
2934
+ def _calculate_layout(graph, layout_type, params, dimension, node_count=None):
2935
+ """Layout hesapla."""
2936
+ if layout_type == '3d_helix':
2937
+ return kececi_layout_3d_helix_parametric(
2938
+ graph,
2939
+ z_spacing=params.get('z_spacing', 8.0),
2940
+ radius=params.get('radius', 25.0),
2941
+ turns=params.get('turns', 3.0)
2942
+ )
2943
+
2944
+ elif layout_type == '2d_linear':
2945
+ return kececi_layout_2d(
2946
+ graph,
2947
+ primary_spacing=params.get('primary_spacing', 2.0),
2948
+ secondary_spacing=params.get('secondary_spacing', 2.0),
2949
+ primary_direction=params.get('primary_direction', 'left-to-right'),
2950
+ secondary_start=params.get('secondary_start', 'up'),
2951
+ expanding=params.get('expanding', True)
2952
+ )
2953
+
2954
+ elif layout_type == '2d_circular':
2955
+ return nx.circular_layout(graph, scale=params.get('scale', 1.0))
2956
+
2957
+ elif layout_type == '3d_spherical':
2958
+ pos = {}
2959
+ n = len(graph.nodes())
2960
+ for i, node in enumerate(graph.nodes()):
2961
+ phi = np.arccos(1 - 2 * (i + 0.5) / n)
2962
+ theta = np.pi * (1 + 5**0.5) * i
2963
+ radius = params.get('radius', 20.0)
2964
+ pos[node] = (
2965
+ radius * np.sin(phi) * np.cos(theta),
2966
+ radius * np.sin(phi) * np.sin(theta),
2967
+ radius * np.cos(phi)
2968
+ )
2969
+ return pos
2970
+
2971
+ elif layout_type == '2d_spring':
2972
+ return nx.spring_layout(graph, k=params.get('k', 2.0),
2973
+ iterations=params.get('iterations', 50))
2974
+
2975
+ elif layout_type == '2d_grid':
2976
+ return _generate_grid_layout(graph, params, node_count)
2977
+
2978
+ else:
2979
+ return kececi_layout_2d(
2980
+ graph,
2981
+ primary_spacing=params.get('primary_spacing', 2.0),
2982
+ secondary_spacing=params.get('secondary_spacing', 2.0),
2983
+ primary_direction=params.get('primary_direction', 'left-to-right'),
2984
+ secondary_start=params.get('secondary_start', 'up'),
2985
+ expanding=params.get('expanding', True)
2986
+ )
2987
+
2988
+ def _generate_grid_layout(graph, params, node_count):
2989
+ """Manuel grid layout oluştur."""
2990
+ rows = params.get('rows', None)
2991
+ cols = params.get('cols', None)
2992
+ spacing = params.get('spacing', 2.0)
2993
+
2994
+ if rows is None and cols is None:
2995
+ cols = int(np.ceil(np.sqrt(node_count)))
2996
+ rows = int(np.ceil(node_count / cols))
2997
+ elif rows is None:
2998
+ rows = int(np.ceil(node_count / cols))
2999
+ elif cols is None:
3000
+ cols = int(np.ceil(node_count / rows))
3001
+
3002
+ pos = {}
3003
+ for i, node in enumerate(sorted(graph.nodes())):
3004
+ row = i // cols
3005
+ col = i % cols
3006
+
3007
+ x_offset = -(cols - 1) * spacing / 2
3008
+ y_offset = (rows - 1) * spacing / 2
3009
+
3010
+ x = col * spacing + x_offset
3011
+ y = -row * spacing + y_offset
3012
+
3013
+ pos[node] = (x, y)
3014
+
3015
+ return pos
3016
+
3017
+
3018
+ def _generate_colors(node_count, scheme, periodic_elements=None):
3019
+ """Renkleri oluştur."""
3020
+ colors = []
3021
+
3022
+ if scheme == 'vibrant':
3023
+ for i in range(node_count):
3024
+ hue = (i * 0.618033988749895) % 1.0
3025
+ saturation = 0.7 + np.random.random() * 0.3
3026
+ value = 0.8 + np.random.random() * 0.2
3027
+ colors.append(hsv_to_rgb([hue, saturation, value]))
3028
+
3029
+ elif scheme == 'distinct':
3030
+ colors = generate_distinct_colors(node_count)
3031
+
3032
+ elif scheme == 'pastel':
3033
+ for i in range(node_count):
3034
+ hue = i / max(node_count, 1)
3035
+ saturation = 0.4 + np.random.random() * 0.3
3036
+ value = 0.9 + np.random.random() * 0.1
3037
+ colors.append(hsv_to_rgb([hue, saturation, value]))
3038
+
3039
+ elif scheme == 'group' and periodic_elements:
3040
+ colors = _get_group_colors(node_count, periodic_elements)
3041
+
3042
+ elif scheme == 'period' and periodic_elements:
3043
+ colors = _get_period_colors(node_count, periodic_elements)
3044
+
3045
+ elif scheme == 'block' and periodic_elements:
3046
+ colors = _get_block_colors(node_count, periodic_elements)
3047
+
3048
+ elif scheme == 'electronegativity' and periodic_elements:
3049
+ colors = _get_electronegativity_colors(node_count, periodic_elements)
3050
+
3051
+ else:
3052
+ cmap = plt.cm.tab20
3053
+ colors = [cmap(i % 20) for i in range(node_count)]
3054
+
3055
+ return colors
3056
+
3057
+ def _get_group_colors(node_count, periodic_elements):
3058
+ """Gruplara göre renkler."""
3059
+ colors = []
3060
+ group_colors = {
3061
+ 1: (1.0, 0.6, 0.6), # Alkali metals
3062
+ 2: (1.0, 0.8, 0.6), # Alkaline earth
3063
+ 3: (0.8, 1.0, 0.6), # Group 3
3064
+ 4: (0.7, 0.9, 0.8), # Group 4
3065
+ 5: (0.6, 0.9, 0.9), # Group 5
3066
+ 6: (0.6, 0.8, 1.0), # Group 6
3067
+ 7: (0.8, 0.6, 1.0), # Group 7
3068
+ 8: (0.9, 0.9, 0.6), # Group 8
3069
+ 9: (1.0, 0.9, 0.6), # Group 9
3070
+ 10: (0.9, 0.8, 0.7), # Group 10
3071
+ 11: (1.0, 0.8, 0.8), # Group 11
3072
+ 12: (0.8, 1.0, 0.8), # Group 12
3073
+ 13: (0.8, 0.9, 1.0), # Boron group
3074
+ 14: (0.9, 0.8, 1.0), # Carbon group
3075
+ 15: (1.0, 0.8, 0.9), # Nitrogen group
3076
+ 16: (0.8, 1.0, 0.9), # Oxygen group
3077
+ 17: (1.0, 0.9, 0.8), # Halogens
3078
+ 18: (0.9, 0.9, 0.9), # Noble gases
3079
+ }
3080
+
3081
+ lanthanide_color = (0.7, 1.0, 0.7)
3082
+ actinide_color = (1.0, 0.7, 0.7)
3083
+
3084
+ for node_id in range(1, node_count + 1):
3085
+ if node_id in list(range(57, 72)):
3086
+ colors.append(lanthanide_color)
3087
+ elif node_id in list(range(89, 104)):
3088
+ colors.append(actinide_color)
3089
+ else:
3090
+ group = _determine_group(node_id)
3091
+ colors.append(group_colors.get(group, (0.8, 0.8, 0.8)))
3092
+
3093
+ return colors
3094
+
3095
+ def _determine_group(atomic_num):
3096
+ """Atom numarasına göre grup belirle."""
3097
+ if atomic_num <= 2:
3098
+ return atomic_num
3099
+ elif atomic_num <= 10:
3100
+ return atomic_num - 2
3101
+ elif atomic_num <= 18:
3102
+ return atomic_num - 10
3103
+ elif atomic_num <= 36:
3104
+ if atomic_num <= 20:
3105
+ return atomic_num - 18
3106
+ elif atomic_num <= 30:
3107
+ return atomic_num - 20
3108
+ else:
3109
+ return atomic_num - 28
3110
+ elif atomic_num <= 54:
3111
+ if atomic_num <= 38:
3112
+ return atomic_num - 36
3113
+ elif atomic_num <= 48:
3114
+ return atomic_num - 38
3115
+ else:
3116
+ return atomic_num - 46
3117
+ else:
3118
+ return 18
3119
+
3120
+ def _get_period_colors(node_count, periodic_elements):
3121
+ """Periyotlara göre renkler."""
3122
+ colors = []
3123
+ period_colors = [
3124
+ (1.0, 0.7, 0.7), # Period 1
3125
+ (1.0, 0.9, 0.7), # Period 2
3126
+ (0.9, 1.0, 0.7), # Period 3
3127
+ (0.7, 1.0, 0.8), # Period 4
3128
+ (0.7, 0.9, 1.0), # Period 5
3129
+ (0.8, 0.7, 1.0), # Period 6
3130
+ (1.0, 0.7, 0.9), # Period 7
3131
+ ]
3132
+
3133
+ for atomic_num in range(1, node_count + 1):
3134
+ if atomic_num <= 2:
3135
+ period = 0
3136
+ elif atomic_num <= 10:
3137
+ period = 1
3138
+ elif atomic_num <= 18:
3139
+ period = 2
3140
+ elif atomic_num <= 36:
3141
+ period = 3
3142
+ elif atomic_num <= 54:
3143
+ period = 4
3144
+ elif atomic_num <= 86:
3145
+ period = 5
3146
+ else:
3147
+ period = 6
3148
+
3149
+ colors.append(period_colors[period % len(period_colors)])
3150
+
3151
+ return colors
3152
+
3153
+ def _get_block_colors(node_count, periodic_elements):
3154
+ """Bloklara göre renkler."""
3155
+ colors = []
3156
+
3157
+ for atomic_num in range(1, node_count + 1):
3158
+ if atomic_num in [1, 2, 3, 4, 11, 12, 19, 20, 37, 38, 55, 56, 87, 88]:
3159
+ colors.append((1.0, 0.6, 0.6)) # s-block
3160
+ elif atomic_num in (list(range(5, 11)) + list(range(13, 19)) +
3161
+ list(range(31, 37)) + list(range(49, 55)) +
3162
+ list(range(81, 87)) + list(range(113, 119))):
3163
+ colors.append((0.6, 0.8, 1.0)) # p-block
3164
+ elif atomic_num in (list(range(21, 31)) + list(range(39, 49)) +
3165
+ list(range(72, 81)) + list(range(104, 113))):
3166
+ colors.append((0.6, 1.0, 0.6)) # d-block
3167
+ elif atomic_num in list(range(57, 72)) + list(range(89, 104)):
3168
+ colors.append((1.0, 0.6, 1.0)) # f-block
3169
+ else:
3170
+ colors.append((0.8, 0.8, 0.8))
3171
+
3172
+ return colors
3173
+
3174
+ def _get_electronegativity_colors(node_count, periodic_elements):
3175
+ """Elektronegativiteye göre renkler."""
3176
+ colors = []
3177
+ electronegativity_data = {
3178
+ 1: 2.20, 3: 0.98, 4: 1.57, 5: 2.04, 6: 2.55, 7: 3.04, 8: 3.44,
3179
+ 9: 3.98, 11: 0.93, 12: 1.31, 13: 1.61, 14: 1.90, 15: 2.19,
3180
+ 16: 2.58, 17: 3.16, 19: 0.82, 20: 1.00, 21: 1.36, 22: 1.54,
3181
+ 23: 1.63, 24: 1.66, 25: 1.55, 26: 1.83, 27: 1.88, 28: 1.91, 29: 1.90,
3182
+ 30: 1.65, 31: 1.81, 32: 2.01, 33: 2.18, 34: 2.55, 35: 2.96,
3183
+ 37: 0.82, 38: 0.95, 39: 1.22, 40: 1.33, 41: 1.60, 42: 2.16, 43: 1.90,
3184
+ 44: 2.20, 45: 2.28, 46: 2.20, 47: 1.93, 48: 1.69, 49: 1.78, 50: 1.96,
3185
+ 51: 2.05, 52: 2.10, 53: 2.66, 55: 0.79, 56: 0.89, 57: 1.10,
3186
+ 58: 1.12, 59: 1.13, 60: 1.14, 62: 1.17, 63: 1.20, 64: 1.20, 65: 1.20,
3187
+ 66: 1.22, 67: 1.23, 68: 1.24, 69: 1.25, 70: 1.10, 71: 1.27, 72: 1.30,
3188
+ 73: 1.50, 74: 2.36, 75: 1.90, 76: 2.20, 77: 2.20, 78: 2.28, 79: 2.54,
3189
+ 80: 2.00, 81: 1.62, 82: 1.87, 83: 2.02, 84: 2.00, 85: 2.20,
3190
+ 87: 0.70, 88: 0.89, 89: 1.10, 90: 1.30, 91: 1.50, 92: 1.38, 93: 1.36,
3191
+ 94: 1.28, 95: 1.30, 96: 1.30, 97: 1.30, 98: 1.30, 99: 1.30, 100: 1.30,
3192
+ 101: 1.30, 102: 1.30, 103: 1.30
3193
+ }
3194
+
3195
+ for atomic_num in range(1, node_count + 1):
3196
+ en = electronegativity_data.get(atomic_num, 1.5)
3197
+ if en < 1.0:
3198
+ color = (0.0, 0.0, 0.8)
3199
+ elif en < 1.5:
3200
+ color = (0.0, 0.5, 1.0)
3201
+ elif en < 2.0:
3202
+ color = (0.0, 0.8, 0.8)
3203
+ elif en < 2.5:
3204
+ color = (0.5, 1.0, 0.5)
3205
+ elif en < 3.0:
3206
+ color = (1.0, 0.8, 0.0)
3207
+ elif en < 3.5:
3208
+ color = (1.0, 0.5, 0.0)
3209
+ else:
3210
+ color = (1.0, 0.0, 0.0)
3211
+
3212
+ colors.append(color)
3213
+
3214
+ return colors
3215
+
3216
+
3217
+ def _generate_labels(graph, periodic_elements):
3218
+ """Etiketleri oluştur."""
3219
+ return {node_id: f"{periodic_elements[node_id][0]}\n{periodic_elements[node_id][1]}"
3220
+ for node_id in graph.nodes()}
3221
+
3222
+ def _get_draw_order(graph, pos, strategy, dimension):
3223
+ """Çizim sırasını belirle."""
3224
+ if strategy == 'fixed':
3225
+ return list(graph.nodes())
3226
+ elif strategy == 'z_based' and dimension == '3d':
3227
+ return sorted(graph.nodes(), key=lambda n: pos[n][2], reverse=True)
3228
+ elif strategy == 'smart':
3229
+ nodes = list(graph.nodes())
3230
+ if len(nodes) == 0:
3231
+ return nodes
3232
+
3233
+ if dimension == '3d':
3234
+ positions = np.array([pos[n] for n in nodes])
3235
+ center = np.mean(positions, axis=0)
3236
+ distances = np.linalg.norm(positions - center, axis=1)
3237
+ else:
3238
+ positions = np.array([pos[n] for n in nodes])
3239
+ center = np.mean(positions, axis=0)
3240
+ distances = np.linalg.norm(positions - center, axis=1)
3241
+
3242
+ sorted_indices = np.argsort(distances)[::-1]
3243
+ return [nodes[i] for i in sorted_indices]
3244
+ else:
3245
+ return list(graph.nodes())
3246
+
3247
+ def _get_edge_config(style):
3248
+ """Edge stilini belirle."""
3249
+ configs = {
3250
+ 'standard': {'color': 'gray', 'alpha': 0.5, 'width': 1.0},
3251
+ 'light': {'color': 'lightgray', 'alpha': 0.3, 'width': 0.8},
3252
+ 'bold': {'color': 'black', 'alpha': 0.7, 'width': 2.0},
3253
+ 'hidden': {'color': 'none', 'alpha': 0.0, 'width': 0.0}
3254
+ }
3255
+ return configs.get(style, configs['standard'])
3256
+
3257
+
3258
+ def _draw_edges(graph, pos, ax, config, dimension):
3259
+ """Edge'leri çiz."""
3260
+ if config['color'] == 'none':
3261
+ return
3262
+
3263
+ for u, v in graph.edges():
3264
+ if dimension == '3d':
3265
+ ax.plot(
3266
+ [pos[u][0], pos[v][0]],
3267
+ [pos[u][1], pos[v][1]],
3268
+ [pos[u][2], pos[v][2]],
3269
+ color=config['color'],
3270
+ alpha=config['alpha'],
3271
+ linewidth=config['width'],
3272
+ zorder=1
3273
+ )
3274
+ else:
3275
+ ax.plot(
3276
+ [pos[u][0], pos[v][0]],
3277
+ [pos[u][1], pos[v][1]],
3278
+ color=config['color'],
3279
+ alpha=config['alpha'],
3280
+ linewidth=config['width'],
3281
+ zorder=1
3282
+ )
3283
+
3284
+ def _draw_nodes(graph, pos, colors, ax, node_size, draw_order, dimension, **kwargs):
3285
+ """Node'ları çiz."""
3286
+ edge_width = kwargs.get('edge_width', 2.0)
3287
+ alpha = kwargs.get('node_alpha', 1.0)
3288
+
3289
+ for node_id in draw_order:
3290
+ if dimension == '3d':
3291
+ x, y, z = pos[node_id]
3292
+ ax.scatter(x, y, z,
3293
+ s=node_size if isinstance(node_size, int) else node_size[node_id-1],
3294
+ c=[colors[node_id-1]],
3295
+ edgecolors='black',
3296
+ linewidths=edge_width,
3297
+ alpha=alpha,
3298
+ depthshade=False if kwargs.get('no_depth_shade', False) else True,
3299
+ zorder=10)
3300
+ else:
3301
+ x, y = pos[node_id]
3302
+ ax.scatter(x, y,
3303
+ s=node_size if isinstance(node_size, int) else node_size[node_id-1],
3304
+ c=[colors[node_id-1]],
3305
+ edgecolors='black',
3306
+ linewidths=edge_width,
3307
+ alpha=alpha,
3308
+ zorder=10)
3309
+
3310
+ def _draw_labels(graph, pos, labels, colors, ax, font_size, position, dimension, **kwargs):
3311
+ """Etiketleri çiz."""
3312
+ label_offset = kwargs.get('label_offset', 0.0)
3313
+
3314
+ for node_id in graph.nodes():
3315
+ if dimension == '3d':
3316
+ x, y, z = pos[node_id]
3317
+ if position == 'above':
3318
+ z += label_offset
3319
+ elif position == 'below':
3320
+ z -= label_offset
3321
+ elif position == 'right':
3322
+ x += label_offset
3323
+ elif position == 'left':
3324
+ x -= label_offset
3325
+
3326
+ bg_color = colors[node_id-1]
3327
+ text_color = get_text_color_for_bg(bg_color)
3328
+
3329
+ ax.text(x, y, z,
3330
+ labels[node_id],
3331
+ fontsize=font_size if isinstance(font_size, int) else font_size[node_id-1],
3332
+ fontweight='bold',
3333
+ color=text_color,
3334
+ ha='center',
3335
+ va='center',
3336
+ zorder=1000)
3337
+ else:
3338
+ x, y = pos[node_id]
3339
+ if position == 'above':
3340
+ y += label_offset
3341
+ elif position == 'below':
3342
+ y -= label_offset
3343
+ elif position == 'right':
3344
+ x += label_offset
3345
+ elif position == 'left':
3346
+ x -= label_offset
3347
+
3348
+ bg_color = colors[node_id-1]
3349
+ text_color = get_text_color_for_bg(bg_color)
3350
+
3351
+ ax.text(x, y,
3352
+ labels[node_id],
3353
+ fontsize=font_size if isinstance(font_size, int) else font_size[node_id-1],
3354
+ fontweight='bold',
3355
+ color=text_color,
3356
+ ha='center',
3357
+ va='center',
3358
+ zorder=1000)
3359
+
3360
+ def _generate_title(layout_type, node_count, color_scheme, dimension):
3361
+ """Başlık oluştur."""
3362
+ dim_text = "3D" if dimension == '3d' else "2D"
3363
+ scheme_text = color_scheme.capitalize()
3364
+
3365
+ layout_names = {
3366
+ '3d_helix': '3D Heliks Layout',
3367
+ '2d_linear': '2D Lineer Layout',
3368
+ '2d_circular': 'Dairesel Layout',
3369
+ '3d_spherical': '3D Küresel Layout',
3370
+ '2d_spring': '2D Yay Layout',
3371
+ '2d_grid': '2D Grid Layout'
3372
+ }
3373
+
3374
+ layout_name = layout_names.get(layout_type, layout_type.replace('_', ' ').title())
3375
+
3376
+ title = f"Keçeci Layout ile Periyodik Tablo\n"
3377
+ title += f"{dim_text} {layout_name}\n"
3378
+ title += f"({node_count} Element, {scheme_text} Renk Şeması)"
3379
+
3380
+ return title
3381
+
3382
+ def _configure_axes(ax, pos, dimension, layout_params, **kwargs):
3383
+ """Eksenleri yapılandır."""
3384
+ ax.set_axis_off()
3385
+
3386
+ if dimension == '3d':
3387
+ elev = kwargs.get('elevation', -25)
3388
+ azim = kwargs.get('azimuth', 15)
3389
+ ax.view_init(elev=elev, azim=azim)
3390
+
3391
+ positions = list(pos.values())
3392
+ if positions:
3393
+ xs, ys, zs = zip(*positions)
3394
+
3395
+ padding = kwargs.get('padding', 0.2)
3396
+ x_range = max(xs) - min(xs)
3397
+ y_range = max(ys) - min(ys)
3398
+ z_range = max(zs) - min(zs)
3399
+
3400
+ x_range = max(x_range, 10)
3401
+ y_range = max(y_range, 10)
3402
+ z_range = max(z_range, 10)
3403
+
3404
+ ax.set_xlim(min(xs) - x_range*padding, max(xs) + x_range*padding)
3405
+ ax.set_ylim(min(ys) - y_range*padding, max(ys) + y_range*padding)
3406
+ ax.set_zlim(min(zs) - z_range*padding, max(zs) + z_range*padding)
3407
+ else:
3408
+ ax.set_aspect('equal')
3409
+ ax.autoscale_view()
3410
+
3411
+ def _add_legend(ax, color_scheme, dimension, periodic_elements):
3412
+ """Renk şeması açıklaması ekle."""
3413
+ legend_text = f"Renk Şeması: {color_scheme.capitalize()}\n"
3414
+
3415
+ if color_scheme == 'group':
3416
+ legend_text += "• Kırmızı: Alkali Metaller\n"
3417
+ legend_text += "• Turuncu: Toprak Alkali\n"
3418
+ legend_text += "• Yeşil: Geçiş Metalleri\n"
3419
+ legend_text += "• Mavi: Ametaller\n"
3420
+ legend_text += "• Mor: Halojenler\n"
3421
+ legend_text += "• Gri: Soygazlar"
3422
+
3423
+ elif color_scheme == 'period':
3424
+ legend_text += "• Her periyot farklı renk\n"
3425
+ legend_text += "• 7 periyot, 7 renk"
3426
+
3427
+ elif color_scheme == 'block':
3428
+ legend_text += "• Kırmızı: s-blok\n"
3429
+ legend_text += "• Mavi: p-blok\n"
3430
+ legend_text += "• Yeşil: d-blok\n"
3431
+ legend_text += "• Mor: f-blok"
3432
+
3433
+ if dimension == '3d':
3434
+ ax.text2D(0.02, 0.98, legend_text, transform=ax.transAxes,
3435
+ fontsize=9, verticalalignment='top',
3436
+ bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
3437
+ else:
3438
+ ax.text(0.02, 0.98, legend_text, transform=ax.transAxes,
3439
+ fontsize=9, verticalalignment='top',
3440
+ bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
3441
+
3442
+ # Ana fonksiyonlar
3443
+ def quick_periodic_table_3d():
3444
+ """
3445
+ Hızlı 3D periyodik tablo görselleştirmesi.
3446
+ Boş şablonlar oluşmaz.
3447
+ """
3448
+ # Önceki figürleri temizle
3449
+ plt.close('all')
3450
+
3451
+ # Periyodik tabloyu yükle
3452
+ periodic_elements, _ = generate_complete_periodic_table()
3453
+
3454
+ # Graf oluştur
3455
+ node_count = len(periodic_elements)
3456
+ G = nx.DiGraph()
3457
+ G.add_nodes_from(range(1, node_count + 1))
3458
+ for i in range(1, node_count):
3459
+ G.add_edge(i, i + 1)
3460
+
3461
+ # Tek figür oluştur
3462
+ fig = plt.figure(figsize=(20, 20))
3463
+ ax = fig.add_subplot(111, projection='3d')
3464
+
3465
+ ax, pos = draw_kececi_periodic_table(
3466
+ G,
3467
+ periodic_elements,
3468
+ layout_type='3d_helix',
3469
+ color_scheme='vibrant',
3470
+ node_size=2000,
3471
+ font_size=10,
3472
+ edge_style='light',
3473
+ title="Keçeci Layout ile Periyodik Tablo\n3D Heliks Layout",
3474
+ elevation=-25,
3475
+ azimuth=15
3476
+ )
3477
+
3478
+ plt.tight_layout()
3479
+ plt.show()
3480
+
3481
+ # Kullanıcıya bilgi ver
3482
+ print(f"\n3D periyodik tablo oluşturuldu!")
3483
+ print(f"Toplam {node_count} element gösteriliyor.")
3484
+ print("Grafı kapatmak için figür penceresini kapatın.")
3485
+
3486
+ return ax, pos
3487
+
3488
+ def generate_comparison_figure():
3489
+ """
3490
+ 4 farklı görseli bir figürde karşılaştırma.
3491
+ Boş şablon oluşmaz.
3492
+ """
3493
+ # Önceki figürleri temizle
3494
+ plt.close('all')
3495
+
3496
+ # Periyodik tabloyu yükle
3497
+ periodic_elements, _ = generate_complete_periodic_table()
3498
+
3499
+ # Graf oluştur
3500
+ node_count = len(periodic_elements)
3501
+ G = nx.DiGraph()
3502
+ G.add_nodes_from(range(1, node_count + 1))
3503
+ for i in range(1, node_count):
3504
+ G.add_edge(i, i + 1)
3505
+
3506
+ # 2x2 grid şeklinde 4 alt figür oluştur
3507
+ fig = plt.figure(figsize=(24, 20))
3508
+ fig.suptitle('Keçeci Layout ile Periyodik Tablo Görselleştirme Karşılaştırması',
3509
+ fontsize=24, fontweight='bold', y=0.98)
3510
+
3511
+ # 1. 3D Heliks Layout
3512
+ ax1 = fig.add_subplot(221, projection='3d')
3513
+ ax1, pos1 = draw_kececi_periodic_table(
3514
+ G,
3515
+ periodic_elements,
3516
+ layout_type='3d_helix',
3517
+ layout_params={'z_spacing': 6.0, 'radius': 20.0, 'turns': 3.0},
3518
+ ax=ax1,
3519
+ color_scheme='vibrant',
3520
+ node_size=1200,
3521
+ font_size=8,
3522
+ edge_style='light',
3523
+ label_position='center',
3524
+ title="3D Heliks Layout\n(Vibrant Renkler)",
3525
+ elevation=-25,
3526
+ azimuth=15,
3527
+ figsize=None # Figsize'ı burada kullanmıyoruz
3528
+ )
3529
+
3530
+ # 2. 2D Linear Layout
3531
+ ax2 = fig.add_subplot(222)
3532
+ ax2, pos2 = draw_kececi_periodic_table(
3533
+ G,
3534
+ periodic_elements,
3535
+ layout_type='2d_linear',
3536
+ layout_params={'primary_spacing': 2.5, 'secondary_spacing': 2.5},
3537
+ ax=ax2,
3538
+ color_scheme='group',
3539
+ dimension='2d',
3540
+ node_size=800,
3541
+ font_size=7,
3542
+ edge_style='standard',
3543
+ show_legend=False,
3544
+ title="2D Linear Layout\n(Grup Renkleri)"
3545
+ )
3546
+
3547
+ # 3. 2D Grid Layout
3548
+ ax3 = fig.add_subplot(223)
3549
+ ax3, pos3 = draw_kececi_periodic_table(
3550
+ G,
3551
+ periodic_elements,
3552
+ layout_type='2d_grid',
3553
+ layout_params={'rows': 9, 'cols': 14, 'spacing': 2.2},
3554
+ ax=ax3,
3555
+ color_scheme='period',
3556
+ dimension='2d',
3557
+ node_size=600,
3558
+ font_size=6,
3559
+ edge_style='light',
3560
+ show_legend=False,
3561
+ title="2D Grid Layout\n(Periyot Renkleri)"
3562
+ )
3563
+
3564
+ # 4. 2D Circular Layout
3565
+ ax4 = fig.add_subplot(224)
3566
+ ax4, pos4 = draw_kececi_periodic_table(
3567
+ G,
3568
+ periodic_elements,
3569
+ layout_type='2d_circular',
3570
+ layout_params={'scale': 2.0},
3571
+ ax=ax4,
3572
+ color_scheme='block',
3573
+ dimension='2d',
3574
+ node_size=800,
3575
+ font_size=7,
3576
+ edge_style='light',
3577
+ show_legend=False,
3578
+ title="2D Dairesel Layout\n(Blok Renkleri)"
3579
+ )
3580
+
3581
+ plt.tight_layout(rect=[0, 0, 1, 0.96])
3582
+ plt.show()
3583
+
3584
+ return fig, (ax1, ax2, ax3, ax4)
3585
+
3586
+ def save_periodic_table_visualization(
3587
+ filename: str = "periodic_table_kececi",
3588
+ format: str = "png",
3589
+ dpi: int = 300,
3590
+ layout_type: str = "3d_helix",
3591
+ color_scheme: str = "vibrant"
3592
+ ):
3593
+ """
3594
+ Periyodik tablo görselleştirmesini kaydet.
3595
+
3596
+ Parameters:
3597
+ -----------
3598
+ filename : str
3599
+ Kaydedilecek dosyanın adı (uzantı olmadan)
3600
+ format : str
3601
+ Kayıt formatı: 'png', 'jpg', 'svg', 'pdf'
3602
+ dpi : int
3603
+ Çözünürlük (dots per inch)
3604
+ layout_type : str
3605
+ Layout tipi
3606
+ color_scheme : str
3607
+ Renk şeması
3608
+ """
3609
+ # Önceki figürleri temizle
3610
+ plt.close('all')
3611
+
3612
+ # Periyodik tabloyu yükle
3613
+ periodic_elements, _ = generate_complete_periodic_table()
3614
+
3615
+ # Graf oluştur
3616
+ node_count = len(periodic_elements)
3617
+ G = nx.DiGraph()
3618
+ G.add_nodes_from(range(1, node_count + 1))
3619
+ for i in range(1, node_count):
3620
+ G.add_edge(i, i + 1)
3621
+
3622
+ # Figür oluştur
3623
+ if '3d' in layout_type.lower():
3624
+ fig = plt.figure(figsize=(16, 16))
3625
+ ax = fig.add_subplot(111, projection='3d')
3626
+ else:
3627
+ fig = plt.figure(figsize=(14, 14))
3628
+ ax = fig.add_subplot(111)
3629
+
3630
+ # Görseli çiz
3631
+ ax, pos = draw_kececi_periodic_table(
3632
+ G,
3633
+ periodic_elements,
3634
+ layout_type=layout_type,
3635
+ ax=ax,
3636
+ color_scheme=color_scheme,
3637
+ node_size=1500 if '3d' in layout_type.lower() else 1000,
3638
+ font_size=9 if '3d' in layout_type.lower() else 8,
3639
+ edge_style='light',
3640
+ show_legend=True if color_scheme in ['group', 'period', 'block'] else False
3641
+ )
3642
+
3643
+ # Kaydet
3644
+ full_filename = f"{filename}.{format}"
3645
+ plt.savefig(full_filename, dpi=dpi, bbox_inches='tight',
3646
+ facecolor='white', edgecolor='none')
3647
+ plt.close()
3648
+
3649
+ print(f"Görsel kaydedildi: {full_filename}")
3650
+ return full_filename
3651
+
3652
+ def highlight_elements(element_symbols: List[str],
3653
+ highlight_color: Tuple[float, float, float] = (1.0, 0.0, 0.0),
3654
+ **kwargs):
3655
+ """
3656
+ Belirli elementleri vurgula.
3657
+
3658
+ Parameters:
3659
+ -----------
3660
+ element_symbols : List[str]
3661
+ Vurgulanacak element sembolleri
3662
+ highlight_color : Tuple[float, float, float]
3663
+ Vurgulama rengi (RGB)
3664
+ **kwargs : diğer parametreler draw_kececi_periodic_table'a aktarılır
3665
+ """
3666
+ # Önceki figürleri temizle
3667
+ plt.close('all')
3668
+
3669
+ # Periyodik tabloyu yükle
3670
+ periodic_elements, _ = generate_complete_periodic_table()
3671
+
3672
+ # Vurgulanacak elementlerin atom numaralarını bul
3673
+ highlight_indices = []
3674
+ element_symbols_found = []
3675
+ valid_symbols = []
3676
+
3677
+ # Element sembolünden isim eşleştirmesi için sabit sözlük
3678
+ # Güncellenmiş Türkçe element isimleri
3679
+ element_name_map = {
3680
+ 'H': 'Hidrojen', 'He': 'Helyum', 'Li': 'Lityum', 'Be': 'Berilyum',
3681
+ 'B': 'Bor', 'C': 'Karbon', 'N': 'Azot', 'O': 'Oksijen', 'F': 'Flor',
3682
+ 'Ne': 'Neon', 'Na': 'Sodyum', 'Mg': 'Magnezyum', 'Al': 'Alüminyum',
3683
+ 'Si': 'Silisyum', 'P': 'Fosfor', 'S': 'Kükürt', 'Cl': 'Klor',
3684
+ 'Ar': 'Argon', 'K': 'Potasyum', 'Ca': 'Kalsiyum', 'Sc': 'Skandiyum',
3685
+ 'Ti': 'Titanyum', 'V': 'Vanadyum', 'Cr': 'Krom', 'Mn': 'Mangan',
3686
+ 'Fe': 'Demir', 'Co': 'Kobalt', 'Ni': 'Nikel', 'Cu': 'Bakır',
3687
+ 'Zn': 'Çinko', 'Ga': 'Galyum', 'Ge': 'Germanyum', 'As': 'Arsenik',
3688
+ 'Se': 'Selenyum', 'Br': 'Brom', 'Kr': 'Kripton', 'Rb': 'Rubidyum',
3689
+ 'Sr': 'Stronsiyum', 'Y': 'İtriyum', 'Zr': 'Zirkonyum', 'Nb': 'Niyobyum',
3690
+ 'Mo': 'Molibden', 'Tc': 'Teknesyum', 'Ru': 'Rutenyum', 'Rh': 'Rodyum',
3691
+ 'Pd': 'Paladyum', 'Ag': 'Gümüş', 'Cd': 'Kadmiyum', 'In': 'İndiyum',
3692
+ 'Sn': 'Kalay', 'Sb': 'Antimon', 'Te': 'Tellür', 'I': 'İyot',
3693
+ 'Xe': 'Ksenon', 'Cs': 'Sezyum', 'Ba': 'Baryum', 'La': 'Lantan',
3694
+ 'Ce': 'Seryum', 'Pr': 'Praseodim', 'Nd': 'Neodimyum', 'Pm': 'Prometyum',
3695
+ 'Sm': 'Samaryum', 'Eu': 'Europyum', 'Gd': 'Gadolinyum', 'Tb': 'Terbiyum',
3696
+ 'Dy': 'Disprozyum', 'Ho': 'Holmiyum', 'Er': 'Erbiyum', 'Tm': 'Tulyum',
3697
+ 'Yb': 'İterbiyum', 'Lu': 'Lutesyum', 'Hf': 'Hafniyum', 'Ta': 'Tantal',
3698
+ 'W': 'Tungsten', 'Re': 'Renyum', 'Os': 'Osmiyum', 'Ir': 'İridyum',
3699
+ 'Pt': 'Platin', 'Au': 'Altın', 'Hg': 'Cıva', 'Tl': 'Talyum',
3700
+ 'Pb': 'Kurşun', 'Bi': 'Bizmut', 'Po': 'Polonyum', 'At': 'Astatin',
3701
+ 'Rn': 'Radon', 'Fr': 'Fransiyum', 'Ra': 'Radyum', 'Ac': 'Aktinyum',
3702
+ 'Th': 'Toryum', 'Pa': 'Protaktinyum', 'U': 'Uranyum', 'Np': 'Neptünyum',
3703
+ 'Pu': 'Plütonyum', 'Am': 'Amerikyum', 'Cm': 'Küriyum', 'Bk': 'Berkelyum',
3704
+ 'Cf': 'Kaliforniyum', 'Es': 'Einsteinyum', 'Fm': 'Fermiyum', 'Md': 'Mendelevyum',
3705
+ 'No': 'Nobelyum', 'Lr': 'Lawrensiyum', 'Rf': 'Rutherfordiyum', 'Db': 'Dubniyum',
3706
+ 'Sg': 'Seaborgiyum', 'Bh': 'Bohriyum', 'Hs': 'Hassiyum', 'Mt': 'Meitneriyum',
3707
+ 'Ds': 'Darmstadtiyum', 'Rg': 'Röntgenyum', 'Cn': 'Kopernikyum', 'Nh': 'Nihonyum',
3708
+ 'Fl': 'Flerovyum', 'Mc': 'Moscovyum', 'Lv': 'Livermoryum', 'Ts': 'Tenesin',
3709
+ 'Og': 'Oganesson/Oganesyan'
3710
+ }
3711
+
3712
+ for input_symbol in element_symbols:
3713
+ input_symbol_clean = str(input_symbol).strip()
3714
+ found = False
3715
+ for atomic_num, (sym, atomic_num_in_tuple) in periodic_elements.items():
3716
+ # Periyodik tablodaki sembol ile kullanıcının girdiği sembolü karşılaştır
3717
+ # Büyük/küçük harf duyarsız karşılaştırma
3718
+ if sym.upper() == input_symbol_clean.upper():
3719
+ highlight_indices.append(atomic_num - 1) # 0-based index
3720
+ # Orijinal sembolü (büyük/küçük harf korunarak) ekle
3721
+ element_symbols_found.append(sym) # Burada sym kullanıyoruz (periyodik tablodaki orijinal)
3722
+ valid_symbols.append(sym) # Orijinal sembolü sakla
3723
+ found = True
3724
+ break
3725
+
3726
+ if not found:
3727
+ print(f"Uyarı: '{input_symbol_clean}' elementi bulunamadı!")
3728
+
3729
+ if not highlight_indices:
3730
+ print("Vurgulanacak geçerli element bulunamadı!")
3731
+ return None, None
3732
+
3733
+ # Element isimlerini bul
3734
+ element_names = [element_name_map.get(sym, sym) for sym in element_symbols_found]
3735
+
3736
+ print(f"Vurgulanan elementler: {', '.join(element_names)}")
3737
+
3738
+ # Graf oluştur
3739
+ node_count = len(periodic_elements)
3740
+ G = nx.DiGraph()
3741
+ G.add_nodes_from(range(1, node_count + 1))
3742
+ for i in range(1, node_count):
3743
+ G.add_edge(i, i + 1)
3744
+
3745
+ # Özel renk şeması oluştur
3746
+ colors = []
3747
+ for i in range(1, node_count + 1):
3748
+ if (i - 1) in highlight_indices:
3749
+ colors.append(highlight_color)
3750
+ else:
3751
+ # Gri tonlarında diğer elementler
3752
+ colors.append((0.9, 0.9, 0.9))
3753
+
3754
+ # Layout tipini belirle
3755
+ layout_type = kwargs.get('layout_type', '3d_helix')
3756
+ dimension = '3d' if '3d' in layout_type.lower() else '2d'
3757
+
3758
+ # Figür oluştur
3759
+ if dimension == '3d':
3760
+ fig = plt.figure(figsize=(16, 16))
3761
+ ax = fig.add_subplot(111, projection='3d')
3762
+ else:
3763
+ fig = plt.figure(figsize=(14, 14))
3764
+ ax = fig.add_subplot(111)
3765
+
3766
+ # Layout hesapla
3767
+ layout_params = kwargs.get('layout_params', {})
3768
+ pos = _calculate_layout(G, layout_type, layout_params, dimension, node_count)
3769
+
3770
+ # Özel etiketler oluştur
3771
+ custom_labels = _generate_labels(G, periodic_elements)
3772
+
3773
+ # Node boyutlarını ayarla (vurgulananlar daha büyük)
3774
+ node_sizes = []
3775
+ for i in range(1, node_count + 1):
3776
+ if (i - 1) in highlight_indices:
3777
+ node_sizes.append(kwargs.get('highlight_size', 2000))
3778
+ else:
3779
+ node_sizes.append(kwargs.get('normal_size', 800))
3780
+
3781
+ # Font boyutlarını ayarla
3782
+ font_sizes = []
3783
+ for i in range(1, node_count + 1):
3784
+ if (i - 1) in highlight_indices:
3785
+ font_sizes.append(kwargs.get('highlight_font_size', 12))
3786
+ else:
3787
+ font_sizes.append(kwargs.get('normal_font_size', 7))
3788
+
3789
+ # Çizim sırasını belirle
3790
+ draw_order = _get_draw_order(G, pos, 'smart', dimension)
3791
+
3792
+ # Edge stilini al
3793
+ edge_config = _get_edge_config(kwargs.get('edge_style', 'light'))
3794
+
3795
+ # Çiz
3796
+ _draw_edges(G, pos, ax, edge_config, dimension)
3797
+ _draw_nodes(G, pos, colors, ax, node_sizes, draw_order, dimension,
3798
+ edge_width=kwargs.get('edge_width', 2.0),
3799
+ node_alpha=kwargs.get('node_alpha', 1.0))
3800
+
3801
+ # Etiketleri çiz
3802
+ _draw_labels(G, pos, custom_labels, colors, ax, font_sizes,
3803
+ kwargs.get('label_position', 'center'), dimension,
3804
+ label_offset=kwargs.get('label_offset', 0.0))
3805
+
3806
+ # Başlık
3807
+ title = kwargs.get('title')
3808
+ if title is None:
3809
+ # Orijinal sembolleri (büyük/küçük harf korunarak) kullan
3810
+ element_symbols_str = ', '.join(element_symbols_found)
3811
+ element_names_str = ', '.join(element_names)
3812
+ title = f"Keçeci Layout ile Vurgulanan Elementler\nHighlighted Elements with Keçeci Layout:\n: {element_names_str} ({element_symbols_str})\n"
3813
+ title += f"Layout: {layout_type}, Toplam/Total {node_count} Element"
3814
+
3815
+ ax.set_title(title, fontsize=18, fontweight='bold', pad=20)
3816
+
3817
+ # Eksen ayarları
3818
+ _configure_axes(ax, pos, dimension, layout_params,
3819
+ elevation=kwargs.get('elevation', -25),
3820
+ azimuth=kwargs.get('azimuth', 15))
3821
+
3822
+ plt.tight_layout()
3823
+
3824
+ # Açıklama ekle
3825
+ if dimension == '3d':
3826
+ ax.text2D(0.02, 0.98,
3827
+ f"Kırmızı: {', '.join(element_names)}\nGri: Diğer elementler",
3828
+ transform=ax.transAxes,
3829
+ fontsize=10, verticalalignment='top',
3830
+ bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
3831
+ else:
3832
+ ax.text(0.02, 0.98,
3833
+ f"Kırmızı: {', '.join(element_names)}\nGri: Diğer elementler",
3834
+ transform=ax.transAxes,
3835
+ fontsize=10, verticalalignment='top',
3836
+ bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
3837
+
3838
+ plt.show()
3839
+
3840
+ print(f"\nVurgulama tamamlandı!")
3841
+ print(f"Toplam {node_count} element, {len(highlight_indices)} element vurgulandı.")
3842
+ print("Grafı kapatmak için figür penceresini kapatın.")
3843
+
3844
+ return ax, pos
3845
+
3846
+ def demo_periodic_table_visualizations():
3847
+ """
3848
+ Periyodik tablo görselleştirmelerinin demo gösterimi.
3849
+ Her görsel ayrı ayrı gösterilir, boş şablonlar oluşmaz.
3850
+ """
3851
+ # Tüm figürleri temizle
3852
+ plt.close('all')
3853
+
3854
+ # Periyodik tabloyu yükle
3855
+ print("Periyodik tablo yükleniyor...")
3856
+ periodic_elements, _ = generate_complete_periodic_table()
3857
+
3858
+ # Graf oluştur
3859
+ node_count = len(periodic_elements)
3860
+ G = nx.DiGraph()
3861
+ G.add_nodes_from(range(1, node_count + 1))
3862
+ for i in range(1, node_count):
3863
+ G.add_edge(i, i + 1)
3864
+
3865
+ print("=" * 70)
3866
+ print("PERİYODİK TABLO GÖRSELLEŞTİRME DEMOLARI")
3867
+ print("=" * 70)
3868
+ print(f"Toplam {node_count} element gösterilecek.")
3869
+ print("Her görsel 5 saniye boyunca gösterilecek...")
3870
+
3871
+ demos = [
3872
+ {
3873
+ "name": "3D Heliks Layout",
3874
+ "layout_type": "3d_helix",
3875
+ "color_scheme": "vibrant",
3876
+ "params": {'z_spacing': 8.0, 'radius': 25.0, 'turns': 3.0},
3877
+ "figsize": (20, 20),
3878
+ "projection": '3d'
3879
+ },
3880
+ {
3881
+ "name": "2D Linear Layout",
3882
+ "layout_type": "2d_linear",
3883
+ "color_scheme": "group",
3884
+ "params": {'primary_spacing': 3.0, 'secondary_spacing': 3.0},
3885
+ "figsize": (16, 16),
3886
+ "projection": None
3887
+ },
3888
+ {
3889
+ "name": "2D Grid Layout",
3890
+ "layout_type": "2d_grid",
3891
+ "color_scheme": "period",
3892
+ "params": {'rows': 9, 'cols': 14, 'spacing': 3.0},
3893
+ "figsize": (18, 18),
3894
+ "projection": None
3895
+ },
3896
+ {
3897
+ "name": "2D Circular Layout",
3898
+ "layout_type": "2d_circular",
3899
+ "color_scheme": "block",
3900
+ "params": {'scale': 2.0},
3901
+ "figsize": (16, 16),
3902
+ "projection": None
3903
+ }
3904
+ ]
3905
+
3906
+ for i, demo in enumerate(demos, 1):
3907
+ print(f"\n{i}. {demo['name']} ({demo['color_scheme']} renkler) oluşturuluyor...")
3908
+
3909
+ if demo['projection'] == '3d':
3910
+ fig = plt.figure(figsize=demo['figsize'])
3911
+ ax = fig.add_subplot(111, projection='3d')
3912
+ else:
3913
+ fig = plt.figure(figsize=demo['figsize'])
3914
+ ax = fig.add_subplot(111)
3915
+
3916
+ ax, pos = draw_kececi_periodic_table(
3917
+ G,
3918
+ periodic_elements,
3919
+ layout_type=demo['layout_type'],
3920
+ layout_params=demo['params'],
3921
+ ax=ax,
3922
+ color_scheme=demo['color_scheme'],
3923
+ node_size=2000 if demo['projection'] == '3d' else 1000,
3924
+ font_size=10 if demo['projection'] == '3d' else 8,
3925
+ edge_style='light',
3926
+ show_legend=True if demo['color_scheme'] in ['group', 'period', 'block'] else False,
3927
+ title=f"Keçeci Layout ile\n {i}/4: {demo['name']}\n{demo['color_scheme'].capitalize()} Renk Şeması"
3928
+ )
3929
+
3930
+ plt.tight_layout()
3931
+ plt.show(block=False)
3932
+ plt.pause(5)
3933
+ plt.close(fig)
3934
+
3935
+ print("\n" + "=" * 70)
3936
+ print("TÜM DEMOLAR TAMAMLANDI!")
3937
+ print("=" * 70)
3938
+
3939
+ return True
3940
+
3941
+ def get_element_info(element_symbol: str) -> Dict[str, Any]:
3942
+ """
3943
+ Element sembolünden element bilgilerini getir.
3944
+
3945
+ Parameters:
3946
+ -----------
3947
+ element_symbol : str
3948
+ Element sembolü (örn: 'H', 'He', 'Fe')
3949
+
3950
+ Returns:
3951
+ --------
3952
+ dict : Element bilgileri
3953
+ """
3954
+ # Periyodik tabloyu yükle
3955
+ periodic_elements, element_dict = generate_complete_periodic_table()
3956
+
3957
+ # Element sembolünden atom numarasını bul
3958
+ atomic_num_found = None
3959
+ original_symbol = None
3960
+
3961
+ for atomic_num, (sym, atomic_num_in_tuple) in periodic_elements.items():
3962
+ if sym.upper() == element_symbol.upper():
3963
+ atomic_num_found = atomic_num
3964
+ original_symbol = sym # Orijinal sembolü sakla
3965
+ break
3966
+
3967
+ if atomic_num_found is None:
3968
+ raise ValueError(f"Element bulunamadı: {element_symbol}")
3969
+
3970
+ # Element ismini bul - Güncellenmiş Türkçe isimler
3971
+ element_name_map = {
3972
+ 'H': 'Hidrojen', 'He': 'Helyum', 'Li': 'Lityum', 'Be': 'Berilyum',
3973
+ 'B': 'Bor', 'C': 'Karbon', 'N': 'Azot', 'O': 'Oksijen', 'F': 'Flor',
3974
+ 'Ne': 'Neon', 'Na': 'Sodyum', 'Mg': 'Magnezyum', 'Al': 'Alüminyum',
3975
+ 'Si': 'Silisyum', 'P': 'Fosfor', 'S': 'Kükürt', 'Cl': 'Klor',
3976
+ 'Ar': 'Argon', 'K': 'Potasyum', 'Ca': 'Kalsiyum', 'Sc': 'Skandiyum',
3977
+ 'Ti': 'Titanyum', 'V': 'Vanadyum', 'Cr': 'Krom', 'Mn': 'Mangan',
3978
+ 'Fe': 'Demir', 'Co': 'Kobalt', 'Ni': 'Nikel', 'Cu': 'Bakır',
3979
+ 'Zn': 'Çinko', 'Ga': 'Galyum', 'Ge': 'Germanyum', 'As': 'Arsenik',
3980
+ 'Se': 'Selenyum', 'Br': 'Brom', 'Kr': 'Kripton', 'Rb': 'Rubidyum',
3981
+ 'Sr': 'Stronsiyum', 'Y': 'İtriyum', 'Zr': 'Zirkonyum', 'Nb': 'Niyobyum',
3982
+ 'Mo': 'Molibden', 'Tc': 'Teknesyum', 'Ru': 'Rutenyum', 'Rh': 'Rodyum',
3983
+ 'Pd': 'Paladyum', 'Ag': 'Gümüş', 'Cd': 'Kadmiyum', 'In': 'İndiyum',
3984
+ 'Sn': 'Kalay', 'Sb': 'Antimon', 'Te': 'Tellür', 'I': 'İyot',
3985
+ 'Xe': 'Ksenon', 'Cs': 'Sezyum', 'Ba': 'Baryum', 'La': 'Lantan',
3986
+ 'Ce': 'Seryum', 'Pr': 'Praseodim', 'Nd': 'Neodimyum', 'Pm': 'Prometyum',
3987
+ 'Sm': 'Samaryum', 'Eu': 'Europyum', 'Gd': 'Gadolinyum', 'Tb': 'Terbiyum',
3988
+ 'Dy': 'Disprozyum', 'Ho': 'Holmiyum', 'Er': 'Erbiyum', 'Tm': 'Tulyum',
3989
+ 'Yb': 'İterbiyum', 'Lu': 'Lutesyum', 'Hf': 'Hafniyum', 'Ta': 'Tantal',
3990
+ 'W': 'Tungsten', 'Re': 'Renyum', 'Os': 'Osmiyum', 'Ir': 'İridyum',
3991
+ 'Pt': 'Platin', 'Au': 'Altın', 'Hg': 'Cıva', 'Tl': 'Talyum',
3992
+ 'Pb': 'Kurşun', 'Bi': 'Bizmut', 'Po': 'Polonyum', 'At': 'Astatin',
3993
+ 'Rn': 'Radon', 'Fr': 'Fransiyum', 'Ra': 'Radyum', 'Ac': 'Aktinyum',
3994
+ 'Th': 'Toryum', 'Pa': 'Protaktinyum', 'U': 'Uranyum', 'Np': 'Neptünyum',
3995
+ 'Pu': 'Plütonyum', 'Am': 'Amerikyum', 'Cm': 'Küriyum', 'Bk': 'Berkelyum',
3996
+ 'Cf': 'Kaliforniyum', 'Es': 'Einsteinyum', 'Fm': 'Fermiyum', 'Md': 'Mendelevyum',
3997
+ 'No': 'Nobelyum', 'Lr': 'Lawrensiyum', 'Rf': 'Rutherfordiyum', 'Db': 'Dubniyum',
3998
+ 'Sg': 'Seaborgiyum', 'Bh': 'Bohriyum', 'Hs': 'Hassiyum', 'Mt': 'Meitneriyum',
3999
+ 'Ds': 'Darmstadtiyum', 'Rg': 'Röntgenyum', 'Cn': 'Kopernikyum', 'Nh': 'Nihonyum',
4000
+ 'Fl': 'Flerovyum', 'Mc': 'Moscovyum', 'Lv': 'Livermoryum', 'Ts': 'Tenesin',
4001
+ 'Og': 'Oganesson/Oganesyan'
4002
+ }
4003
+
4004
+ element_name = element_name_map.get(original_symbol.upper(), original_symbol)
4005
+
4006
+ # Yuri Oganessian hakkında ek bilgi
4007
+ additional_info = ""
4008
+ if original_symbol.upper() == 'OG':
4009
+ additional_info = "\n Not: Element, Rus-Armeni fizikçi Yuri Oganessian (Юрий Оганесян) onuruna adlandırılmıştır."
4010
+
4011
+ # Grup ve periyot bilgilerini hesapla
4012
+ group = _determine_group(atomic_num_found)
4013
+
4014
+ # Periyot hesapla
4015
+ if atomic_num_found <= 2:
4016
+ period = 1
4017
+ elif atomic_num_found <= 10:
4018
+ period = 2
4019
+ elif atomic_num_found <= 18:
4020
+ period = 3
4021
+ elif atomic_num_found <= 36:
4022
+ period = 4
4023
+ elif atomic_num_found <= 54:
4024
+ period = 5
4025
+ elif atomic_num_found <= 86:
4026
+ period = 6
4027
+ else:
4028
+ period = 7
4029
+
4030
+ # Blok bilgisi
4031
+ if atomic_num_found in [1, 2, 3, 4, 11, 12, 19, 20, 37, 38, 55, 56, 87, 88]:
4032
+ block = "s"
4033
+ elif atomic_num_found in (list(range(5, 11)) + list(range(13, 19)) +
4034
+ list(range(31, 37)) + list(range(49, 55)) +
4035
+ list(range(81, 87)) + list(range(113, 119))):
4036
+ block = "p"
4037
+ elif atomic_num_found in (list(range(21, 31)) + list(range(39, 49)) +
4038
+ list(range(72, 81)) + list(range(104, 113))):
4039
+ block = "d"
4040
+ elif atomic_num_found in list(range(57, 72)) + list(range(89, 104)):
4041
+ block = "f"
4042
+ else:
4043
+ block = "unknown"
4044
+
4045
+ # Elektronegativite verisi
4046
+ electronegativity_data = {
4047
+ 1: 2.20, 2: None, 3: 0.98, 4: 1.57, 5: 2.04, 6: 2.55, 7: 3.04, 8: 3.44,
4048
+ 9: 3.98, 10: None, 11: 0.93, 12: 1.31, 13: 1.61, 14: 1.90, 15: 2.19,
4049
+ 16: 2.58, 17: 3.16, 18: None, 19: 0.82, 20: 1.00, 21: 1.36, 22: 1.54,
4050
+ 23: 1.63, 24: 1.66, 25: 1.55, 26: 1.83, 27: 1.88, 28: 1.91, 29: 1.90,
4051
+ 30: 1.65, 31: 1.81, 32: 2.01, 33: 2.18, 34: 2.55, 35: 2.96, 36: None,
4052
+ 37: 0.82, 38: 0.95, 39: 1.22, 40: 1.33, 41: 1.60, 42: 2.16, 43: 1.90,
4053
+ 44: 2.20, 45: 2.28, 46: 2.20, 47: 1.93, 48: 1.69, 49: 1.78, 50: 1.96,
4054
+ 51: 2.05, 52: 2.10, 53: 2.66, 54: None, 55: 0.79, 56: 0.89, 57: 1.10,
4055
+ 58: 1.12, 59: 1.13, 60: 1.14, 61: 1.13, 62: 1.17, 63: 1.20, 64: 1.20,
4056
+ 65: 1.20, 66: 1.22, 67: 1.23, 68: 1.24, 69: 1.25, 70: 1.10, 71: 1.27,
4057
+ 72: 1.30, 73: 1.50, 74: 2.36, 75: 1.90, 76: 2.20, 77: 2.20, 78: 2.28,
4058
+ 79: 2.54, 80: 2.00, 81: 1.62, 82: 1.87, 83: 2.02, 84: 2.00, 85: 2.20,
4059
+ 86: None, 87: 0.70, 88: 0.89, 89: 1.10, 90: 1.30, 91: 1.50, 92: 1.38,
4060
+ 93: 1.36, 94: 1.28, 95: 1.30, 96: 1.30, 97: 1.30, 98: 1.30, 99: 1.30,
4061
+ 100: 1.30, 101: 1.30, 102: 1.30, 103: 1.30, 118: None # Oganesson
4062
+ }
4063
+
4064
+ result = {
4065
+ 'atomic_number': atomic_num_found,
4066
+ 'symbol': original_symbol, # Orijinal sembolü döndür
4067
+ 'name': element_name,
4068
+ 'group': group,
4069
+ 'period': period,
4070
+ 'block': block,
4071
+ 'electronegativity': electronegativity_data.get(atomic_num_found, None)
4072
+ }
4073
+
4074
+ # Ek bilgiyi de döndürelim
4075
+ result['additional_info'] = additional_info
4076
+
4077
+ return result
4078
+
4079
+ def custom_visualization():
4080
+ """
4081
+ Özelleştirilmiş görselleştirme menüsü.
4082
+ """
4083
+ print("\n" + "=" * 70)
4084
+ print("Custom Visualization")
4085
+ print("=" * 70)
4086
+
4087
+ # Periyodik tabloyu yükle
4088
+ periodic_elements, _ = generate_complete_periodic_table()
4089
+
4090
+ # Graf oluştur
4091
+ node_count = len(periodic_elements)
4092
+ G = nx.DiGraph()
4093
+ G.add_nodes_from(range(1, node_count + 1))
4094
+ for i in range(1, node_count):
4095
+ G.add_edge(i, i + 1)
4096
+
4097
+ # Layout seçenekleri
4098
+ layouts = {
4099
+ '1': ('3d_helix', '3D Heliks Layout'),
4100
+ '2': ('2d_linear', '2D Linear Layout'),
4101
+ '3': ('2d_grid', '2D Grid Layout'),
4102
+ '4': ('2d_circular', '2D Dairesel Layout'),
4103
+ '5': ('2d_spring', '2D Yay Layout')
4104
+ }
4105
+
4106
+ print("\nLayout Tipleri:")
4107
+ for key, (_, name) in layouts.items():
4108
+ print(f"{key}. {name}")
4109
+
4110
+ layout_choice = input("\nLayout tipi seçin (1-5): ").strip()
4111
+ if layout_choice not in layouts:
4112
+ print("Varsayılan olarak 3D Heliks seçildi.")
4113
+ layout_type = '3d_helix'
4114
+ else:
4115
+ layout_type, layout_name = layouts[layout_choice]
4116
+
4117
+ # Renk şeması seçenekleri
4118
+ color_schemes = {
4119
+ '1': 'vibrant',
4120
+ '2': 'distinct',
4121
+ '3': 'pastel',
4122
+ '4': 'group',
4123
+ '5': 'period',
4124
+ '6': 'block'
4125
+ }
4126
+
4127
+ print("\nRenk Şemaları:")
4128
+ print("1. Vibrant (Canlı renkler)")
4129
+ print("2. Distinct (Farklı renkler)")
4130
+ print("3. Pastel (Pastel tonlar)")
4131
+ print("4. Group (Gruplara göre)")
4132
+ print("5. Period (Periyotlara göre)")
4133
+ print("6. Block (Bloklara göre)")
4134
+
4135
+ color_choice = input("\nRenk şeması seçin (1-6): ").strip()
4136
+ if color_choice not in color_schemes:
4137
+ print("Varsayılan olarak Vibrant seçildi.")
4138
+ color_scheme = 'vibrant'
4139
+ else:
4140
+ color_scheme = color_schemes[color_choice]
4141
+
4142
+ # Boyut seçimi
4143
+ try:
4144
+ node_size = int(input(f"\nNode boyutu (varsayılan: 1600): ") or "1600")
4145
+ except:
4146
+ node_size = 1600
4147
+
4148
+ try:
4149
+ font_size = int(input(f"Font boyutu (varsayılan: 10): ") or "10")
4150
+ except:
4151
+ font_size = 10
4152
+
4153
+ # 3D için özel parametreler
4154
+ if '3d' in layout_type:
4155
+ fig = plt.figure(figsize=(20, 20))
4156
+ ax = fig.add_subplot(111, projection='3d')
4157
+ else:
4158
+ fig = plt.figure(figsize=(16, 16))
4159
+ ax = fig.add_subplot(111)
4160
+
4161
+ # Özel başlık
4162
+ custom_title = input("\nÖzel başlık (boş bırakırsanız otomatik oluşturulur): ").strip()
4163
+
4164
+ # Çizim yap
4165
+ ax, pos = draw_kececi_periodic_table(
4166
+ G,
4167
+ periodic_elements,
4168
+ layout_type=layout_type,
4169
+ ax=ax,
4170
+ color_scheme=color_scheme,
4171
+ node_size=node_size,
4172
+ font_size=font_size,
4173
+ title=custom_title if custom_title else None,
4174
+ show_legend=(color_scheme in ['group', 'period', 'block'])
4175
+ )
4176
+
4177
+ plt.tight_layout()
4178
+ plt.show()
4179
+
4180
+ print(f"\n{layout_name} ile {color_scheme} renk şeması başarıyla oluşturuldu!")
4181
+ return ax, pos
4182
+
4183
+ def debug_periodic_table_structure():
4184
+ """Periyodik tablo veri yapısını kontrol et."""
4185
+ print("Periyodik tablo veri yapısı kontrol ediliyor...")
4186
+ periodic_elements, _ = generate_complete_periodic_table()
4187
+
4188
+ print(f"\nToplam element sayısı: {len(periodic_elements)}")
4189
+
4190
+ # İlk 5 elementi göster
4191
+ print("\nİlk 5 element:")
4192
+ for i, (atomic_num, value) in enumerate(list(periodic_elements.items())[:5]):
4193
+ print(f" Atom numarası {atomic_num}:")
4194
+ print(f" Değer: {value}")
4195
+ print(f" Tip: {type(value)}")
4196
+
4197
+ if isinstance(value, tuple):
4198
+ print(f" Tuple uzunluğu: {len(value)}")
4199
+ for j, item in enumerate(value):
4200
+ print(f" Item {j}: {item} (tip: {type(item)})")
4201
+
4202
+ # Rastgele bir element kontrolü
4203
+ print("\nRastgele element kontrolü (atom numarası 26 - Demir):")
4204
+ if 26 in periodic_elements:
4205
+ value = periodic_elements[26]
4206
+ print(f" Değer: {value}")
4207
+ print(f" Tip: {type(value)}")
4208
+ if isinstance(value, tuple) and len(value) >= 2:
4209
+ print(f" Sembol: {value[0]}")
4210
+ print(f" İsim: {value[1]}")
4211
+
4212
+ def _generate_labels(graph, periodic_elements):
4213
+ """Etiketleri oluştur."""
4214
+ labels = {}
4215
+ for node_id in graph.nodes():
4216
+ if node_id in periodic_elements:
4217
+ sym, atomic_num = periodic_elements[node_id]
4218
+ # Etiket formatı: Sembol\nAtom Numarası
4219
+ labels[node_id] = f"{sym}\n{atomic_num}"
4220
+ else:
4221
+ labels[node_id] = str(node_id)
4222
+ return labels
4223
+
4224
+ # =============================================================================
4225
+ # MODULE TEST CODE
4226
+ # =============================================================================
4227
+
4228
+ if __name__ == '__main__':
4229
+ print("Testing kececilayout.py module...")
4230
+ G_test = nx.gnp_random_graph(12, 0.3, seed=42)
4231
+
4232
+ # graph-tool grafi oluşturma ve test etme
4233
+ if gt:
4234
+ g = gt.Graph()
4235
+ g.add_vertex(12)
4236
+ for u, v in G_test.edges():
4237
+ g.add_edge(g.vertex(u), g.vertex(v))
4238
+ fig_gt = plt.figure(figsize=(10, 8))
4239
+ draw_kececi(g, ax=fig_gt.add_subplot(111), style='curved')
4240
+ plt.title("Keçeci Layout: graph-tool Graph")
2511
4241
  plt.show()
2512
4242
 
2513
4243
  # Compare expanding=False (parallel) vs. expanding=True ('v4' style)
@@ -2536,13 +4266,3 @@ if __name__ == '__main__':
2536
4266
  draw_kececi(G_test, style='3d', ax=fig_styles.add_subplot(2, 2, (3, 4), projection='3d'))
2537
4267
  plt.tight_layout(rect=[0, 0, 1, 0.96])
2538
4268
  plt.show()
2539
-
2540
-
2541
-
2542
-
2543
-
2544
-
2545
-
2546
-
2547
-
2548
-