kececilayout 0.5.0__py3-none-any.whl → 0.5.1__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.
docs/conf.py ADDED
@@ -0,0 +1,97 @@
1
+ # Configuration file for the Sphinx documentation builder.
2
+ import os
3
+ import sys
4
+
5
+ # Proje kök dizinini Python yoluna ekle (kececilayout'u bulmak için)
6
+ sys.path.insert(0, os.path.abspath('..'))
7
+
8
+ # Proje Bilgileri
9
+ project = 'kececilayout'
10
+ copyright = '2025, Mehmet Keçeci'
11
+ author = 'Mehmet Keçeci'
12
+
13
+ # Sürüm Bilgisi (setuptools_scm kullanmıyorsanız sabit olarak tanımlayın)
14
+ # Gerçek sürümü modülden al (eğer mümkünse)
15
+ try:
16
+ from kececilayout import __version__
17
+ version = __version__
18
+ release = __version__
19
+ except (ImportError, AttributeError) as e:
20
+ print(f"Warning: Could not import __version__ from kececilayout: {e}")
21
+ # Varsayılan değerler korunur
22
+ # version = '0.2.7' # Geliştirme sürümü
23
+ # release = '0.2.7' # Yayın sürümü
24
+
25
+ # Ana belge
26
+ master_doc = 'index'
27
+
28
+ # Sphinx Uzantıları
29
+ extensions = [
30
+ 'sphinx.ext.autodoc',
31
+ 'sphinx.ext.viewcode', # "Show Source" linki
32
+ 'sphinx.ext.napoleon', # Google/NumPy docstring desteği
33
+ 'sphinx.ext.intersphinx', # Dış belgelere link (ör: Python, NetworkX)
34
+ 'sphinx.ext.autosummary', # Otomatik özet tabloları
35
+ 'sphinx_rtd_theme', # Read the Docs teması
36
+ ]
37
+
38
+ # Otomatik Özet (autosummary)
39
+ autosummary_generate = True
40
+ autodoc_default_options = {
41
+ 'members': True,
42
+ 'undoc-members': True,
43
+ 'show-inheritance': True,
44
+ 'special-members': '__init__',
45
+ 'exclude-members': '__weakref__'
46
+ }
47
+
48
+ # Mock Imports — RTD'de kurulamayan modülleri taklit et
49
+ autodoc_mock_imports = [
50
+ "igraph",
51
+ "networkit",
52
+ "rustworkx",
53
+ "graphillion",
54
+ "itertools", # Bu aslında stdlib ama bazen sorun çıkarabilir
55
+ ]
56
+
57
+ # Dış Belge Linkleri (intersphinx)
58
+ intersphinx_mapping = {
59
+ 'python': ('https://docs.python.org/3', None),
60
+ 'networkx': ('https://networkx.org/documentation/stable/', None),
61
+ 'matplotlib': ('https://matplotlib.org/stable/', None),
62
+ 'numpy': ('https://numpy.org/doc/stable/', None),
63
+ }
64
+
65
+ # Hariç Tutulan Dosyalar
66
+ exclude_patterns = [
67
+ '_build',
68
+ 'Thumbs.db',
69
+ '.DS_Store',
70
+ '**/.ipynb_checkpoints',
71
+ 'README.md' # HTML'e çevrilmemesi için
72
+ ]
73
+
74
+ # HTML Ayarları
75
+ html_theme = 'sphinx_rtd_theme'
76
+ html_static_path = ['_static']
77
+ html_logo = '_static/logo.png' # Opsiyonel: logo
78
+ html_favicon = '_static/favicon.ico' # Opsiyonel: favicon
79
+ html_title = "KeçeciLayout Docs"
80
+
81
+ # HTML Tema Seçenekleri
82
+ html_theme_options = {
83
+ 'navigation_depth': 4,
84
+ 'collapse_navigation': False,
85
+ 'sticky_navigation': True,
86
+ 'logo_only': True,
87
+ 'display_version': True,
88
+ 'prev_next_buttons_location': 'bottom',
89
+ }
90
+
91
+ # -- Extra: Eğer kececilayout içinde sürüm varsa, onu kullan (opsiyonel) --
92
+ # try:
93
+ # from kececilayout import __version__
94
+ # version = __version__
95
+ # release = __version__
96
+ # except (ImportError, AttributeError):
97
+ # pass
kececilayout/__init__.py CHANGED
@@ -10,7 +10,7 @@ import inspect
10
10
  import warnings
11
11
 
12
12
  # Paket sürüm numarası
13
- __version__ = "0.5.0"
13
+ __version__ = "0.5.1"
14
14
 
15
15
  # =============================================================================
16
16
  # OTOMATİK İÇE AKTARMA VE __all__ OLUŞTURMA
