knit-graphs 0.0.7__tar.gz → 0.0.8__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.
Files changed (42) hide show
  1. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/PKG-INFO +2 -2
  2. knit_graphs-0.0.8/docs/source/api/knit_graphs.Course.rst +7 -0
  3. knit_graphs-0.0.8/docs/source/api/knit_graphs.Knit_Graph.rst +7 -0
  4. knit_graphs-0.0.8/docs/source/api/knit_graphs.Knit_Graph_Visualizer.rst +7 -0
  5. knit_graphs-0.0.8/docs/source/api/knit_graphs.Loop.rst +7 -0
  6. knit_graphs-0.0.8/docs/source/api/knit_graphs.Pull_Direction.rst +7 -0
  7. knit_graphs-0.0.8/docs/source/api/knit_graphs.Yarn.rst +7 -0
  8. knit_graphs-0.0.8/docs/source/api/knit_graphs.artin_wale_braids.Crossing_Direction.rst +7 -0
  9. knit_graphs-0.0.8/docs/source/api/knit_graphs.artin_wale_braids.Loop_Braid_Graph.rst +7 -0
  10. knit_graphs-0.0.8/docs/source/api/knit_graphs.artin_wale_braids.Wale.rst +7 -0
  11. knit_graphs-0.0.8/docs/source/api/knit_graphs.artin_wale_braids.Wale_Braid.rst +7 -0
  12. knit_graphs-0.0.8/docs/source/api/knit_graphs.artin_wale_braids.Wale_Braid_Word.rst +7 -0
  13. knit_graphs-0.0.8/docs/source/api/knit_graphs.artin_wale_braids.Wale_Group.rst +7 -0
  14. knit_graphs-0.0.8/docs/source/api/knit_graphs.artin_wale_braids.rst +23 -0
  15. knit_graphs-0.0.8/docs/source/api/knit_graphs.basic_knit_graph_generators.rst +7 -0
  16. knit_graphs-0.0.8/docs/source/api/knit_graphs.rst +32 -0
  17. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/pyproject.toml +3 -37
  18. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/Knit_Graph_Visualizer.py +188 -193
  19. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/basic_knit_graph_generators.py +24 -75
  20. knit_graphs-0.0.7/docs/source/api/knit_graphs.artin_wale_braids.rst +0 -58
  21. knit_graphs-0.0.7/docs/source/api/knit_graphs.rst +0 -74
  22. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/LICENSE +0 -0
  23. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/README.md +0 -0
  24. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/docs/Makefile +0 -0
  25. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/docs/make.bat +0 -0
  26. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/docs/source/conf.py +0 -0
  27. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/docs/source/index.rst +0 -0
  28. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/docs/source/installation.rst +0 -0
  29. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/Course.py +0 -0
  30. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/Knit_Graph.py +0 -0
  31. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/Loop.py +0 -0
  32. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/Pull_Direction.py +0 -0
  33. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/Yarn.py +0 -0
  34. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/__init__.py +0 -0
  35. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/_base_classes.py +0 -0
  36. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/artin_wale_braids/Crossing_Direction.py +0 -0
  37. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/artin_wale_braids/Loop_Braid_Graph.py +0 -0
  38. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/artin_wale_braids/Wale.py +0 -0
  39. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/artin_wale_braids/Wale_Braid.py +0 -0
  40. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/artin_wale_braids/Wale_Braid_Word.py +0 -0
  41. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/artin_wale_braids/Wale_Group.py +0 -0
  42. {knit_graphs-0.0.7 → knit_graphs-0.0.8}/src/knit_graphs/artin_wale_braids/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: knit-graphs
3
- Version: 0.0.7
3
+ Version: 0.0.8
4
4
  Summary: A graph representation of knitted structures where each loop is a node and edges represent yarn and stitch relationships.
5
5
  Home-page: https://mhofmann-Khoury.github.io/knit-graphs/
6
6
  License: MIT
@@ -21,7 +21,7 @@ Classifier: Programming Language :: Python :: 3.12
21
21
  Classifier: Programming Language :: Python :: 3.13
22
22
  Classifier: Topic :: Scientific/Engineering
23
23
  Requires-Dist: networkx (>=3.5)
24
- Requires-Dist: plotly (>=6.3.0)
24
+ Requires-Dist: plotly (>=6.3.0,<7.0.0)
25
25
  Project-URL: Documentation, https://mhofmann-Khoury.github.io/knit-graphs/
26
26
  Project-URL: Repository, https://github.com/mhofmann-Khoury/knit-graphs
27
27
  Description-Content-Type: text/markdown
@@ -0,0 +1,7 @@
1
+ knit\_graphs.Course module
2
+ ==========================
3
+
4
+ .. automodule:: knit_graphs.Course
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,7 @@
1
+ knit\_graphs.Knit\_Graph module
2
+ ===============================
3
+
4
+ .. automodule:: knit_graphs.Knit_Graph
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,7 @@
1
+ knit\_graphs.Knit\_Graph\_Visualizer module
2
+ ===========================================
3
+
4
+ .. automodule:: knit_graphs.Knit_Graph_Visualizer
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,7 @@
1
+ knit\_graphs.Loop module
2
+ ========================
3
+
4
+ .. automodule:: knit_graphs.Loop
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,7 @@
1
+ knit\_graphs.Pull\_Direction module
2
+ ===================================
3
+
4
+ .. automodule:: knit_graphs.Pull_Direction
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,7 @@
1
+ knit\_graphs.Yarn module
2
+ ========================
3
+
4
+ .. automodule:: knit_graphs.Yarn
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,7 @@
1
+ knit\_graphs.artin\_wale\_braids.Crossing\_Direction module
2
+ ===========================================================
3
+
4
+ .. automodule:: knit_graphs.artin_wale_braids.Crossing_Direction
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,7 @@
1
+ knit\_graphs.artin\_wale\_braids.Loop\_Braid\_Graph module
2
+ ==========================================================
3
+
4
+ .. automodule:: knit_graphs.artin_wale_braids.Loop_Braid_Graph
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,7 @@
1
+ knit\_graphs.artin\_wale\_braids.Wale module
2
+ ============================================
3
+
4
+ .. automodule:: knit_graphs.artin_wale_braids.Wale
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,7 @@
1
+ knit\_graphs.artin\_wale\_braids.Wale\_Braid module
2
+ ===================================================
3
+
4
+ .. automodule:: knit_graphs.artin_wale_braids.Wale_Braid
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,7 @@
1
+ knit\_graphs.artin\_wale\_braids.Wale\_Braid\_Word module
2
+ =========================================================
3
+
4
+ .. automodule:: knit_graphs.artin_wale_braids.Wale_Braid_Word
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,7 @@
1
+ knit\_graphs.artin\_wale\_braids.Wale\_Group module
2
+ ===================================================
3
+
4
+ .. automodule:: knit_graphs.artin_wale_braids.Wale_Group
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,23 @@
1
+ knit\_graphs.artin\_wale\_braids package
2
+ ========================================
3
+
4
+ Submodules
5
+ ----------
6
+
7
+ .. toctree::
8
+ :maxdepth: 4
9
+
10
+ knit_graphs.artin_wale_braids.Crossing_Direction
11
+ knit_graphs.artin_wale_braids.Loop_Braid_Graph
12
+ knit_graphs.artin_wale_braids.Wale
13
+ knit_graphs.artin_wale_braids.Wale_Braid
14
+ knit_graphs.artin_wale_braids.Wale_Braid_Word
15
+ knit_graphs.artin_wale_braids.Wale_Group
16
+
17
+ Module contents
18
+ ---------------
19
+
20
+ .. automodule:: knit_graphs.artin_wale_braids
21
+ :members:
22
+ :undoc-members:
23
+ :show-inheritance:
@@ -0,0 +1,7 @@
1
+ knit\_graphs.basic\_knit\_graph\_generators module
2
+ ==================================================
3
+
4
+ .. automodule:: knit_graphs.basic_knit_graph_generators
5
+ :members:
6
+ :undoc-members:
7
+ :show-inheritance:
@@ -0,0 +1,32 @@
1
+ knit\_graphs package
2
+ ====================
3
+
4
+ Subpackages
5
+ -----------
6
+
7
+ .. toctree::
8
+ :maxdepth: 4
9
+
10
+ knit_graphs.artin_wale_braids
11
+
12
+ Submodules
13
+ ----------
14
+
15
+ .. toctree::
16
+ :maxdepth: 4
17
+
18
+ knit_graphs.Course
19
+ knit_graphs.Knit_Graph
20
+ knit_graphs.Knit_Graph_Visualizer
21
+ knit_graphs.Loop
22
+ knit_graphs.Pull_Direction
23
+ knit_graphs.Yarn
24
+ knit_graphs.basic_knit_graph_generators
25
+
26
+ Module contents
27
+ ---------------
28
+
29
+ .. automodule:: knit_graphs
30
+ :members:
31
+ :undoc-members:
32
+ :show-inheritance:
@@ -12,7 +12,7 @@ build-backend = "poetry.core.masonry.api" # Use Poetry's build system
12
12
  # All the information about your project that will appear on PyPI
