kececilayout 0.5.9__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
@@ -2843,6 +2846,1381 @@ def draw_kececi(graph, style='curved', ax=None, **kwargs):
2843
2846
  return ax
2844
2847
  """
2845
2848
 
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
+
2846
4224
  # =============================================================================
2847
4225
  # MODULE TEST CODE
2848
4226
  # =============================================================================
@@ -2888,14 +4266,3 @@ if __name__ == '__main__':
2888
4266
  draw_kececi(G_test, style='3d', ax=fig_styles.add_subplot(2, 2, (3, 4), projection='3d'))
2889
4267
  plt.tight_layout(rect=[0, 0, 1, 0.96])
2890
4268
  plt.show()
2891
-
2892
-
2893
-
2894
-
2895
-
2896
-
2897
-
2898
-
2899
-
2900
-
2901
-