@@ -58,6 +58,10 @@ from .kececi_layout import ( # Veya fonksiyonların bulunduğu asıl modül
58
58
  kececi_layout_toric,
59
59
  draw_kececi_weighted,
60
60
  draw_kececi_colored,
61
+ kececi_layout_edge,
62
+ _compute_positions,
63
+ _extract_graph_data,
64
+ _validate_directions,
61
65
 
62
66
  # Drawing functions
63
67
  draw_kececi,
@@ -107,6 +111,10 @@ __all__ = [
107
111
  'kececi_layout_toric',
108
112
  'draw_kececi_weighted',
109
113
  'draw_kececi_colored',
114
+ 'kececi_layout_edge',
115
+ '_compute_positions',
116
+ '_extract_graph_data',
117
+ '_validate_directions',
110
118
 
111
119
  # Drawing functions
112
120
  'draw_kececi',
@@ -157,3 +165,4 @@ def old_function_placeholder():
157
165
 
158
166
  # Eğer bu eski fonksiyonu da dışa aktarmak istiyorsanız, __all__ listesine ekleyin
159
167
  # __all__.append('old_function_placeholder')
168
+
kececilayout/_version.py CHANGED
@@ -1,9 +1,10 @@
1
1
  # _version.py
2
2
 
3
3
  __version__ = "0.5.0"
4
- __license__ = "MIT"
4
+ __license__ = "AGPL3.0-or-later"
5
5
  __description__ = "A deterministic node placement algorithm used in graph visualization. In this layout, nodes are arranged sequentially along a defined primary axis. Each subsequent node is then alternately offset along a secondary, perpendicular axis, typically moving to one side of the primary axis and then the other. Often, the magnitude of this secondary offset increases as nodes progress along the primary axis, creating a characteristic zig-zag or serpentine pattern."
6
6
  __author__ = "Mehmet Keçeci"
7
7
  __url__ = "https://github.com/WhiteSymmetry/kececilayout"
8
8
  __docs__ = "https://github.com/WhiteSymmetry/kececilayout" # Opsiyonel: Dokümantasyon linki
9
- __dependencies__ = ["python>=3.10"] # Diğer bağımlılıkları da ekleyebilirsiniz
9
+ __dependencies__ = ["python>=3.11"] # Diğer bağımlılıkları da ekleyebilirsiniz
10
+
@@ -5,8 +5,25 @@ kececilayout.py
5
5
 
6
6
  This module provides sequential-zigzag ("Keçeci Layout") and advanced visualization styles for various Python graph libraries.
7
7
  Bu modül, çeşitli Python graf kütüphaneleri için sıralı-zigzag ("Keçeci Layout") ve gelişmiş görselleştirme stilleri sağlar.
8
+
9
+ **Key Features:**
10
+ * **Linear Focus:** Ideal for visualizing paths, chains, or ordered processes.
11
+ * **Deterministic:** Produces identical results for the same input.
12
+ * **Overlap Reduction:** Prevents node collisions by spreading them across axes.
13
+ * **Parametric:** Fully customizable with parameters like `primary_spacing`, `secondary_spacing`, `primary_direction`, and `secondary_start`.
14
+
15
+ **v0.2.7**: Curved, transparent, 3D, and `expanding=True` styles supported.
16
+
17
+ **v0.5.0:**
18
+
19
+ layouts = ['2d', 'cylindrical', 'cubic', 'spherical', 'elliptical', 'toric']
20
+
21
+ styles = ['standard', 'default', 'curved', 'helix', '3d', 'weighted', 'colored']
22
+
23
+ **v0.5.1:** edge (kececi_layout_edge)
8
24
  """
9
25
 
26
+ from collections import defaultdict
10
27
  import graphillion as gg
11
28
  import igraph as ig
12
29
  import itertools # Graphillion için eklendi
@@ -245,12 +262,104 @@ def kececi_layout(graph, primary_spacing=1.0, secondary_spacing=1.0,
245
262
  pos[node_id] = (x, y)
246
263
  return pos
247
264
 
265
+ def kececi_layout_edge(graph: Any,
266
+ primary_spacing: float = 1.0,
267
+ secondary_spacing: float = 1.0,
268
+ primary_direction: str = 'top_down',
269
+ secondary_start: str = 'right',
270
+ expanding: bool = True,
271
+ edge: bool = True) -> Dict[Any, Tuple[float, float]]:
272
+ """Deterministik O(n) layout — edge farkındalıklı mod ile."""
273
+ nodes, edges = _extract_graph_data(graph)
274
+ _validate_directions(primary_direction, secondary_start)
275
+
276
+ if edge and edges:
277
+ degree = defaultdict(int)
278
+ for u, v in edges:
279
+ degree[u] += 1
280
+ degree[v] += 1
281
+ nodes = sorted(nodes, key=lambda n: (-degree.get(n, 0), str(n)))
282
+
283
+ return _compute_positions(
284
+ nodes, primary_spacing, secondary_spacing,
285
+ primary_direction, secondary_start, expanding
286
+ )
287
+
288
+ def _validate_directions(pd: str, ss: str) -> None:
289
+ VERTICAL = {'top_down', 'bottom_up'}
290
+ HORIZONTAL = {'left-to-right', 'right-to-left'}
291
+
292
+ if pd in VERTICAL and ss not in {'left', 'right'}:
293
+ raise ValueError(
294
+ f"Invalid secondary_start '{ss}' for vertical direction '{pd}'\n"
295
+ f"✓ Use: 'left' or 'right' (e.g., secondary_start='right')"
296
+ )
297
+ if pd in HORIZONTAL and ss not in {'up', 'down'}:
298
+ raise ValueError(
299
+ f"Invalid secondary_start '{ss}' for horizontal direction '{pd}'\n"
300
+ f"✓ Use: 'up' or 'down' (e.g., secondary_start='up')"
301
+ )
302
+ if pd not in VERTICAL and pd not in HORIZONTAL:
303
+ raise ValueError(f"Invalid primary_direction: '{pd}'")
304
+
305
+ def _extract_graph_data(graph: Any) -> Tuple[List[Any], List[Tuple[Any, Any]]]:
306
+ # Rustworkx
307
+ try:
308
+ import rustworkx as rx
309
+ if isinstance(graph, (rx.PyGraph, rx.PyDiGraph)):
310
+ nodes = sorted(int(u) for u in graph.node_indices())
311
+ edges = [(int(u), int(v)) for u, v in graph.edge_list()]
312
+ return nodes, edges
313
+ except (ImportError, AttributeError, NameError):
314
+ pass
315
+
316
+ # NetworkX (fallback)
317
+ try:
318
+ import networkx as nx
319
+ if isinstance(graph, (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)):
320
+ try:
321
+ nodes = sorted(graph.nodes())
322
+ except TypeError:
323
+ nodes = list(graph.nodes())
324
+ edges = [(u, v) for u, v in graph.edges()]
325
+ return nodes, edges
326
+ except (ImportError, AttributeError, NameError):
327
+ pass
328
+
329
+ raise TypeError(
330
+ f"Unsupported graph type: {type(graph).__name__}\n"
331
+ "Supported: NetworkX, Rustworkx"
332
+ )
333
+
334
+ def _compute_positions(nodes: List[Any],
335
+ ps: float, ss: float,
336
+ pd: str, sc: str, exp: bool) -> Dict[Any, Tuple[float, float]]:
337
+ pos = {}
338
+ for i, node in enumerate(nodes):
339
+ if pd == 'top_down':
340
+ pc, sa = i * -ps, 'x'
341
+ elif pd == 'bottom_up':
342
+ pc, sa = i * ps, 'x'
343
+ elif pd == 'left-to-right':
344
+ pc, sa = i * ps, 'y'
345
+ else: # right-to-left
346
+ pc, sa = i * -ps, 'y'
347
+
348
+ so = 0.0
349
+ if i > 0:
350
+ sm = 1.0 if sc in {'right', 'up'} else -1.0
351
+ mag = math.ceil(i / 2.0) if exp else 1.0
352
+ side = 1 if i % 2 else -1
353
+ so = sm * mag * side * ss
354
+
355
+ pos[node] = (so, pc) if sa == 'x' else (pc, so)
356
+ return pos
357
+
248
358
  # =============================================================================
249
359
  # 1. TEMEL LAYOUT HESAPLAMA FONKSİYONU (2D)
250
360
  # Bu fonksiyon sadece koordinatları hesaplar, çizim yapmaz.
251
361
  # 1. LAYOUT CALCULATION FUNCTION (UNIFIED AND IMPROVED)
252
362
  # =============================================================================
253
-
254
363
  def kececi_layout_v4(graph, primary_spacing=1.0, secondary_spacing=1.0,
255
364
  primary_direction='top_down', secondary_start='right',
256
365
  expanding=True):
@@ -343,7 +452,7 @@ def kececi_layout_nx(graph, primary_spacing=1.0, secondary_spacing=1.0,
343
452
  primary_direction (str): 'top_down', 'bottom_up', 'left-to-right', 'right-to-left'.
344
453
  secondary_start (str): Initial direction for the zigzag offset.
345
454
  expanding (bool): If True (default), the zigzag offset grows.
346
- If False, the offset is constant (parallel lines). # <-- 2. DOKÜMANTASYON GÜNCELLENDİ
455
+ If False, the offset is constant (parallel lines).
347
456
 
348
457
  Returns:
349
458
  dict: A dictionary of positions keyed by node ID.
@@ -402,7 +511,7 @@ def kececi_layout_networkx(graph, primary_spacing=1.0, secondary_spacing=1.0,
402
511
  primary_direction (str): 'top_down', 'bottom_up', 'left-to-right', 'right-to-left'.
403
512
  secondary_start (str): Initial direction for the zigzag offset.
404
513
  expanding (bool): If True (default), the zigzag offset grows.
405
- If False, the offset is constant (parallel lines). # <-- 2. DOKÜMANTASYON GÜNCELLENDİ
514
+ If False, the offset is constant (parallel lines).
406
515
 
407
516
  Returns:
408
517
  dict: A dictionary of positions keyed by node ID.
@@ -2075,3 +2184,6 @@ if __name__ == '__main__':
2075
2184
  draw_kececi(G_test, style='3d', ax=fig_styles.add_subplot(2, 2, (3, 4), projection='3d'))
2076
2185
  plt.tight_layout(rect=[0, 0, 1, 0.96])
2077
2186
  plt.show()
2187
+
2188
+
2189
+