13
13
  [tool.poetry]
14
14
  name = "knit-graphs"
15
- version = "0.0.7"
15
+ version = "0.0.8"
16
16
  description = "A graph representation of knitted structures where each loop is a node and edges represent yarn and stitch relationships."
17
17
  authors = ["Megan Hofmann <m.hofmann@northeastern.edu>"]
18
18
  maintainers = ["Megan Hofmann <m.hofmann@northeastern.edu>"]
@@ -79,7 +79,7 @@ exclude = [
79
79
  [tool.poetry.dependencies]
80
80
  python = ">=3.11,<3.14"
81
81
  networkx = ">=3.5"
82
- plotly = ">=6.3.0"
82
+ plotly = "^6.3.0"
83
83
  # Examples:
84
84
  # requests = "^2.31.0" # For HTTP requests
85
85
  # pydantic = "^2.0.0" # For data validation
@@ -102,6 +102,7 @@ plotly = ">=6.3.0"
102
102
  # =============================================================================
103
103
  # These packages are only needed during development and testing
104
104
 
105
+
105
106
  [tool.poetry.group.dev.dependencies]
106
107
  importlib-resources = ">=6.5.2"
107
108
 
@@ -277,8 +278,6 @@ omit = [ # Files to exclude from coverage measurement
277
278
  "*/__pycache__/*", # Ignore Python cache files
278
279
  "*/site-packages/*", # Ignore installed packages
279
280
  "*/venv/*", # Ignore virtual environment
280
- "setup.py", # Ignore setup script (if present)
281
- "update_project_config.py"
282
281
  ]
283
282
  branch = true # Enable branch coverage (more comprehensive)
284
283
 
@@ -301,39 +300,6 @@ show_missing = true # Show which lines are missing coverage
301
300
  skip_covered = false # Show covered files in report
302
301
  skip_empty = true # Skip empty files in report
303
302
 
304
- # Coverage output formats
305
- [tool.coverage.html]
306
- directory = "htmlcov" # Directory for HTML coverage reports
307
-
308
- [tool.coverage.xml]
309
- output = "coverage.xml" # XML coverage report (used by CI/CD tools)
310
-
311
- # =============================================================================
312
- # VERSION BUMPING CONFIGURATION
313
- # =============================================================================
314
- # Configuration for bump2version tool to automate version updates
315
- [tool.bumpversion]
316
- current_version = "0.0.7" # Keep this in sync with tool.poetry.version
317
- parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
318
- serialize = ["{major}.{minor}.{patch}"]
319
- search = "{current_version}"
320
- replace = "{new_version}"
321
- commit = true # Automatically commit version changes
322
- tag = true # Automatically create git tags
323
- sign_tags = false # Set to true if you want to sign tags with GPG
324
-
325
- # Files where version numbers should be updated
326
- [[tool.bumpversion.files]]
327
- filename = "pyproject.toml"
328
- search = 'version = "{current_version}"'
329
- replace = 'version = "{new_version}"'
330
-
331
- # Add other files that contain version numbers
332
- # [[tool.bumpversion.files]]
333
- # filename = "src/your_project_name/__init__.py"
334
- # search = '__version__ = "{current_version}"'
335
- # replace = '__version__ = "{new_version}"'
336
-
337
303
  # =============================================================================
338
304
  # WHEEL BUILDING CONFIGURATION
339
305
  # =============================================================================
@@ -3,8 +3,13 @@
3
3
  This module provides comprehensive visualization capabilities for knit graphs using Plotly.
4
4
  It handles the positioning of loops, rendering of yarn paths, stitch edges, and cable crossings to create interactive 2D visualizations of knitted structures.
5
5
  """
6
+ from __future__ import annotations
7
+
8
+ import os
9
+ import sys
6
10
  from typing import Iterable, cast
7
11
 
12
+ import plotly.io as pio
8
13
  from networkx import DiGraph
9
14
  from plotly.graph_objs import Figure, Layout, Scatter
10
15
 
@@ -15,6 +20,25 @@ from knit_graphs.Loop import Loop
15
20
  from knit_graphs.Pull_Direction import Pull_Direction
16
21
 
17
22
 
23
+ def configure_plotly_environment() -> None:
24
+ """Auto-configure Plotly based on environment detection to avoid socket issues."""
25
+ # Check if we're in a testing environment
26
+ if ('pytest' in sys.modules or 'unittest' in sys.modules or
27
+ os.environ.get('TESTING') or os.environ.get('CI')):
28
+ # For testing, don't set a default renderer - we'll handle this with show_figure=False
29
+ pass
30
+ elif 'ipykernel' in sys.modules or 'jupyter' in sys.modules:
31
+ # Jupyter environment - use notebook renderer
32
+ pio.renderers.default = "notebook"
33
+ else:
34
+ # Development environment - use browser but with timeout to prevent hanging
35
+ pio.renderers.default = "browser"
36
+
37
+
38
+ # Configure environment on import
39
+ configure_plotly_environment()
40
+
41
+
18
42
  class Knit_Graph_Visualizer:
19
43
  """A class used to visualize a knit graph using the plotly graph objects library.
20
44
 
@@ -79,11 +103,14 @@ class Knit_Graph_Visualizer:
79
103
  self._set_yarn_traces()
80
104
  self._add_stitch_edges()
81
105
 
82
- def make_figure(self, graph_title: str = "Knit Graph") -> None:
83
- """Generate and display the interactive figure to visualize this knit graph.
106
+ def make_figure(self, graph_title: str = "Knit Graph") -> Figure:
107
+ """Generate the interactive figure to visualize this knit graph.
84
108
 
85
109
  Args:
86
110
  graph_title (str, optional): The title to display on the figure. Defaults to "Knit Graph".
111
+
112
+ Returns:
113
+ Figure: The plotly figure object.
87
114
  """
88
115
  go_layout = Layout(title=graph_title,
89
116
  showlegend=True,
@@ -97,7 +124,34 @@ class Knit_Graph_Visualizer:
97
124
  figure_data.extend(self._loop_markers)
98
125
  fig = Figure(data=figure_data,
99
126
  layout=go_layout)
100
- fig.show()
127
+ return fig
128
+
129
+ def show_figure(self, graph_title: str = "Knit Graph", renderer: str | None = None) -> None:
130
+ """Generate and display the interactive figure to visualize this knit graph.
131
+
132
+ Args:
133
+ graph_title (str, optional): The title to display on the figure. Defaults to "Knit Graph".
134
+ renderer (str, optional): Plotly renderer to use. If None, uses the default configured renderer.
135
+ """
136
+ fig = self.make_figure(graph_title)
137
+
138
+ # Configure display to minimize resource usage
139
+ config = {
140
+ 'displayModeBar': False, # Hide toolbar to reduce resource usage
141
+ 'displaylogo': False, # Hide plotly logo
142
+ 'staticPlot': False, # Keep interactive
143
+ 'scrollZoom': False, # Allow zoom
144
+ 'doubleClick': 'reset+autosize' # Double-click behavior
145
+ }
146
+
147
+ try:
148
+ if renderer:
149
+ fig.show(renderer=renderer, config=config)
150
+ else:
151
+ fig.show(config=config)
152
+ except Exception as e:
153
+ print(f"Warning: Could not display figure: {e}")
154
+ print("Figure created successfully but display failed. Consider using show_figure=False and accessing the returned Figure object directly.")
101
155
 
102
156
  def _no_cross_knit_trace(self, line_width: float = 4.0, knit_color: str = 'blue') -> Scatter:
103
157
  """Create a scatter trace for knit stitches not involved in cable crossings.
@@ -159,12 +213,12 @@ class Knit_Graph_Visualizer:
159
213
  """
160
214
  return self._stitch_trace(self._top_purl_trace_data, "Purl Stitches on Top of Cable", purl_color, line_width, opacity=1.0)
161
215
 
162
- def _bot_purl_trace(self, line_width: float = 3.0, purl_color: str = 'blue') -> Scatter:
216
+ def _bot_purl_trace(self, line_width: float = 3.0, purl_color: str = 'red') -> Scatter:
163
217
  """Create a scatter trace for purl stitches that cross under other stitches in cables.
164
218
 
165
219
  Args:
166
220
  line_width (float, optional): The width of the lines representing the stitch edges. Defaults to 3.0.
167
- purl_color (str, optional): The color of purl stitches in the visualization. Defaults to 'blue'.
221
+ purl_color (str, optional): The color of purl stitches in the visualization. Defaults to 'red'.
168
222
 
169
223
  Returns:
170
224
  Scatter: The plotly scatter object used to visualize purl stitches below cable crossings.
@@ -192,10 +246,7 @@ class Knit_Graph_Visualizer:
192
246
  mode='lines')
