kececilayout 0.2.5__tar.gz → 0.2.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kececilayout
3
- Version: 0.2.5
3
+ Version: 0.2.7
4
4
  Summary: 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.
5
5
  Home-page: https://github.com/WhiteSymmetry/kececilayout
6
6
  Author: Mehmet Keçeci
@@ -41,9 +41,9 @@ Dynamic: summary
41
41
  [![PyPI version](https://badge.fury.io/py/kececilayout.svg)](https://badge.fury.io/py/kececilayout)
42
42
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
43
43
 
44
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15313946.svg)](https://doi.org/10.5281/zenodo.15313946)
45
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15314329.svg)](https://doi.org/10.5281/zenodo.15314329)
46
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15353535.svg)](https://doi.org/10.5281/zenodo.15353535)
44
+ [![Zenodo DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15313946.svg)](https://doi.org/10.5281/zenodo.15313946)
45
+ [![Zenodo DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15314328.svg)](https://doi.org/10.5281/zenodo.15314328)
46
+ [![Zenodo DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15353535.svg)](https://doi.org/10.5281/zenodo.15353535)
47
47
 
48
48
  [![WorkflowHub DOI](https://img.shields.io/badge/DOI-10.48546%2Fworkflowhub.datafile.17.1-blue)](https://doi.org/10.48546/workflowhub.datafile.17.1)
49
49
 
@@ -67,6 +67,10 @@ Dynamic: summary
67
67
  [![CI/CD](https://github.com/WhiteSymmetry/kececilayout/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/WhiteSymmetry/kececilayout/actions/workflows/ci-cd.yml)
68
68
  [![Linted with Ruff](https://img.shields.io/badge/Linted%20with-Ruff-green?logo=python&logoColor=white)](https://github.com/astral-sh/ruff)
69
69
 
70
+ | **Documentation**| **Paper**|
71
+ |:----------------:|:--------:|
72
+ |[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://whitesymmetry.github.io/kececilayout/)|[![Zenodo](https://zenodo.org/badge/DOI/10.5281/zenodo.15314328.svg)](https://doi.org/10.5281/zenodo.15314328)|
73
+
70
74
  ---
71
75
 
72
76
  <p align="left">
@@ -120,6 +124,8 @@ This algorithm arranges nodes sequentially along a primary axis and offsets them
120
124
 
121
125
  *Bu algoritma, düğümleri birincil eksen boyunca sıralı olarak yerleştirir ve ikincil eksen boyunca dönüşümlü olarak kaydırır. Yol grafları, zincirler veya ilerlemeyi göstermek için özellikle kullanışlıdır.*
122
126
 
127
+ => 0.2.6: Curved, transparent, 3d, expanding=True
128
+
123
129
  ---
124
130
 
125
131
  ### English Description
@@ -808,7 +814,9 @@ Keçeci, Mehmet. kececilayout [Data set]. WorkflowHub, 2025. https://doi.org/10.
808
814
 
809
815
  Keçeci, Mehmet. "Kececilayout". Open Science Articles (OSAs), Zenodo, 2025. https://doi.org/10.5281/zenodo.15313946.
810
816
 
811
- Keçeci, Mehmet. "Keçeci Layout". Open Science Articles (OSAs), Zenodo, 2025. https://doi.org/10.5281/zenodo.15314329.
817
+ Keçeci, Mehmet. "Keçeci Layout". Open Science Articles (OSAs), Zenodo, 2025. https://doi.org/10.5281/zenodo.15314328.
812
818
  ```
813
819
 
814
820
 
821
+
822
+
@@ -3,9 +3,9 @@
3
3
  [![PyPI version](https://badge.fury.io/py/kececilayout.svg)](https://badge.fury.io/py/kececilayout)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15313946.svg)](https://doi.org/10.5281/zenodo.15313946)
7
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15314329.svg)](https://doi.org/10.5281/zenodo.15314329)
8
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15353535.svg)](https://doi.org/10.5281/zenodo.15353535)
6
+ [![Zenodo DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15313946.svg)](https://doi.org/10.5281/zenodo.15313946)
7
+ [![Zenodo DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15314328.svg)](https://doi.org/10.5281/zenodo.15314328)
8
+ [![Zenodo DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15353535.svg)](https://doi.org/10.5281/zenodo.15353535)
9
9
 
10
10
  [![WorkflowHub DOI](https://img.shields.io/badge/DOI-10.48546%2Fworkflowhub.datafile.17.1-blue)](https://doi.org/10.48546/workflowhub.datafile.17.1)
11
11
 
@@ -29,6 +29,10 @@
29
29
  [![CI/CD](https://github.com/WhiteSymmetry/kececilayout/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/WhiteSymmetry/kececilayout/actions/workflows/ci-cd.yml)
30
30
  [![Linted with Ruff](https://img.shields.io/badge/Linted%20with-Ruff-green?logo=python&logoColor=white)](https://github.com/astral-sh/ruff)
31
31
 
32
+ | **Documentation**| **Paper**|
33
+ |:----------------:|:--------:|
34
+ |[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://whitesymmetry.github.io/kececilayout/)|[![Zenodo](https://zenodo.org/badge/DOI/10.5281/zenodo.15314328.svg)](https://doi.org/10.5281/zenodo.15314328)|
35
+
32
36
  ---
33
37
 
34
38
  <p align="left">
@@ -82,6 +86,8 @@ This algorithm arranges nodes sequentially along a primary axis and offsets them
82
86
 
83
87
  *Bu algoritma, düğümleri birincil eksen boyunca sıralı olarak yerleştirir ve ikincil eksen boyunca dönüşümlü olarak kaydırır. Yol grafları, zincirler veya ilerlemeyi göstermek için özellikle kullanışlıdır.*
84
88
 
89
+ => 0.2.6: Curved, transparent, 3d, expanding=True
90
+
85
91
  ---
86
92
 
87
93
  ### English Description
@@ -770,7 +776,9 @@ Keçeci, Mehmet. kececilayout [Data set]. WorkflowHub, 2025. https://doi.org/10.
770
776
 
771
777
  Keçeci, Mehmet. "Kececilayout". Open Science Articles (OSAs), Zenodo, 2025. https://doi.org/10.5281/zenodo.15313946.
772
778
 
773
- Keçeci, Mehmet. "Keçeci Layout". Open Science Articles (OSAs), Zenodo, 2025. https://doi.org/10.5281/zenodo.15314329.
779
+ Keçeci, Mehmet. "Keçeci Layout". Open Science Articles (OSAs), Zenodo, 2025. https://doi.org/10.5281/zenodo.15314328.
774
780
  ```
775
781
 
776
782
 
783
+
784
+
@@ -0,0 +1,60 @@
1
+ # __init__.py
2
+
3
+ """
4
+ kececilayout - A Python package for sequential-zigzag graph layouts
5
+ and advanced visualizations compatible with multiple graph libraries.
6
+ """
7
+
8
+ from __future__ import annotations
9
+ import inspect
10
+ import warnings
11
+
12
+ # Paket sürüm numarası
13
+ __version__ = "0.2.7"
14
+
15
+ # =============================================================================
16
+ # OTOMATİK İÇE AKTARMA VE __all__ OLUŞTURMA
17
+ # Bu bölüm, yeni fonksiyon eklediğinizde elle güncelleme yapma
18
+ # ihtiyacını ortadan kaldırır.
19
+ # =============================================================================
20
+
21
+ # Ana modülümüzü içe aktarıyoruz
22
+ from . import kececi_layout
23
+
24
+ # __all__ listesini dinamik olarak dolduracağız
25
+ __all__ = []
26
+
27
+ # kececi_layout modülünün içindeki tüm üyelere (fonksiyonlar, sınıflar vb.) bak
28
+ for name, member in inspect.getmembers(kececi_layout):
29
+ # Eğer üye bir fonksiyonsa VE adı '_' ile başlamıyorsa (yani public ise)
30
+ if inspect.isfunction(member) and not name.startswith('_'):
31
+ # Onu paketin ana seviyesine taşı (örn: kl.draw_kececi)
32
+ globals()[name] = member
33
+ # Ve dışa aktarılacaklar listesine ekle
34
+ __all__.append(name)
35
+
36
+ # Temizlik: Döngüde kullanılan geçici değişkenleri sil
37
+ del inspect, name, member
38
+
39
+ # =============================================================================
40
+ # GERİYE DÖNÜK UYUMLULUK VE UYARILAR
41
+ # =============================================================================
42
+
43
+ def old_function_placeholder():
44
+ """
45
+ This is an old function scheduled for removal.
46
+ Please use alternative functions.
47
+ """
48
+ warnings.warn(
49
+ (
50
+ "old_function_placeholder() is deprecated and will be removed in a future version. "
51
+ "Please use the new alternative functions. "
52
+ "Keçeci Layout should work smoothly on Python 3.7-3.14."
53
+ ),
54
+ category=DeprecationWarning,
55
+ stacklevel=2
56
+ )
57
+
58
+ # Eğer bu eski fonksiyonu da dışa aktarmak istiyorsanız, __all__ listesine ekleyin
59
+ # __all__.append('old_function_placeholder')
60
+
@@ -1,6 +1,6 @@
1
1
  # _version.py
2
2
 
3
- __version__ = "0.2.5"
3
+ __version__ = "0.2.7"
4
4
  __license__ = "MIT"
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"
@@ -1,21 +1,37 @@
1
- # kececilayout/kececi_layout.py
1
+ # -*- coding: utf-8 -*-
2
+ # ruff: noqa: N806, N815
3
+ """
4
+ kececilayout.py
2
5
 
6
+ Bu modül, çeşitli Python graf kütüphaneleri için sıralı-zigzag ("Keçeci Layout")
7
+ ve gelişmiş görselleştirme stilleri sağlar.
8
+ """
9
+
10
+ import graphillion as gg
11
+ import igraph as ig
3
12
  import itertools # Graphillion için eklendi
4
- import numpy as np # rustworkx
5
13
  import math
6
- import networkx as nx
7
- import rustworkx as rx
8
- import igraph as ig
14
+ import matplotlib.pyplot as plt
15
+ from mpl_toolkits.mplot3d import Axes3D
9
16
  import networkit as nk
10
- import graphillion as gg
17
+ import networkx as nx
18
+ import numpy as np # rustworkx
11
19
  import random
20
+ import rustworkx as rx
21
+ import warnings
12
22
 
13
23
 
14
- # Gerekli olabilecek kütüphane importları (type hinting veya isinstance için)
24
+ # Ana bağımlılıklar (çizim için gerekli)
15
25
  try:
16
26
  import networkx as nx
17
- except ImportError:
18
- nx = None # Yoksa None ata
27
+ #from mpl_toolkits.mplot3d import Axes3D
28
+ except ImportError as e:
29
+ raise ImportError(
30
+ "Bu modülün çalışması için 'networkx' ve 'matplotlib' gereklidir. "
31
+ "Lütfen `pip install networkx matplotlib` ile kurun."
32
+ ) from e
33
+
34
+ # Opsiyonel graf kütüphaneleri
19
35
  try:
20
36
  import rustworkx as rx
21
37
  except ImportError:
@@ -29,10 +45,11 @@ try:
29
45
  except ImportError:
30
46
  nk = None
31
47
  try:
32
- import graphillion as gg # Graphillion importu eklendi
48
+ import graphillion as gg
33
49
  except ImportError:
34
50
  gg = None
35
51
 
52
+
36
53
  def find_max_node_id(edges):
37
54
  """Verilen kenar listesindeki en büyük düğüm ID'sini bulur."""
38
55
  if not edges:
@@ -45,270 +62,160 @@ def find_max_node_id(edges):
45
62
  print("Uyarı: Kenar formatı beklenenden farklı, max node ID 0 varsayıldı.")
46
63
  return 0
47
64
 
48
- def kececi_layout_v4(graph, primary_spacing=1.0, secondary_spacing=1.0,
49
- primary_direction='top-down', secondary_start='right'):
50
- """
51
- Keçeci Layout v4 - Graf düğümlerine sıralı-zigzag yerleşimi sağlar.
52
- NetworkX, Rustworkx, igraph, Networkit ve Graphillion grafikleriyle çalışır.
53
65
 
54
- Parametreler:
55
- -------------
56
- graph : Kütüphaneye özel graf nesnesi
57
- NetworkX, Rustworkx, igraph, Networkit veya Graphillion nesnesi.
58
- Graphillion için bir GraphSet nesnesi beklenir.
59
- ... (diğer parametreler) ...
60
-
61
- Dönüş:
62
- ------
63
- dict[node_identifier, tuple[float, float]]
64
- Her düğümün koordinatını içeren sözlük. Anahtarlar kütüphaneye
65
- göre değişir (NX: node obj/id, RW/NK/igraph: int index, GG: 1-based int index).
66
+ def kececi_layout(graph, primary_spacing=1.0, secondary_spacing=1.0,
67
+ primary_direction='top_down', secondary_start='right',
68
+ expanding=True):
66
69
  """
70
+ Calculates 2D sequential-zigzag coordinates for the nodes of a graph.
67
71
 
68
- nodes = None
69
-
70
- # Kütüphane Tespiti ve Düğüm Listesi Çıkarımı
71
- # isinstance kullanmak hasattr'dan daha güvenilirdir.
72
- # Önce daha spesifik tipleri kontrol etmek iyi olabilir.
72
+ This function is compatible with graphs from NetworkX, Rustworkx, igraph,
73
+ Networkit, and Graphillion.
73
74
 
74
- if gg and isinstance(graph, gg.GraphSet): # Graphillion kontrolü EKLENDİ
75
- edges = graph.universe()
76
- max_node_id = find_max_node_id(edges)
77
- if max_node_id > 0:
78
- nodes = list(range(1, max_node_id + 1)) # 1-tabanlı indeksleme
79
- else:
80
- nodes = [] # Boş evren
81
- print(f"DEBUG: Graphillion tespit edildi. Düğümler (1..{max_node_id}): {nodes[:10]}...") # Debug mesajı
82
-
83
- elif ig and isinstance(graph, ig.Graph): # igraph
84
- nodes = sorted([v.index for v in graph.vs]) # 0-tabanlı indeksleme
85
- print(f"DEBUG: igraph tespit edildi. Düğümler (0..{len(nodes)-1}): {nodes[:10]}...")
86
-
87
- elif nk and isinstance(graph, nk.graph.Graph): # Networkit
88
- try:
89
- # iterNodes genellikle 0..N-1 verir ama garanti değil
90
- nodes = sorted(list(graph.iterNodes()))
91
- except Exception:
92
- nodes = list(range(graph.numberOfNodes()))
93
- print(f"DEBUG: Networkit tespit edildi. Düğümler: {nodes[:10]}...")
94
-
95
- elif rx and isinstance(graph, (rx.PyGraph, rx.PyDiGraph)): # Rustworkx (hem yönlü hem yönsüz)
96
- nodes = sorted(graph.node_indices()) # 0-tabanlı indeksleme
97
- print(f"DEBUG: Rustworkx tespit edildi. Düğümler (0..{len(nodes)-1}): {nodes[:10]}...")
98
-
99
- elif nx and isinstance(graph, (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)): # NetworkX
100
- try:
101
- # Düğümler sıralanabilirse sırala (genelde int/str)
102
- nodes = sorted(list(graph.nodes()))
103
- except TypeError:
104
- # Sıralanamayan düğüm tipleri varsa (örn. tuple, nesne) sırasız al
105
- nodes = list(graph.nodes())
106
- print(f"DEBUG: NetworkX tespit edildi. Düğümler: {nodes[:10]}...")
107
-
108
- else:
109
- # Desteklenmeyen tip veya kütüphane kurulu değilse
110
- supported_types = []
111
- if nx:
112
- supported_types.append("NetworkX")
113
- if rx:
114
- supported_types.append("Rustworkx")
115
- if ig:
116
- supported_types.append("igraph")
117
- if nk:
118
- supported_types.append("Networkit")
119
- if gg:
120
- supported_types.append("Graphillion.GraphSet")
121
- raise TypeError(f"Unsupported graph type: {type(graph)}. Desteklenen türler: {', '.join(supported_types)}")
122
-
123
- # ----- Buradan sonrası tüm kütüphaneler için ortak -----
75
+ Args:
76
+ graph: A graph object from a supported library.
77
+ primary_spacing (float): The distance between nodes along the primary axis.
78
+ secondary_spacing (float): The base unit for the zigzag offset.
79
+ primary_direction (str): 'top_down', 'bottom_up', 'left-to-right', 'right-to-left'.
80
+ secondary_start (str): Initial direction for the zigzag ('up', 'down', 'left', 'right').
81
+ expanding (bool): If True (default), the zigzag offset grows (the 'v4' style).
82
+ If False, the offset is constant (parallel lines).
124
83
 
125
- num_nodes = len(nodes)
126
- if num_nodes == 0:
127
- return {} # Boş graf için boş sözlük döndür
84
+ Returns:
85
+ dict: A dictionary of positions formatted as {node_id: (x, y)}.
86
+ """
87
+ # Bu blok, farklı kütüphanelerden düğüm listelerini doğru şekilde alır.
88
+ nx_graph = to_networkx(graph) # Emin olmak için en başta dönüştür
89
+ try:
90
+ nodes = sorted(list(nx_graph.nodes()))
91
+ except TypeError:
92
+ nodes = list(nx_graph.nodes())
128
93
 
129
- pos = {} # Sonuç sözlüğü
94
+ pos = {}
95
+
96
+ # --- DOĞRULANMIŞ KONTROL BLOĞU ---
130
97
  is_vertical = primary_direction in ['top-down', 'bottom-up']
131
98
  is_horizontal = primary_direction in ['left-to-right', 'right-to-left']
132
99
 
133
- # Parametre kontrolleri
134
100
  if not (is_vertical or is_horizontal):
135
- raise ValueError(f"Invalid primary_direction: {primary_direction}")
101
+ raise ValueError(f"Invalid primary_direction: '{primary_direction}'")
136
102
  if is_vertical and secondary_start not in ['right', 'left']:
137
- raise ValueError(f"Invalid secondary_start ('{secondary_start}') for vertical primary_direction ('{primary_direction}'). Use 'right' or 'left'.")
103
+ raise ValueError(f"Invalid secondary_start for vertical direction: '{secondary_start}'")
138
104
  if is_horizontal and secondary_start not in ['up', 'down']:
139
- raise ValueError(f"Invalid secondary_start ('{secondary_start}') for horizontal primary_direction ('{primary_direction}'). Use 'up' or 'down'.")
105
+ raise ValueError(f"Invalid secondary_start for horizontal direction: '{secondary_start}'")
106
+ # --- BİTİŞ ---
140
107
 
141
- # Ana döngü - Düğümleri sıralı indekslerine göre yerleştirir,
142
- # sözlüğe ise gerçek düğüm ID/indeks/nesnesini anahtar olarak kullanır.
143
108
  for i, node_id in enumerate(nodes):
144
- # i: Düğümün sıralı listedeki 0-tabanlı indeksi (0, 1, 2, ...) - Yerleşim için kullanılır
145
- # node_id: Gerçek düğüm kimliği/indeksi - Sonuç sözlüğünün anahtarı
146
-
147
- # 1. Ana eksen koordinatını hesapla
109
+ primary_coord, secondary_axis = 0.0, ''
148
110
  if primary_direction == 'top-down':
149
- primary_coord = i * -primary_spacing;
150
- secondary_axis = 'x'
111
+ primary_coord, secondary_axis = i * -primary_spacing, 'x'
151
112
  elif primary_direction == 'bottom-up':
152
- primary_coord = i * primary_spacing;
153
- secondary_axis = 'x'
113
+ primary_coord, secondary_axis = i * primary_spacing, 'x'
154
114
  elif primary_direction == 'left-to-right':
155
- primary_coord = i * primary_spacing;
156
- secondary_axis = 'y'
157
- else: # right-to-left
158
- primary_coord = i * -primary_spacing;
159
- secondary_axis = 'y'
160
-
161
- # 2. Yan eksen ofsetini hesapla (zigzag)
162
- if i == 0:
163
- secondary_offset_multiplier = 0.0
115
+ primary_coord, secondary_axis = i * primary_spacing, 'y'
164
116
  else:
165
- start_mult = 1.0 if secondary_start in ['right', 'up'] else -1.0
166
- magnitude = math.ceil(i / 2.0)
167
- side = 1 if i % 2 != 0 else -1
168
- secondary_offset_multiplier = start_mult * magnitude * side
169
- secondary_coord = secondary_offset_multiplier * secondary_spacing
117
+ primary_coord, secondary_axis = i * -primary_spacing, 'y'
170
118
 
171
- # 3. (x, y) koordinatlarını ata
172
- if secondary_axis == 'x':
173
- x, y = secondary_coord, primary_coord
174
- else:
175
- x, y = primary_coord, secondary_coord
119
+ secondary_offset = 0.0
120
+ if i > 0:
121
+ start_multiplier = 1.0 if secondary_start in ['right', 'up'] else -1.0
122
+ magnitude = math.ceil(i / 2.0) if expanding else 1.0
123
+ side = 1 if i % 2 != 0 else -1
124
+ secondary_offset = start_multiplier * magnitude * side * secondary_spacing
176
125
 
177
- # Sonuç sözlüğüne ekle
126
+ x, y = ((secondary_offset, primary_coord) if secondary_axis == 'x' else
127
+ (primary_coord, secondary_offset))
178
128
  pos[node_id] = (x, y)
179
-
180
129
  return pos
181
-
182
- def kececi_layout(graph, primary_spacing=1.0, secondary_spacing=1.0,
183
- primary_direction='top-down', secondary_start='right'):
184
- """
185
- Keçeci Layout v4 - Graf düğümlerine sıralı-zigzag yerleşimi sağlar.
186
- NetworkX, Rustworkx, igraph, Networkit ve Graphillion grafikleriyle çalışır.
187
130
 
188
- Parametreler:
189
- -------------
190
- graph : Kütüphaneye özel graf nesnesi
191
- NetworkX, Rustworkx, igraph, Networkit veya Graphillion nesnesi.
192
- Graphillion için bir GraphSet nesnesi beklenir.
193
- ... (diğer parametreler) ...
131
+ # =============================================================================
132
+ # 1. TEMEL LAYOUT HESAPLAMA FONKSİYONU (2D)
133
+ # Bu fonksiyon sadece koordinatları hesaplar, çizim yapmaz.
134
+ # 1. LAYOUT CALCULATION FUNCTION (UNIFIED AND IMPROVED)
135
+ # =============================================================================
194
136
 
195
- Dönüş:
196
- ------
197
- dict[node_identifier, tuple[float, float]]
198
- Her düğümün koordinatını içeren sözlük. Anahtarlar kütüphaneye
199
- göre değişir (NX: node obj/id, RW/NK/igraph: int index, GG: 1-based int index).
137
+ def kececi_layout_v4(graph, primary_spacing=1.0, secondary_spacing=1.0,
138
+ primary_direction='top_down', secondary_start='right',
139
+ expanding=True): # v4 davranışını kontrol etmek için parametre eklendi
200
140
  """
141
+ Calculates 2D sequential-zigzag coordinates for the nodes of a graph.
201
142
 
202
- nodes = None
143
+ This function is compatible with graphs from NetworkX, Rustworkx, igraph,
144
+ Networkit, and Graphillion.
203
145
 
204
- # Kütüphane Tespiti ve Düğüm Listesi Çıkarımı
205
- # isinstance kullanmak hasattr'dan daha güvenilirdir.
206
- # Önce daha spesifik tipleri kontrol etmek iyi olabilir.
146
+ Args:
147
+ graph: A graph object from a supported library.
148
+ primary_spacing (float): The distance between nodes along the primary axis.
149
+ secondary_spacing (float): The base unit for the zigzag offset.
150
+ primary_direction (str): 'top_down', 'bottom_up', 'left_to_right', 'right_to_left'.
151
+ secondary_start (str): Initial direction for the zigzag ('up', 'down', 'left', 'right').
152
+ expanding (bool): If True (default), the zigzag offset grows, creating the
153
+ triangle-like 'v4' style. If False, the offset is constant,
154
+ creating parallel lines.
207
155
 
208
- if gg and isinstance(graph, gg.GraphSet): # Graphillion kontrolü EKLENDİ
156
+ Returns:
157
+ dict: A dictionary of positions formatted as {node_id: (x, y)}.
158
+ """
159
+ # ==========================================================
160
+ # Sizin orijinal, çoklu kütüphane uyumluluk bloğunuz burada korunuyor.
161
+ # Bu, kodun sağlamlığını garanti eder.
162
+ # ==========================================================
163
+ nodes = None
164
+ if gg and isinstance(graph, gg.GraphSet):
209
165
  edges = graph.universe()
210
- max_node_id = find_max_node_id(edges)
211
- if max_node_id > 0:
212
- nodes = list(range(1, max_node_id + 1)) # 1-tabanlı indeksleme
213
- else:
214
- nodes = [] # Boş evren
215
- print(f"DEBUG: Graphillion tespit edildi. Düğümler (1..{max_node_id}): {nodes[:10]}...") # Debug mesajı
216
-
217
- elif ig and isinstance(graph, ig.Graph): # igraph
218
- nodes = sorted([v.index for v in graph.vs]) # 0-tabanlı indeksleme
219
- print(f"DEBUG: igraph tespit edildi. Düğümler (0..{len(nodes)-1}): {nodes[:10]}...")
220
-
221
- elif nk and isinstance(graph, nk.graph.Graph): # Networkit
222
- try:
223
- # iterNodes genellikle 0..N-1 verir ama garanti değil
224
- nodes = sorted(list(graph.iterNodes()))
225
- except Exception:
226
- nodes = list(range(graph.numberOfNodes()))
227
- print(f"DEBUG: Networkit tespit edildi. Düğümler: {nodes[:10]}...")
228
-
229
- elif rx and isinstance(graph, (rx.PyGraph, rx.PyDiGraph)): # Rustworkx (hem yönlü hem yönsüz)
230
- nodes = sorted(graph.node_indices()) # 0-tabanlı indeksleme
231
- print(f"DEBUG: Rustworkx tespit edildi. Düğümler (0..{len(nodes)-1}): {nodes[:10]}...")
232
-
233
- elif nx and isinstance(graph, (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph)): # NetworkX
166
+ max_node_id = max(set(itertools.chain.from_iterable(edges))) if edges else 0
167
+ nodes = list(range(1, max_node_id + 1)) if max_node_id > 0 else []
168
+ elif ig and isinstance(graph, ig.Graph):
169
+ nodes = sorted([v.index for v in graph.vs])
170
+ elif nk and isinstance(graph, nk.graph.Graph):
171
+ nodes = sorted(list(graph.iterNodes()))
172
+ elif rx and isinstance(graph, (rx.PyGraph, rx.PyDiGraph)):
173
+ nodes = sorted(graph.node_indices())
174
+ elif isinstance(graph, nx.Graph):
234
175
  try:
235
- # Düğümler sıralanabilirse sırala (genelde int/str)
236
176
  nodes = sorted(list(graph.nodes()))
237
177
  except TypeError:
238
- # Sıralanamayan düğüm tipleri varsa (örn. tuple, nesne) sırasız al
239
- nodes = list(graph.nodes())
240
- print(f"DEBUG: NetworkX tespit edildi. Düğümler: {nodes[:10]}...")
241
-
178
+ nodes = list(graph.nodes())
242
179
  else:
243
- # Desteklenmeyen tip veya kütüphane kurulu değilse
244
- supported_types = []
245
- if nx:
246
- supported_types.append("NetworkX")
247
- if rx:
248
- supported_types.append("Rustworkx")
249
- if ig:
250
- supported_types.append("igraph")
251
- if nk:
252
- supported_types.append("Networkit")
253
- if gg:
254
- supported_types.append("Graphillion.GraphSet")
255
- raise TypeError(f"Unsupported graph type: {type(graph)}. Desteklenen türler: {', '.join(supported_types)}")
256
-
257
- # ----- Buradan sonrası tüm kütüphaneler için ortak -----
258
-
259
- num_nodes = len(nodes)
260
- if num_nodes == 0:
261
- return {} # Boş graf için boş sözlük döndür
180
+ supported = ["NetworkX", "Rustworkx", "igraph", "Networkit", "Graphillion"]
181
+ raise TypeError(f"Unsupported graph type: {type(graph)}. Supported: {', '.join(supported)}")
182
+ # ==========================================================
262
183
 
263
- pos = {} # Sonuç sözlüğü
264
- is_vertical = primary_direction in ['top-down', 'bottom-up']
184
+ pos = {}
185
+ is_vertical = primary_direction in ['top_down', 'bottom_up']
265
186
  is_horizontal = primary_direction in ['left-to-right', 'right-to-left']
266
187
 
267
- # Parametre kontrolleri
268
188
  if not (is_vertical or is_horizontal):
269
189
  raise ValueError(f"Invalid primary_direction: {primary_direction}")
270
190
  if is_vertical and secondary_start not in ['right', 'left']:
271
- raise ValueError(f"Invalid secondary_start ('{secondary_start}') for vertical primary_direction ('{primary_direction}'). Use 'right' or 'left'.")
191
+ raise ValueError(f"Invalid secondary_start for vertical direction: {secondary_start}")
272
192
  if is_horizontal and secondary_start not in ['up', 'down']:
273
- raise ValueError(f"Invalid secondary_start ('{secondary_start}') for horizontal primary_direction ('{primary_direction}'). Use 'up' or 'down'.")
193
+ raise ValueError(f"Invalid secondary_start for horizontal direction: {secondary_start}")
274
194
 
275
- # Ana döngü - Düğümleri sıralı indekslerine göre yerleştirir,
276
- # sözlüğe ise gerçek düğüm ID/indeks/nesnesini anahtar olarak kullanır.
277
195
  for i, node_id in enumerate(nodes):
278
- # i: Düğümün sıralı listedeki 0-tabanlı indeksi (0, 1, 2, ...) - Yerleşim için kullanılır
279
- # node_id: Gerçek düğüm kimliği/indeksi - Sonuç sözlüğünün anahtarı
280
-
281
- # 1. Ana eksen koordinatını hesapla
196
+ primary_coord, secondary_axis = 0.0, ''
282
197
  if primary_direction == 'top-down':
283
- primary_coord = i * -primary_spacing;
284
- secondary_axis = 'x'
285
- elif primary_direction == 'bottom-up':
286
- primary_coord = i * primary_spacing;
287
- secondary_axis = 'x'
198
+ primary_coord, secondary_axis = i * -primary_spacing, 'x'
199
+ elif primary_direction == 'bottom_up':
200
+ primary_coord, secondary_axis = i * primary_spacing, 'x'
288
201
  elif primary_direction == 'left-to-right':
289
- primary_coord = i * primary_spacing;
290
- secondary_axis = 'y'
291
- else: # right-to-left
292
- primary_coord = i * -primary_spacing;
293
- secondary_axis = 'y'
202
+ primary_coord, secondary_axis = i * primary_spacing, 'y'
203
+ else: # 'right_to_left'
204
+ primary_coord, secondary_axis = i * -primary_spacing, 'y'
294
205
 
295
- # 2. Yan eksen ofsetini hesapla (zigzag)
296
- if i == 0:
297
- secondary_offset_multiplier = 0.0
298
- else:
299
- start_mult = 1.0 if secondary_start in ['right', 'up'] else -1.0
300
- magnitude = math.ceil(i / 2.0)
206
+ secondary_offset = 0.0
207
+ if i > 0:
208
+ start_multiplier = 1.0 if secondary_start in ['right', 'up'] else -1.0
209
+
210
+ # --- YENİ ESNEK MANTIK BURADA ---
211
+ # `expanding` True ise 'v4' stili gibi genişler, değilse sabit kalır.
212
+ magnitude = math.ceil(i / 2.0) if expanding else 1.0
213
+
301
214
  side = 1 if i % 2 != 0 else -1
302
- secondary_offset_multiplier = start_mult * magnitude * side
303
- secondary_coord = secondary_offset_multiplier * secondary_spacing
215
+ secondary_offset = start_multiplier * magnitude * side * secondary_spacing
304
216
 
305
- # 3. (x, y) koordinatlarını ata
306
- if secondary_axis == 'x':
307
- x, y = secondary_coord, primary_coord
308
- else:
309
- x, y = primary_coord, secondary_coord
310
-
311
- # Sonuç sözlüğüne ekle
217
+ x, y = ((secondary_offset, primary_coord) if secondary_axis == 'x' else
218
+ (primary_coord, secondary_offset))
312
219
  pos[node_id] = (x, y)
313
220
 
314
221
  return pos
@@ -1129,5 +1036,204 @@ def generate_random_graph_ig(min_nodes=0, max_nodes=200, edge_prob_min=0.15, edg
1129
1036
  g.vs["degree"] = g.degree()
1130
1037
  return g
1131
1038
 
1039
+ # =============================================================================
1040
+ # 1. GRAPH PROCESSING AND CONVERSION HELPERS
1041
+ # =============================================================================
1042
+
1043
+ def _get_nodes_from_graph(graph):
1044
+ """Extracts a sorted list of nodes from various graph library objects."""
1045
+ nodes = None
1046
+ if gg and isinstance(graph, gg.GraphSet):
1047
+ edges = graph.universe()
1048
+ max_node_id = max(set(itertools.chain.from_iterable(edges))) if edges else 0
1049
+ nodes = list(range(1, max_node_id + 1)) if max_node_id > 0 else []
1050
+ elif ig and isinstance(graph, ig.Graph):
1051
+ nodes = sorted([v.index for v in graph.vs])
1052
+ elif nk and isinstance(graph, nk.graph.Graph):
1053
+ nodes = sorted(list(graph.iterNodes()))
1054
+ elif rx and isinstance(graph, (rx.PyGraph, rx.PyDiGraph)):
1055
+ nodes = sorted(graph.node_indices())
1056
+ elif isinstance(graph, nx.Graph):
1057
+ try:
1058
+ nodes = sorted(list(graph.nodes()))
1059
+ except TypeError: # For non-sortable node types
1060
+ nodes = list(graph.nodes())
1061
+ else:
1062
+ supported = ["NetworkX"]
1063
+ if rx:
1064
+ supported.append("Rustworkx")
1065
+ if ig:
1066
+ supported.append("igraph")
1067
+ if nk:
1068
+ supported.append("Networkit")
1069
+ if gg:
1070
+ supported.append("Graphillion")
1071
+ raise TypeError(
1072
+ f"Unsupported graph type: {type(graph)}. Supported types: {', '.join(supported)}"
1073
+ )
1074
+ return nodes
1075
+
1076
+
1077
+ def to_networkx(graph):
1078
+ """Converts any supported graph type to a NetworkX graph."""
1079
+ if isinstance(graph, nx.Graph):
1080
+ return graph.copy()
1081
+ nx_graph = nx.Graph()
1082
+ if rx and isinstance(graph, (rx.PyGraph, rx.PyDiGraph)):
1083
+ nx_graph.add_nodes_from(graph.node_indices())
1084
+ nx_graph.add_edges_from(graph.edge_list())
1085
+ elif ig and isinstance(graph, ig.Graph):
1086
+ nx_graph.add_nodes_from(v.index for v in graph.vs)
1087
+ nx_graph.add_edges_from(graph.get_edgelist())
1088
+ elif nk and isinstance(graph, nk.graph.Graph):
1089
+ nx_graph.add_nodes_from(graph.iterNodes())
1090
+ nx_graph.add_edges_from(graph.iterEdges())
1091
+ elif gg and isinstance(graph, gg.GraphSet):
1092
+ edges = graph.universe()
1093
+ max_node_id = max(set(itertools.chain.from_iterable(edges))) if edges else 0
1094
+ if max_node_id > 0:
1095
+ nx_graph.add_nodes_from(range(1, max_node_id + 1))
1096
+ nx_graph.add_edges_from(edges)
1097
+ else:
1098
+ # This block is rarely reached as _get_nodes_from_graph would fail first
1099
+ raise TypeError(f"Unsupported graph type {type(graph)} could not be converted to NetworkX.")
1100
+ #raise TypeError(f"Desteklenmeyen graf tipi {type(graph)} NetworkX'e dönüştürülemedi.")
1101
+ return nx_graph
1102
+
1103
+
1104
+ def _kececi_layout_3d_helix(nx_graph):
1105
+ """Internal function: Arranges nodes in a helix along the Z-axis."""
1106
+ pos_3d = {}
1107
+ nodes = sorted(list(nx_graph.nodes()))
1108
+ for i, node_id in enumerate(nodes):
1109
+ angle, radius, z_step = i * (np.pi / 2.5), 1.0, i * 0.8
1110
+ pos_3d[node_id] = (np.cos(angle) * radius, np.sin(angle) * radius, z_step)
1111
+ return pos_3d
1112
+
1113
+
1114
+ # =============================================================================
1115
+ # 3. INTERNAL DRAWING STYLE IMPLEMENTATIONS
1116
+ # =============================================================================
1117
+
1118
+ def _draw_internal(nx_graph, ax, style, **kwargs):
1119
+ """Internal router that handles the different drawing styles."""
1120
+ layout_params = {
1121
+ k: v for k, v in kwargs.items()
1122
+ if k in ['primary_spacing', 'secondary_spacing', 'primary_direction',
1123
+ 'secondary_start', 'expanding']
1124
+ }
1125
+ draw_params = {k: v for k, v in kwargs.items() if k not in layout_params}
1126
+
1127
+ if style == 'curved':
1128
+ pos = kececi_layout(nx_graph, **layout_params)
1129
+ final_params = {'ax': ax, 'with_labels': True, 'node_color': '#1f78b4',
1130
+ 'node_size': 700, 'font_color': 'white',
1131
+ 'connectionstyle': 'arc3,rad=0.2', 'arrows': True}
1132
+ final_params.update(draw_params)
1133
+ with warnings.catch_warnings():
1134
+ warnings.simplefilter("ignore", UserWarning)
1135
+ nx.draw(nx_graph, pos, **final_params)
1136
+ ax.set_title("Keçeci Layout: Curved Edges")
1137
+
1138
+ elif style == 'transparent':
1139
+ pos = kececi_layout(nx_graph, **layout_params)
1140
+ nx.draw_networkx_nodes(nx_graph, pos, ax=ax, node_color='#2ca02c', node_size=700, **draw_params)
1141
+ nx.draw_networkx_labels(nx_graph, pos, ax=ax, font_color='white')
1142
+ edge_lengths = {e: np.linalg.norm(np.array(pos[e[0]]) - np.array(pos[e[1]])) for e in nx_graph.edges()}
1143
+ max_len = max(edge_lengths.values()) if edge_lengths else 1.0
1144
+ for edge, length in edge_lengths.items():
1145
+ alpha = 0.15 + 0.85 * (1 - length / max_len)
1146
+ nx.draw_networkx_edges(nx_graph, pos, edgelist=[edge], ax=ax, width=1.5, edge_color='black', alpha=alpha)
1147
+ ax.set_title("Keçeci Layout: Transparent Edges")
1148
+
1149
+ elif style == '3d':
1150
+ pos_3d = _kececi_layout_3d_helix(nx_graph)
1151
+ node_color = draw_params.get('node_color', '#d62728')
1152
+ edge_color = draw_params.get('edge_color', 'gray')
1153
+ for node, (x, y, z) in pos_3d.items():
1154
+ ax.scatter([x], [y], [z], s=200, c=[node_color], depthshade=True)
1155
+ ax.text(x, y, z, f' {node}', size=10, zorder=1, color='k')
1156
+ for u, v in nx_graph.edges():
1157
+ coords = np.array([pos_3d[u], pos_3d[v]])
1158
+ ax.plot(coords[:, 0], coords[:, 1], coords[:, 2], color=edge_color, alpha=0.8)
1159
+ ax.set_title("Keçeci Layout: 3D Helix")
1160
+ ax.set_axis_off()
1161
+ ax.view_init(elev=20, azim=-60)
1162
+
1163
+
1164
+ # =============================================================================
1165
+ # 4. MAIN USER-FACING DRAWING FUNCTION
1166
+ # =============================================================================
1167
+
1168
+ def draw_kececi(graph, style='curved', ax=None, **kwargs):
1169
+ """
1170
+ Draws a graph using the Keçeci Layout with a specified style.
1171
+
1172
+ This function automatically handles graphs from different libraries
1173
+ (NetworkX, Rustworkx, igraph, etc.).
1174
+
1175
+ Args:
1176
+ graph: The graph object to be drawn.
1177
+ style (str): The drawing style. Options: 'curved', 'transparent', '3d'.
1178
+ ax (matplotlib.axis.Axis, optional): The axis to draw on. If not
1179
+ provided, a new figure and axis are created.
1180
+ **kwargs: Additional keyword arguments passed to both `kececi_layout`
1181
+ and the drawing functions (e.g., expanding=True, node_size=500).
1182
+
1183
+ Returns:
1184
+ matplotlib.axis.Axis: The axis object where the graph was drawn.
1185
+ """
1186
+ nx_graph = to_networkx(graph)
1187
+ is_3d = (style.lower() == '3d')
1188
+
1189
+ if ax is None:
1190
+ fig = plt.figure(figsize=(10, 8))
1191
+ projection = '3d' if is_3d else None
1192
+ ax = fig.add_subplot(111, projection=projection)
1193
+
1194
+ if is_3d and getattr(ax, 'name', '') != '3d':
1195
+ raise ValueError("The '3d' style requires an axis with 'projection=\"3d\"'.")
1196
+
1197
+ draw_styles = ['curved', 'transparent', '3d']
1198
+ if style.lower() not in draw_styles:
1199
+ raise ValueError(f"Invalid style: '{style}'. Options are: {draw_styles}")
1200
+
1201
+ _draw_internal(nx_graph, ax, style.lower(), **kwargs)
1202
+ return ax
1203
+
1204
+
1205
+ # =============================================================================
1206
+ # MODULE TEST CODE
1207
+ # =============================================================================
1132
1208
 
1209
+ if __name__ == '__main__':
1210
+ print("Testing kececilayout.py module...")
1211
+ G_test = nx.gnp_random_graph(12, 0.3, seed=42)
1212
+
1213
+ # Compare expanding=False (parallel) vs. expanding=True ('v4' style)
1214
+ fig_v4 = plt.figure(figsize=(16, 7))
1215
+ fig_v4.suptitle("Effect of the `expanding` Parameter", fontsize=20)
1216
+ ax_v4_1 = fig_v4.add_subplot(1, 2, 1)
1217
+ draw_kececi(G_test, ax=ax_v4_1, style='curved',
1218
+ primary_direction='left_to_right', secondary_start='up',
1219
+ expanding=False)
1220
+ ax_v4_1.set_title("Parallel Style (expanding=False)", fontsize=16)
1221
+
1222
+ ax_v4_2 = fig_v4.add_subplot(1, 2, 2)
1223
+ draw_kececi(G_test, ax=ax_v4_2, style='curved',
1224
+ primary_direction='left_to_right', secondary_start='up',
1225
+ expanding=True)
1226
+ ax_v4_2.set_title("Expanding 'v4' Style (expanding=True)", fontsize=16)
1227
+ plt.show()
1228
+
1229
+ # Test all advanced drawing styles
1230
+ fig_styles = plt.figure(figsize=(18, 12))
1231
+ fig_styles.suptitle("Advanced Drawing Styles Test", fontsize=20)
1232
+ draw_kececi(G_test, style='curved', ax=fig_styles.add_subplot(2, 2, 1),
1233
+ primary_direction='left_to_right', secondary_start='up', expanding=True)
1234
+ draw_kececi(G_test, style='transparent', ax=fig_styles.add_subplot(2, 2, 2),
1235
+ primary_direction='top_down', secondary_start='left', expanding=True, node_color='purple')
1236
+ draw_kececi(G_test, style='3d', ax=fig_styles.add_subplot(2, 2, (3, 4), projection='3d'))
1237
+ plt.tight_layout(rect=[0, 0, 1, 0.96])
1238
+ plt.show()
1133
1239
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kececilayout
3
- Version: 0.2.5
3
+ Version: 0.2.7
4
4
  Summary: 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.
5
5
  Home-page: https://github.com/WhiteSymmetry/kececilayout
6
6
  Author: Mehmet Keçeci
@@ -41,9 +41,9 @@ Dynamic: summary
41
41
  [![PyPI version](https://badge.fury.io/py/kececilayout.svg)](https://badge.fury.io/py/kececilayout)
42
42
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
43
43
 
44
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15313946.svg)](https://doi.org/10.5281/zenodo.15313946)
45
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15314329.svg)](https://doi.org/10.5281/zenodo.15314329)
46
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15353535.svg)](https://doi.org/10.5281/zenodo.15353535)
44
+ [![Zenodo DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15313946.svg)](https://doi.org/10.5281/zenodo.15313946)
45
+ [![Zenodo DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15314328.svg)](https://doi.org/10.5281/zenodo.15314328)
46
+ [![Zenodo DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.15353535.svg)](https://doi.org/10.5281/zenodo.15353535)
47
47
 
48
48
  [![WorkflowHub DOI](https://img.shields.io/badge/DOI-10.48546%2Fworkflowhub.datafile.17.1-blue)](https://doi.org/10.48546/workflowhub.datafile.17.1)
49
49
 
@@ -67,6 +67,10 @@ Dynamic: summary
67
67
  [![CI/CD](https://github.com/WhiteSymmetry/kececilayout/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/WhiteSymmetry/kececilayout/actions/workflows/ci-cd.yml)
68
68
  [![Linted with Ruff](https://img.shields.io/badge/Linted%20with-Ruff-green?logo=python&logoColor=white)](https://github.com/astral-sh/ruff)
69
69
 
70
+ | **Documentation**| **Paper**|
71
+ |:----------------:|:--------:|
72
+ |[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://whitesymmetry.github.io/kececilayout/)|[![Zenodo](https://zenodo.org/badge/DOI/10.5281/zenodo.15314328.svg)](https://doi.org/10.5281/zenodo.15314328)|
73
+
70
74
  ---
71
75
 
72
76
  <p align="left">
@@ -120,6 +124,8 @@ This algorithm arranges nodes sequentially along a primary axis and offsets them
120
124
 
121
125
  *Bu algoritma, düğümleri birincil eksen boyunca sıralı olarak yerleştirir ve ikincil eksen boyunca dönüşümlü olarak kaydırır. Yol grafları, zincirler veya ilerlemeyi göstermek için özellikle kullanışlıdır.*
122
126
 
127
+ => 0.2.6: Curved, transparent, 3d, expanding=True
128
+
123
129
  ---
124
130
 
125
131
  ### English Description
@@ -808,7 +814,9 @@ Keçeci, Mehmet. kececilayout [Data set]. WorkflowHub, 2025. https://doi.org/10.
808
814
 
809
815
  Keçeci, Mehmet. "Kececilayout". Open Science Articles (OSAs), Zenodo, 2025. https://doi.org/10.5281/zenodo.15313946.
810
816
 
811
- Keçeci, Mehmet. "Keçeci Layout". Open Science Articles (OSAs), Zenodo, 2025. https://doi.org/10.5281/zenodo.15314329.
817
+ Keçeci, Mehmet. "Keçeci Layout". Open Science Articles (OSAs), Zenodo, 2025. https://doi.org/10.5281/zenodo.15314328.
812
818
  ```
813
819
 
814
820
 
821
+
822
+
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="kececilayout",
5
- version="0.2.5",
5
+ version="0.2.7",
6
6
  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.",
7
7
  long_description=open("README.md").read(),
8
8
  long_description_content_type="text/markdown",
@@ -34,3 +34,5 @@ setup(
34
34
  license="MIT",
35
35
  )
36
36
 
37
+
38
+
@@ -1,76 +0,0 @@
1
- # __init__.py
2
- # Bu dosya paketin başlangıç noktası olarak çalışır.
3
- # Alt modülleri yükler, sürüm bilgileri tanımlar ve geriye dönük uyumluluk için uyarılar sağlar.
4
-
5
- from __future__ import annotations
6
- import importlib
7
- import warnings
8
- import os
9
- # if os.getenv("DEVELOPMENT") == "true":
10
- # importlib.reload(kececi_layout) # F821 undefined name 'kececi_layout'
11
-
12
- # Dışa aktarılacak semboller listesi
13
- __all__ = [
14
- 'kececi_layout_v4',
15
- 'kececi_layout',
16
- 'kececi_layout_v4_nx',
17
- 'kececi_layout_v4_networkx',
18
- 'kececi_layout_v4_ig',
19
- 'kececi_layout_v4_igraph',
20
- 'kececi_layout_v4_nk',
21
- 'kececi_layout_v4_networkit',
22
- 'kececi_layout_v4_gg',
23
- 'kececi_layout_v4_graphillion',
24
- 'kececi_layout_v4_rx',
25
- 'kececi_layout_v4_rustworkx',
26
- 'generate_random_rx_graph',
27
- 'kececi_layout_v4_pure',
28
- 'generate_random_graph',
29
- 'generate_random_graph_ig'
30
- ]
31
-
32
- # Göreli modül içe aktarmaları
33
- # F401 hatasını önlemek için sadece kullanacağınız şeyleri dışa aktarın
34
- # Aksi halde linter'lar "imported but unused" uyarısı verir
35
- try:
36
- #from .kececi_layout import * # gerekirse burada belirli fonksiyonları seçmeli yapmak daha güvenlidir
37
- #from . import kececi_layout # Modülün kendisine doğrudan erişim isteniyorsa
38
- from .kececi_layout import (
39
- kececi_layout_v4,
40
- kececi_layout,
41
- kececi_layout_v4_nx,
42
- kececi_layout_v4_networkx,
43
- kececi_layout_v4_ig,
44
- kececi_layout_v4_igraph,
45
- kececi_layout_v4_nk,
46
- kececi_layout_v4_networkit,
47
- kececi_layout_v4_gg,
48
- kececi_layout_v4_graphillion,
49
- kececi_layout_v4_rx,
50
- kececi_layout_v4_rustworkx,
51
- generate_random_rx_graph,
52
- kececi_layout_v4_pure,
53
- generate_random_graph,
54
- generate_random_graph_ig
55
- )
56
- except ImportError as e:
57
- warnings.warn(f"Gerekli modül yüklenemedi: {e}", ImportWarning)
58
-
59
- # Eski bir fonksiyonun yer tutucusu - gelecekte kaldırılacak
60
- def eski_fonksiyon():
61
- """
62
- Kaldırılması planlanan eski bir fonksiyondur.
63
- Lütfen alternatif fonksiyonları kullanın.
64
- """
65
- warnings.warn(
66
- "eski_fonksiyon() artık kullanılmamaktadır ve gelecekte kaldırılacaktır. "
67
- "Lütfen yeni alternatif fonksiyonları kullanın. "
68
- "Keçeci Layout; Python 3.7-3.14 sürümlerinde sorunsuz çalışmalıdır.",
69
- category=DeprecationWarning,
70
- stacklevel=2
71
- )
72
-
73
- # Paket sürüm numarası
74
- __version__ = "0.2.5"
75
-
76
-
File without changes
File without changes
File without changes