193
247
 
194
248
  def _add_cable_edges(self) -> None:
195
- """Add all stitch edges that are involved in cable crossings to the appropriate trace data.
196
-
197
- This method processes all cable crossings in the knit graph and adds the associated stitch edges to the correct trace data based on their crossing direction (over/under).
198
- """
249
+ """Add all stitch edges that are involved in cable crossings to the appropriate trace data."""
199
250
  for left_loop, right_loop in self.knit_graph.braid_graph.loop_crossing_graph.edges:
200
251
  crossing_direction = self.knit_graph.braid_graph.get_crossing(left_loop, right_loop)
201
252
  for left_parent in left_loop.parent_loops:
@@ -204,10 +255,7 @@ class Knit_Graph_Visualizer:
204
255
  self._add_stitch_edge(right_parent, right_loop, ~crossing_direction)
205
256
 
206
257
  def _add_stitch_edges(self) -> None:
207
- """Add all stitch edges to the visualization trace data based on their type and cable position.
208
-
209
- This method first adds cable-involved edges, then adds all remaining stitch edges as non-cable stitches. It ensures all visible stitch connections are properly categorized for rendering.
210
- """
258
+ """Add all stitch edges to the visualization trace data based on their type and cable position."""
211
259
  self._add_cable_edges()
212
260
  # Add remaining stitches as though they have no cable crossing.
213
261
  for u, v in self.knit_graph.stitch_graph.edges:
@@ -216,13 +264,7 @@ class Knit_Graph_Visualizer:
216
264
  self._add_stitch_edge(u, v, Crossing_Direction.No_Cross)
217
265
 
218
266
  def _add_stitch_edge(self, u: Loop, v: Loop, crossing_direction: Crossing_Direction) -> None:
219
- """Add a single stitch edge to the appropriate trace data based on stitch type and cable crossing.
220
-
221
- Args:
222
- u (Loop): The parent loop in the stitch connection.
223
- v (Loop): The child loop in the stitch connection.
224
- crossing_direction (Crossing_Direction): The cable crossing direction of this stitch edge.
225
- """
267
+ """Add a single stitch edge to the appropriate trace data based on stitch type and cable crossing."""
226
268
  pull_direction = self.knit_graph.get_pull_direction(u, v)
227
269
  if pull_direction is None:
228
270
  return # No edge between these loops
@@ -253,12 +295,7 @@ class Knit_Graph_Visualizer:
253
295
  trace_data['y'].append(None)
254
296
 
255
297
  def _set_loop_markers(self, loop_size: float = 30.0, loop_border_width: float = 2.0) -> None:
256
- """Create plotly scatter objects to mark the position of each loop in the visualization.
257
-
258
- Args:
259
- loop_size (float, optional): The diameter of the circle marking each loop. Defaults to 30.0.
260
- loop_border_width (float, optional): The width of the border around each loop marker. Defaults to 2.0.
261
- """
298
+ """Create plotly scatter objects to mark the position of each loop in the visualization."""
262
299
  yarns_to_loop_data = {yarn: {'x': [self._get_x_of_loop(loop) for loop in yarn],
263
300
  'y': [self._get_y_of_loop(loop) for loop in yarn],
264
301
  'loop_id': [loop.loop_id for loop in yarn]
@@ -276,12 +313,7 @@ class Knit_Graph_Visualizer:
276
313
  for yarn, yarn_data in yarns_to_loop_data.items()]
277
314
 
278
315
  def _set_yarn_traces(self, line_width: float = 1.0, smoothing: float = 1.3) -> None:
279
- """Create plotly traces representing the path of each yarn through the knitted structure.
280
-
281
- Args:
282
- line_width (float, optional): The width of the lines representing yarn paths. Defaults to 1.0.
283
- smoothing (float, optional): The smoothing factor for spline interpolation of yarn paths. Defaults to 1.3.
284
- """
316
+ """Create plotly traces representing the path of each yarn through the knitted structure."""
285
317
  yarns_to_float_data = {}
286
318
  for yarn in self.knit_graph.yarns:
287
319
  float_data: dict[str, list[float]] = {'x': [], 'y': []}
@@ -300,23 +332,14 @@ class Knit_Graph_Visualizer:
300
332
  for yarn, float_data in yarns_to_float_data.items()]
301
333
 
302
334
  def _position_loops(self) -> None:
303
- """Calculate and set the x,y coordinate positions of all loops to be visualized.
304
-
305
- This method orchestrates the complete positioning process including base course positioning, subsequent course positioning, knit/purl shifting, and float alignment adjustments.
306
- """
335
+ """Calculate and set the x,y coordinate positions of all loops to be visualized."""
307
336
  self._position_base_course()
308
337
  self._place_loops_in_courses()
309
338
  self._shift_knit_purl()
310
339
  self._shift_loops_by_float_alignment()
311
340
 
312
341
  def _shift_knit_purl(self, shift: float = 0.1) -> None:
313
- """Adjust the horizontal position of loops to visually distinguish knit from purl stitches.
314
-
315
- This method shifts knit stitches slightly left and purl stitches slightly right to create visual separation that makes knit-purl patterns more distinct in the visualization.
316
-
317
- Args:
318
- shift (float, optional): The amount to shift stitches horizontally. Knit stitches are shifted left and purl stitches are shifted right. Defaults to 0.1.
319
- """
342
+ """Adjust the horizontal position of loops to visually distinguish knit from purl stitches."""
320
343
  has_knits = any(self.knit_graph.get_pull_direction(u, v) is Pull_Direction.BtF for u, v in self.knit_graph.stitch_graph.edges)
321
344
  has_purls = any(self.knit_graph.get_pull_direction(u, v) is Pull_Direction.FtB for u, v in self.knit_graph.stitch_graph.edges)
322
345
  if not (has_knits and has_purls):
@@ -340,14 +363,7 @@ class Knit_Graph_Visualizer:
340
363
  self._set_x_of_loop(loop, self._get_x_of_loop(child_loop))
341
364
 
342
365
  def _shift_loops_by_float_alignment(self, float_increment: float = 0.25) -> None:
343
- """Adjust the vertical position of loops based on their float relationships.
344
-
345
- Loops that pass in front of floats are shifted down while loops that pass behind floats are shifted up.
346
- This creates a visual layering effect that represents the three-dimensional structure of the knitted fabric.
347
-
348
- Args:
349
- float_increment (float, optional): The vertical spacing adjustment for loops relative to floats they cross. Defaults to 0.25.
350
- """
366
+ """Adjust the vertical position of loops based on their float relationships."""
351
367
  for yarn in self.knit_graph.yarns:
352
368
  for u, v, front_loops in yarn.loops_in_front_of_floats():
353
369
  for front_loop in front_loops:
@@ -359,26 +375,11 @@ class Knit_Graph_Visualizer:
359
375
  self._set_y_of_loop(back_loop, self._get_y_of_loop(back_loop) + float_increment) # shift loop up to show it is behind the float.
360
376
 
361
377
  def _get_course_of_loop(self, loop: Loop) -> Course:
362
- """Get the course (horizontal row) that contains the specified loop.
363
-
364
- Args:
365
- loop (Loop): The loop to find the course for.
366
-
367
- Returns:
368
- Course: The course that contains this loop.
369
- """
378
+ """Get the course (horizontal row) that contains the specified loop."""
370
379
  return self.loops_to_course[loop]
371
380
 
372
381
  def _place_loop(self, loop: Loop, x: float, y: float) -> None:
373
- """Add a loop to the visualization data graph at the specified coordinates.
374
-
375
- If the loop already exists in the data graph, its coordinates will be updated to the new position.
376
-
377
- Args:
378
- loop (Loop): The loop to position in the visualization.
379
- x (float): The x coordinate for the loop.
380
- y (float): The y coordinate for the loop.
381
- """
382
+ """Add a loop to the visualization data graph at the specified coordinates."""
382
383
  if self._loop_has_position(loop):
383
384
  self._set_x_of_loop(loop, x)
384
385
  self._set_y_of_loop(loop, y)
@@ -386,98 +387,43 @@ class Knit_Graph_Visualizer:
386
387
  self.data_graph.add_node(loop, x=x, y=y)
387
388
 
388
389
  def _set_x_of_loop(self, loop: Loop, x: float) -> None:
389
- """Update the x coordinate of a loop that already exists in the visualization data graph.
390
-
391
- Args:
392
- loop (Loop): The loop to update the x coordinate for.
393
- x (float): The new x coordinate for the loop.
394
-
395
- Raises:
396
- KeyError: If the loop does not exist in the visualization data graph.
397
- """
390
+ """Update the x coordinate of a loop that already exists in the visualization data graph."""
398
391
  if self._loop_has_position(loop):
399
392
  self.data_graph.nodes[loop]['x'] = x
400
393
  else:
401
394
  raise KeyError(f"Loop {loop} is not in the data graph")
402
395
 
403
396
  def _set_y_of_loop(self, loop: Loop, y: float) -> None:
404
- """Update the y coordinate of a loop that already exists in the visualization data graph.
405
-
406
- Args:
407
- loop (Loop): The loop to update the y coordinate for.
408
- y (float): The new y coordinate for the loop.
409
-
410
- Raises:
411
- KeyError: If the loop does not exist in the visualization data graph.
412
- """
397
+ """Update the y coordinate of a loop that already exists in the visualization data graph."""
413
398
  if self._loop_has_position(loop):
414
399
  self.data_graph.nodes[loop]['y'] = y
415
400
  else:
416
401
  raise KeyError(f"Loop {loop} is not in the data graph")
417
402
 
418
403
  def _get_x_of_loop(self, loop: Loop) -> float:
419
- """Get the x coordinate of a loop from the visualization data graph.
420
-
421
- Args:
422
- loop (Loop): The loop to get the x coordinate for.
423
-
424
- Returns:
425
- float: The x coordinate of the loop.
426
-
427
- Raises:
428
- KeyError: If the loop does not exist in the visualization data graph.
429
- """
404
+ """Get the x coordinate of a loop from the visualization data graph."""
430
405
  if self._loop_has_position(loop):
431
406
  return float(self.data_graph.nodes[loop]['x'])
432
407
  else:
433
408
  raise KeyError(f"Loop {loop} is not in the data graph")
434
409
 
435
410
  def _get_y_of_loop(self, loop: Loop) -> float:
436
- """Get the y coordinate of a loop from the visualization data graph.
437
-
438
- Args:
439
- loop (Loop): The loop to get the y coordinate for.
440
-
441
- Returns:
442
- float: The y coordinate of the loop.
443
-
444
- Raises:
445
- KeyError: If the loop does not exist in the visualization data graph.
446
- """
411
+ """Get the y coordinate of a loop from the visualization data graph."""
447
412
  if self._loop_has_position(loop):
448
413
  return float(self.data_graph.nodes[loop]['y'])
449
414
  else:
450
415
  raise KeyError(f"Loop {loop} is not in the data graph")
451
416
 
452
417
  def _loop_has_position(self, loop: Loop) -> bool:
453
- """Check if a loop has been positioned in the visualization data graph.
454
-
455
- Args:
456
- loop (Loop): The loop to check for positioning.
457
-
458
- Returns:
459
- bool: True if the loop has been positioned in the visualization, False otherwise.
460
- """
418
+ """Check if a loop has been positioned in the visualization data graph."""
461
419
  return bool(self.data_graph.has_node(loop))
462
420
 
463
421
  def _stitch_has_position(self, u: Loop, v: Loop) -> bool:
464
- """Check if a stitch edge between two loops has been added to the visualization data graph.
465
-
466
- Args:
467
- u (Loop): The parent loop in the stitch edge.
468
- v (Loop): The child loop in the stitch edge.
469
-
470
- Returns:
471
- bool: True if a stitch edge from u to v exists in the visualization data graph, False otherwise.
472
- """
422
+ """Check if a stitch edge between two loops has been added to the visualization data graph."""
473
423
  return bool(self.data_graph.has_edge(u, v))
474
424
 
475
425
  def _place_loops_in_courses(self, course_spacing: float = 1.0) -> None:
476
- """Position loops in all courses above the base course using parent relationships and yarn connections.
477
-
478
- Args:
479
- course_spacing (float, optional): The vertical distance between consecutive courses. Defaults to 1.0.
480
- """
426
+ """Position loops in all courses above the base course using parent relationships and yarn connections."""
481
427
  y = course_spacing
482
428
  for course in self.courses[self.first_course_index + 1:self.top_course_index]:
483
429
  self._place_loops_by_parents(course, y)
@@ -487,11 +433,7 @@ class Knit_Graph_Visualizer:
487
433
  y += course_spacing # Shift y coordinate up with each course
488
434
 
489
435
  def _swap_loops_in_cables(self, course: Course) -> None:
490
- """Swap the horizontal positions of loops involved in cable crossings within a course.
491
-
492
- Args:
493
- course (Course): The course containing loops that may need position swapping due to cable crossings.
494
- """
436
+ """Swap the horizontal positions of loops involved in cable crossings within a course."""
495
437
  for left_loop in course:
496
438
  for right_loop in self.knit_graph.braid_graph.left_crossing_loops(left_loop):
497
439
  crossing_direction = self.knit_graph.braid_graph.get_crossing(left_loop, right_loop)
@@ -501,12 +443,7 @@ class Knit_Graph_Visualizer:
501
443
  self._set_x_of_loop(right_loop, left_x)
502
444
 
503
445
  def _place_loops_by_parents(self, course: Course, y: float) -> None:
504
- """Position loops in a course based on the average position of their parent loops.
505
-
506
- Args:
507
- course (Course): The course containing loops to be positioned.
508
- y (float): The y coordinate for all loops in this course.
509
- """
446
+ """Position loops in a course based on the average position of their parent loops."""
510
447
  for x, loop in enumerate(course):
511
448
  self._set_loop_x_by_parent_average(loop, y)
512
449
  placed_loops = set()
@@ -519,14 +456,7 @@ class Knit_Graph_Visualizer:
519
456
  # A loops past the first course should have at least one yarn neighbor to place them.
520
457
 
521
458
  def _set_loop_x_by_parent_average(self, loop: Loop, y: float) -> None:
522
- """Set the x coordinate of a loop based on the weighted average position of its parent loops.
523
-
524
- If the loop has no parent loops, it is added to the set of loops that need positioning through other methods.
525
-
526
- Args:
527
- loop (Loop): The loop to position based on its parents.
528
- y (float): The y coordinate to assign to the loop.
529
- """
459
+ """Set the x coordinate of a loop based on the weighted average position of its parent loops."""
530
460
  if len(loop.parent_loops) == 0:
531
461
  self._loops_need_placement.add(loop)
532
462
  return
@@ -542,16 +472,7 @@ class Knit_Graph_Visualizer:
542
472
  self._place_loop(loop, x=x, y=y)
543
473
 
544
474
  def _set_loop_between_yarn_neighbors(self, loop: Loop, y: float, spacing: float = 1.0) -> bool:
545
- """Position a loop based on the average position of its neighboring loops along the yarn.
546
-
547
- Args:
548
- loop (Loop): The loop to position based on its yarn neighbors.
549
- y (float): The y coordinate to assign to the loop.
550
- spacing (float, optional): The minimum spacing to maintain between adjacent loops on the same course. Defaults to 1.0.
551
-
552
- Returns:
553
- bool: True if the loop was successfully positioned, False if no yarn neighbors were available for positioning.
554
- """
475
+ """Position a loop based on the average position of its neighboring loops along the yarn."""
555
476
  spacing = abs(spacing) # Ensure spacing is positive.
556
477
  x_neighbors = []
557
478
  prior_loop = loop.prior_loop_on_yarn()
@@ -573,11 +494,7 @@ class Knit_Graph_Visualizer:
573
494
  return True
574
495
 
575
496
  def _position_base_course(self) -> None:
576
- """Position the loops in the bottom course of the visualization and establish base metrics.
577
-
578
- This method determines whether the base course is knit in the round (tube) or in rows (flat) and positions loops accordingly.
579
- It also establishes the base width and left position for scaling other courses.
580
- """
497
+ """Position the loops in the bottom course of the visualization and establish base metrics."""
581
498
  base_course = self.courses[self.first_course_index]
582
499
  if (len(self.courses) > self.first_course_index + 1 # There are more courses to show after the base course
583
500
  and base_course.in_round_with(self.courses[self.first_course_index + 1])): # The first course is knit in the round to form a tube structure.
@@ -590,13 +507,7 @@ class Knit_Graph_Visualizer:
590
507
  self.base_width = max_x - self.base_left
591
508
 
592
509
  def _get_base_round_course_positions(self, base_course: Course, loop_space: float = 1.0, back_shift: float = 0.5) -> None:
593
- """Position loops in the base course for circular/tube knitting structure.
594
-
595
- Args:
596
- base_course (Course): The base course to position for circular knitting.
597
- loop_space (float, optional): The horizontal spacing between loops in the course. Defaults to 1.0.
598
- back_shift (float, optional): The vertical offset for loops on the back of the tube. Defaults to 0.5.
599
- """
510
+ """Position loops in the base course for circular/tube knitting structure."""
600
511
  split_index = len(base_course) // 2 # Split the course in half to form a tube.
601
512
  front_loops: list[Loop] = cast(list[Loop], base_course[:split_index])
602
513
  front_set: set[Loop] = set(front_loops)
@@ -617,12 +528,7 @@ class Knit_Graph_Visualizer:
617
528
  self._place_loop(back_loop, x=(x * loop_space) - back_shift, y=0)
618
529
 
619
530
  def _get_base_row_course_positions(self, base_course: Course, loop_space: float = 1.0) -> None:
620
- """Position loops in the base course for flat/row knitting structure.
621
-
622
- Args:
623
- base_course (Course): The base course to position for flat knitting.
624
- loop_space (float, optional): The horizontal spacing between loops. Defaults to 1.0.
625
- """
531
+ """Position loops in the base course for flat/row knitting structure."""
626
532
  loops: Iterable[Loop] = list(base_course)
627
533
  if not self.start_on_left:
628
534
  loops = reversed(base_course)
@@ -630,13 +536,7 @@ class Knit_Graph_Visualizer:
630
536
  self._place_loop(loop, x=x * loop_space, y=0)
631
537
 
632
538
  def _left_align_course(self, course: Course) -> None:
633
- """Align the leftmost loop of a course to x=0 if left alignment is enabled.
634
-
635
- The relative positions of all loops in the course are preserved while shifting the entire course horizontally.
636
-
637
- Args:
638
- course (Course): The course to potentially left-align.
639
- """
539
+ """Align the leftmost loop of a course to x=0 if left alignment is enabled."""
640
540
  if self.left_zero_align:
641
541
  current_left = min(self._get_x_of_loop(loop) for loop in course)
642
542
  if current_left != 0.0:
@@ -644,11 +544,7 @@ class Knit_Graph_Visualizer:
644
544
  self._set_x_of_loop(loop, self._get_x_of_loop(loop) - current_left)
645
545
 
646
546
  def _balance_course(self, course: Course) -> None:
647
- """Scale the width of a course to match the base course width if balancing is enabled.
648
-
649
- Args:
650
- course (Course): The course to potentially balance to match the base width.
651
- """
547
+ """Scale the width of a course to match the base course width if balancing is enabled."""
652
548
  current_left = min(self._get_x_of_loop(loop) for loop in course)
653
549
  max_x = max(self._get_x_of_loop(loop) for loop in course)
654
550
  course_width = max_x - current_left
@@ -660,10 +556,60 @@ class Knit_Graph_Visualizer:
660
556
  for loop in course:
661
557
  self._set_x_of_loop(loop, _target_distance_from_left(loop) + current_left)
662
558
 
559
+ def x_coordinate_differences(self, other: Knit_Graph_Visualizer) -> dict[Loop: tuple[float | None, float | None]]:
560
+ """Find the differences in x-coordinates between two knitgraph visualizations. Used for testing and comparing visualization results.
561
+
562
+ Args:
563
+ other (Knit_Graph_Visualizer): The knitgraph visualization to compare to.
564
+
565
+ Returns:
566
+ dict[Loop: tuple[float | None, float | None]]: The differences in x-coordinates.
567
+ * The keys of the dictionary are loops with differences between the two visualizations.
568
+ * The values of the dictionary are tuples of floats or None.
569
+ ** The first value in each tuple is the x-coordinate of the loop in this knitgraph visualization or None if the loop is not in this visualization.
570
+ ** The second value of each tuple is the x-coordinate of the loop in the other visualization or NOne if the loop is not in that visualization.
571
+
572
+ """
573
+ differences = {l: (self._get_x_of_loop(l), None) for l in self.data_graph.nodes if not other.data_graph.has_node(l)}
574
+ differences.update({l: (None, other._get_x_of_loop(l)) for l in other.data_graph.nodes if not self.data_graph.has_node(l)})
575
+ differences.update({l: (self._get_x_of_loop(l), other._get_x_of_loop(l)) for l in self.data_graph.nodes if other.data_graph.has_node(l) and self._get_x_of_loop(l) != other._get_x_of_loop(l)})
576
+ return differences
577
+
578
+ def y_coordinate_differences(self, other: Knit_Graph_Visualizer) -> dict[Loop: tuple[float | None, float | None]]:
579
+ """Find the differences in y-coordinates between two knitgraph visualizations. Used for testing and comparing visualization results.
580
+
581
+ Args:
582
+ other (Knit_Graph_Visualizer): The knitgraph visualization to compare to.
583
+
584
+ Returns:
585
+ dict[Loop: tuple[float | None, float | None]]: The differences in y-coordinates.
586
+ * The keys of the dictionary are loops with differences between the two visualizations.
587
+ * The values of the dictionary are tuples of floats or None.
588
+ ** The first value in each tuple is the y-coordinate of the loop in this knitgraph visualization or None if the loop is not in this visualization.
589
+ ** The second value of each tuple is the y-coordinate of the loop in the other visualization or NOne if the loop is not in that visualization.
590
+
591
+ """
592
+ differences = {l: (self._get_y_of_loop(l), None) for l in self.data_graph.nodes if not other.data_graph.has_node(l)}
593
+ differences.update({l: (None, other._get_y_of_loop(l)) for l in other.data_graph.nodes if not self.data_graph.has_node(l)})
594
+ differences.update({l: (self._get_y_of_loop(l), other._get_y_of_loop(l)) for l in self.data_graph.nodes if other.data_graph.has_node(l) and self._get_y_of_loop(l) != other._get_y_of_loop(l)})
595
+ return differences
596
+
597
+ def __eq__(self, other: Knit_Graph_Visualizer) -> bool:
598
+ """Two visualizations are equal if share the same x,y coordinates for all loops in the visualization and both contain the same set of loop nodes.
599
+ Args:
600
+ other (Knit_Graph_Visualizer): The knitgraph visualization to compare to.
601
+
602
+ Returns:
603
+ bool: True if the knitgraph visualizations are equal, False otherwise.
604
+ """
605
+ return len(self.data_graph.nodes) == len(other.data_graph.nodes) and len(self.x_coordinate_differences(other)) == 0 and len(self.y_coordinate_differences(other)) == 0
663
606
 
664
- def visualize_knit_graph(knit_graph: Knit_Graph, first_course_index: int = 0, top_course_index: int | None = None, start_on_left: bool = True, balance_by_base_width: bool = False,
665
- left_zero_align: bool = True, graph_title: str = "knit_graph", show_figure: bool = True) -> None:
666
- """Generate and display a plotly visualization of the given knit graph with specified configuration.
607
+
608
+ def visualize_knit_graph(knit_graph: Knit_Graph, first_course_index: int = 0, top_course_index: int | None = None,
609
+ start_on_left: bool = True, balance_by_base_width: bool = False,
610
+ left_zero_align: bool = True, graph_title: str = "knit_graph",
611
+ show_figure: bool = True, renderer: str | None = None) -> Figure:
612
+ """Generate and optionally display a plotly visualization of the given knit graph with specified configuration.
667
613
 
668
614
  Args:
669
615
  knit_graph (Knit_Graph): The knit graph to visualize.
@@ -674,7 +620,56 @@ def visualize_knit_graph(knit_graph: Knit_Graph, first_course_index: int = 0, to
674
620
  left_zero_align (bool): Whether to align the leftmost position of each course with x=0 in the figure. Defaults to True.
675
621
  graph_title (str): The title to display on the generated figure. Defaults to "knit_graph".
676
622
  show_figure (bool, optional): If True, the visualization will be shown. Defaults to True.
623
+ renderer (str, optional): Plotly renderer to use. Common options: 'browser', 'notebook'. Defaults to None (uses configured default).
624
+
625
+ Returns:
626
+ Figure: The plotly figure object.
677
627
  """
678
628
  visualizer = Knit_Graph_Visualizer(knit_graph, first_course_index, top_course_index, start_on_left, balance_by_base_width, left_zero_align)
629
+ fig = visualizer.make_figure(graph_title)
630
+
679
631
  if show_figure:
680
- visualizer.make_figure(graph_title)
632
+ try:
633
+ # Configure display to minimize resource usage
634
+ config = {
635
+ 'displayModeBar': False, # Hide toolbar to reduce resource usage
636
+ 'displaylogo': False, # Hide plotly logo
637
+ 'staticPlot': False, # Keep interactive
638
+ 'scrollZoom': True, # Allow zoom
639
+ 'doubleClick': 'reset+autosize' # Double-click behavior
640
+ }
641
+
642
+ if renderer:
643
+ fig.show(renderer=renderer, config=config)
644
+ else:
645
+ fig.show(config=config)
646
+ except Exception as e:
647
+ print(f"Warning: Could not display figure '{graph_title}': {e}")
648
+ print("Figure created successfully but display failed.")
649
+
650
+ return fig
651
+
652
+
653
+ def visualize_knit_graph_safe(knit_graph: Knit_Graph, first_course_index: int = 0, top_course_index: int | None = None,
654
+ start_on_left: bool = True, balance_by_base_width: bool = False,
655
+ left_zero_align: bool = True, graph_title: str = "knit_graph") -> Figure:
656
+ """Generate a plotly visualization of the given knit graph with specified configuration.
657
+ This function is safe for UnitTest and other headless environments because it does not attempt to show the visualization.
658
+
659
+ Args:
660
+ knit_graph (Knit_Graph): The knit graph to visualize.
661
+ first_course_index (int): Index of the first (bottom) course to include in the visualization. Defaults to 0.
662
+ top_course_index (int | None): Index of the last (top) course to include in the visualization. If None, visualizes up to the top of the knit graph.
663
+ start_on_left (bool): Whether the first loop knit is presumed to be positioned on the left of the pattern. Defaults to True.
664
+ balance_by_base_width (bool): Whether to scale all course widths to match the first course width. Defaults to False.
665
+ left_zero_align (bool): Whether to align the leftmost position of each course with x=0 in the figure. Defaults to True.
666
+ graph_title (str): The title to display on the generated figure. Defaults to "knit_graph".
667
+
668
+ Returns:
669
+ Figure: The plotly figure object.
670
+ """
671
+ return visualize_knit_graph(knit_graph, first_course_index=first_course_index, top_course_index=top_course_index,
672
+ start_on_left=start_on_left,
673
+ balance_by_base_width=balance_by_base_width,
674
+ left_zero_align=left_zero_align, graph_title=graph_title,
675
+ show_figure=False)
@@ -5,6 +5,7 @@ These functions serve as building blocks for testing and demonstration purposes.
5
5
  """
6
6
  from knit_graphs.artin_wale_braids.Crossing_Direction import Crossing_Direction
7
7
  from knit_graphs.Knit_Graph import Knit_Graph
8
+ from knit_graphs.Loop import Loop
8
9
  from knit_graphs.Pull_Direction import Pull_Direction
9
10
  from knit_graphs.Yarn import Yarn
10
11
 
@@ -153,105 +154,53 @@ def seed_swatch(width: int, height: int) -> Knit_Graph:
153
154
  return knit_graph
154
155
 
155
156
 
156
- def kp_mesh_decrease_left_swatch(width: int, height: int) -> Knit_Graph:
157
- """Generate a mesh pattern with left-leaning decreases and yarn overs in knit-purl ribbing.
158
-
159
- This creates an openwork mesh pattern where purl stitches are decreased leftward on even courses and replaced with yarn overs,
160
- creating decorative holes in the fabric while maintaining the overall stitch count.
157
+ def lace_mesh(width: int, height: int) -> Knit_Graph:
158
+ """Generate a mesh pattern with alternating left and right leaning decrease paired to yarn-overs.
159
+ These pairings create a basic lace pattern with eyelets formed around the increases.
161
160
 
162
161
  Args:
163
162
  width (int): The number of stitches per course (horizontal row).
164
163
  height (int): The number of courses (vertical rows) in the swatch.
165
164
 
166
165
  Returns:
167
- Knit_Graph: A knit graph representing a mesh swatch with left-leaning decreases and yarn overs.
166
+ Knit_Graph: A knit graph representing a mesh swatch.
168
167
  """
169
- # k<o k<o k <-: 1->2
170
- # |\ |\
171
- # k p k p k ->: 0->1
172
- # 0 1 2 3 4
173
168
  knit_graph, yarn = co_loops(width)
174
169
  last_course = knit_graph.get_courses()[0]
175
170
  next_course = []
176
- next_pull = Pull_Direction.BtF
177
171
  for parent_loop in reversed(last_course):
178
172
  child_loop = yarn.make_loop_on_end()
179
- knit_graph.connect_loops(parent_loop, child_loop, pull_direction=next_pull)
180
- next_pull = next_pull.opposite()
173
+ knit_graph.connect_loops(parent_loop, child_loop, pull_direction=Pull_Direction.BtF)
181
174
  next_course.append(child_loop)
182
175
  last_course = next_course
183
176
  for _ in range(1, height):
177
+ # Make the lace course
184
178
  next_course = []
185
- for parent_loop in reversed(last_course):
179
+ yo_parent = None
180
+ prior_child = None
181
+ for i, parent_loop in enumerate(reversed(last_course)):
186
182
  child_loop = yarn.make_loop_on_end()
187
- grand_parent = parent_loop.parent_loops[0]
188
- parent_pull = knit_graph.get_pull_direction(grand_parent, parent_loop)
189
- if parent_pull is Pull_Direction.BtF: # knits stay in decrease at bottom of stack
183
+ if i % 3 == 0: # Just knit every third stitch
190
184
  knit_graph.connect_loops(parent_loop, child_loop, pull_direction=Pull_Direction.BtF, stack_position=0)
191
- prior_parent = yarn.prior_loop(parent_loop)
192
- if prior_parent is not None and prior_parent in last_course:
193
- knit_graph.connect_loops(prior_parent, child_loop, pull_direction=Pull_Direction.FtB, stack_position=1)
194
- next_course.append(child_loop)
195
- last_course = next_course
196
- next_course = []
197
- for parent_loop in reversed(last_course):
198
- child_loop = yarn.make_loop_on_end()
199
- if len(parent_loop.parent_loops) == 0:
200
- knit_graph.connect_loops(parent_loop, child_loop, pull_direction=Pull_Direction.FtB)
201
- else:
202
- knit_graph.connect_loops(parent_loop, child_loop, pull_direction=Pull_Direction.BtF)
203
- next_course.append(child_loop)
204
- last_course = next_course
205
- return knit_graph
206
-
207
-
208
- def kp_mesh_decrease_right_swatch(width: int, height: int) -> Knit_Graph:
209
- """Generate a mesh pattern with right-leaning decreases and yarn overs in knit-purl ribbing.
210
-
211
- This creates an openwork mesh pattern where purl stitches are decreased rightward on even courses and replaced with yarn overs,
212
- creating decorative holes in the fabric while maintaining the overall stitch count.
213
-
214
- Args:
215
- width (int): The number of stitches per course (horizontal row).
216
- height (int): The number of courses (vertical rows) in the swatch.
217
-
218
- Returns:
219
- Knit_Graph: A knit graph representing a mesh swatch with right-leaning decreases and yarn overs.
220
- """
221
- # k o>k o>k <-: 1->2
222
- # /| /|
223
- # k p k p k ->: 0->1
224
- # 0 1 2 3 4
225
- knit_graph, yarn = co_loops(width)
226
- last_course = knit_graph.get_courses()[0]
227
- next_course = []
228
- next_pull = Pull_Direction.BtF
229
- for parent_loop in reversed(last_course):
230
- child_loop = yarn.make_loop_on_end()
231
- knit_graph.connect_loops(parent_loop, child_loop, pull_direction=next_pull)
232
- next_pull = next_pull.opposite()
233
- next_course.append(child_loop)
234
- last_course = next_course
235
- for _ in range(1, height):
236
- next_course = []
237
- for parent_loop in reversed(last_course):
238
- child_loop = yarn.make_loop_on_end()
239
- grand_parent = parent_loop.parent_loops[0]
240
- parent_pull = knit_graph.get_pull_direction(grand_parent, parent_loop)
241
- if parent_pull is Pull_Direction.BtF: # knits stay in decrease at bottom of stack
185
+ elif i % 6 == 1: # Second of every 6 stitches (0 indexed) is yarn over before a decrease.
186
+ yo_parent = parent_loop
187
+ elif i % 6 == 2: # Third of every 6 stitches is bottom of decrease with prior yarn-over's parent
188
+ knit_graph.connect_loops(parent_loop, child_loop, pull_direction=Pull_Direction.BtF, stack_position=0)
189
+ assert isinstance(yo_parent, Loop)
190
+ knit_graph.connect_loops(yo_parent, child_loop, pull_direction=Pull_Direction.BtF, stack_position=1)
191
+ elif i % 6 == 4: # Fifth of every six stitches is bottom of decrease with next yarn-over's parent
242
192
  knit_graph.connect_loops(parent_loop, child_loop, pull_direction=Pull_Direction.BtF, stack_position=0)
243
- next_parent = yarn.next_loop(parent_loop)
244
- if next_parent is not None:
245
- knit_graph.connect_loops(next_parent, child_loop, pull_direction=Pull_Direction.FtB, stack_position=1)
193
+ prior_child = child_loop
194
+ elif i % 6 == 5: # The last of six stitches is the top of the prior decrease and new yarn-over
195
+ assert isinstance(prior_child, Loop)
196
+ knit_graph.connect_loops(parent_loop, prior_child, pull_direction=Pull_Direction.BtF, stack_position=1)
246
197
  next_course.append(child_loop)
247
198
  last_course = next_course
199
+ # Make a basic jersey course
248
200
  next_course = []
249
201
  for parent_loop in reversed(last_course):
250
202
  child_loop = yarn.make_loop_on_end()
251
- if len(parent_loop.parent_loops) == 0:
252
- knit_graph.connect_loops(parent_loop, child_loop, pull_direction=Pull_Direction.FtB)
253
- else:
254
- knit_graph.connect_loops(parent_loop, child_loop, pull_direction=Pull_Direction.BtF)
203
+ knit_graph.connect_loops(parent_loop, child_loop, pull_direction=Pull_Direction.BtF)
255
204
  next_course.append(child_loop)
256
205
  last_course = next_course
257
206
  return knit_graph
@@ -1,58 +0,0 @@
1
- knit\_graphs.artin\_wale\_braids package
2
- ========================================
3
-
4
- .. automodule:: knit_graphs.artin_wale_braids
5
- :members:
6
- :undoc-members:
7
- :show-inheritance:
8
-
9
- Submodules
10
- ----------
11
-
12
- knit\_graphs.artin\_wale\_braids.Crossing\_Direction module
13
- -----------------------------------------------------------
14
-
15
- .. automodule:: knit_graphs.artin_wale_braids.Crossing_Direction
16
- :members:
17
- :undoc-members:
18
- :show-inheritance:
19
-
20
- knit\_graphs.artin\_wale\_braids.Loop\_Braid\_Graph module
21
- ----------------------------------------------------------
22
-
23
- .. automodule:: knit_graphs.artin_wale_braids.Loop_Braid_Graph
24
- :members:
25
- :undoc-members:
26
- :show-inheritance:
27
-
28
- knit\_graphs.artin\_wale\_braids.Wale module
29
- --------------------------------------------
30
-
31
- .. automodule:: knit_graphs.artin_wale_braids.Wale
32
- :members:
33
- :undoc-members:
34
- :show-inheritance:
35
-
36
- knit\_graphs.artin\_wale\_braids.Wale\_Braid module
37
- ---------------------------------------------------
38
-
39
- .. automodule:: knit_graphs.artin_wale_braids.Wale_Braid
40
- :members:
41
- :undoc-members:
42
- :show-inheritance:
43
-
44
- knit\_graphs.artin\_wale\_braids.Wale\_Braid\_Word module
45
- ---------------------------------------------------------
46
-
47
- .. automodule:: knit_graphs.artin_wale_braids.Wale_Braid_Word
48
- :members:
49
- :undoc-members:
50
- :show-inheritance:
51
-
52
- knit\_graphs.artin\_wale\_braids.Wale\_Group module
53
- ---------------------------------------------------
54
-
55
- .. automodule:: knit_graphs.artin_wale_braids.Wale_Group
56
- :members:
57
- :undoc-members:
58
- :show-inheritance:
@@ -1,74 +0,0 @@
1
- knit\_graphs package
2
- ====================
3
-
4
- .. automodule:: knit_graphs
5
- :members:
6
- :undoc-members:
7
- :show-inheritance:
8
-
9
- Subpackages
10
- -----------
11
-
12
- .. toctree::
13
- :maxdepth: 4
14
-
15
- knit_graphs.artin_wale_braids
16
-
17
- Submodules
18
- ----------
19
-
20
- knit\_graphs.Course module
21
- --------------------------
22
-
23
- .. automodule:: knit_graphs.Course
24
- :members:
25
- :undoc-members:
26
- :show-inheritance:
27
-
28
- knit\_graphs.Knit\_Graph module
29
- -------------------------------
30
-
31
- .. automodule:: knit_graphs.Knit_Graph
32
- :members:
33
- :undoc-members:
34
- :show-inheritance:
35
-
36
- knit\_graphs.Knit\_Graph\_Visualizer module
37
- -------------------------------------------
38
-
39
- .. automodule:: knit_graphs.Knit_Graph_Visualizer
40
- :members:
41
- :undoc-members:
42
- :show-inheritance:
43
-
44
- knit\_graphs.Loop module
45
- ------------------------
46
-
47
- .. automodule:: knit_graphs.Loop
48
- :members:
49
- :undoc-members:
50
- :show-inheritance:
51
-
52
- knit\_graphs.Pull\_Direction module
53
- -----------------------------------
54
-
55
- .. automodule:: knit_graphs.Pull_Direction
56
- :members:
57
- :undoc-members:
58
- :show-inheritance:
59
-
60
- knit\_graphs.Yarn module
61
- ------------------------
62
-
63
- .. automodule:: knit_graphs.Yarn
64
- :members:
65
- :undoc-members:
66
- :show-inheritance:
67
-
68
- knit\_graphs.basic\_knit\_graph\_generators module
69
- --------------------------------------------------
70
-
71
- .. automodule:: knit_graphs.basic_knit_graph_generators
72
- :members:
73
- :undoc-members:
74
- :show-inheritance:
File without changes
File without changes
File without changes
File without changes