arrscope 0.2.0__tar.gz → 0.3.0__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 (31) hide show
  1. arrscope-0.3.0/PKG-INFO +158 -0
  2. arrscope-0.3.0/README.md +131 -0
  3. arrscope-0.3.0/examples/renders.py +71 -0
  4. {arrscope-0.2.0 → arrscope-0.3.0}/main.py +2 -2
  5. {arrscope-0.2.0 → arrscope-0.3.0}/pyproject.toml +1 -1
  6. {arrscope-0.2.0 → arrscope-0.3.0}/src/arrscope/_api.py +29 -79
  7. arrscope-0.3.0/src/arrscope/_config.py +10 -0
  8. {arrscope-0.2.0 → arrscope-0.3.0}/src/arrscope/_types.py +11 -0
  9. {arrscope-0.2.0 → arrscope-0.3.0}/src/arrscope/renderers/html.py +2 -17
  10. {arrscope-0.2.0 → arrscope-0.3.0}/src/arrscope/renderers/terminal.py +17 -31
  11. {arrscope-0.2.0 → arrscope-0.3.0}/uv.lock +1 -1
  12. arrscope-0.2.0/PKG-INFO +0 -185
  13. arrscope-0.2.0/README.md +0 -158
  14. arrscope-0.2.0/src/arrscope/_config.py +0 -15
  15. {arrscope-0.2.0 → arrscope-0.3.0}/.gitignore +0 -0
  16. {arrscope-0.2.0 → arrscope-0.3.0}/docs/ADR-001-visual-grammar.md +0 -0
  17. {arrscope-0.2.0 → arrscope-0.3.0}/docs/ADR-002-architecture.md +0 -0
  18. {arrscope-0.2.0 → arrscope-0.3.0}/docs/ADR-003-api-design.md +0 -0
  19. {arrscope-0.2.0 → arrscope-0.3.0}/docs/GLOSSARY.md +0 -0
  20. {arrscope-0.2.0 → arrscope-0.3.0}/src/arrscope/__init__.py +0 -0
  21. {arrscope-0.2.0 → arrscope-0.3.0}/src/arrscope/__main__.py +0 -0
  22. {arrscope-0.2.0 → arrscope-0.3.0}/src/arrscope/_format.py +0 -0
  23. {arrscope-0.2.0 → arrscope-0.3.0}/src/arrscope/_layout.py +0 -0
  24. {arrscope-0.2.0 → arrscope-0.3.0}/src/arrscope/adapters/__init__.py +0 -0
  25. {arrscope-0.2.0 → arrscope-0.3.0}/src/arrscope/adapters/_core.py +0 -0
  26. {arrscope-0.2.0 → arrscope-0.3.0}/src/arrscope/renderers/__init__.py +0 -0
  27. {arrscope-0.2.0 → arrscope-0.3.0}/test.ipynb +0 -0
  28. {arrscope-0.2.0 → arrscope-0.3.0}/tests/test_adapter.py +0 -0
  29. {arrscope-0.2.0 → arrscope-0.3.0}/tests/test_format.py +0 -0
  30. {arrscope-0.2.0 → arrscope-0.3.0}/tests/test_layout.py +0 -0
  31. {arrscope-0.2.0 → arrscope-0.3.0}/tests/test_stats.py +0 -0
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.4
2
+ Name: arrscope
3
+ Version: 0.3.0
4
+ Summary: Beautiful n-dimensional array visualization for Python
5
+ Project-URL: Homepage, https://github.com/vizarray/arrscope
6
+ Project-URL: Repository, https://github.com/vizarray/arrscope
7
+ Author: arrscope contributors
8
+ License: MIT
9
+ Keywords: arrays,data-science,machine-learning,numpy,visualization
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Scientific/Engineering :: Visualization
17
+ Requires-Python: >=3.11
18
+ Requires-Dist: numpy>=1.24
19
+ Requires-Dist: rich>=13.0
20
+ Provides-Extra: jax
21
+ Requires-Dist: jax>=0.4; extra == 'jax'
22
+ Provides-Extra: tf
23
+ Requires-Dist: tensorflow>=2.12; extra == 'tf'
24
+ Provides-Extra: torch
25
+ Requires-Dist: torch>=2.0; extra == 'torch'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # arrscope
29
+
30
+ Visualize n-dimensional arrays in the terminal and Jupyter — with structural trees, tiled mosaics, and color-coded value maps.
31
+
32
+ ```python
33
+ from arrscope import scope
34
+ import numpy as np
35
+
36
+ scope(np.random.rand(3, 4, 5))
37
+ ```
38
+
39
+ ## Features
40
+
41
+ - **1D → 6D+**: Tiered visual grammar — lists, grids, trees, nested layers
42
+ - **Named axes**: Attach semantics (`batch`, `heads`, `h`, `w`)
43
+ - **Three color modes**:
44
+ - `dtype` — semantic colors by data type (blue=float, green=int, …)
45
+ - `heatmap` — diverging colormap (red → light → blue) by value
46
+ - `sparsity` — zeros as `·`, non-zeros in bold
47
+ - **Two render styles**:
48
+ - `tree` (default) — hierarchical branch view with colored guide lines
49
+ - `mosaic` — all 2D sub-slices tiled side by side as numeric tables
50
+ - **Method chaining**: `scope(arr, mode="heatmap").tree().mosaic()` — switch styles without re-specifying
51
+ - **Stats overlay**: min, max, mean, std, zero%, NaN count (always shown)
52
+ - **Head/tail truncation**: large dims show first/last N slices with `…` (default 20)
53
+ - **Smart precision**: auto-detects significant figures for floats
54
+ - **Terminal + Jupyter**: Rich ANSI + static HTML/CSS with dark mode auto-detect
55
+ - **Multi-framework**: NumPy, PyTorch, TensorFlow, JAX, tinygrad (lazy imports)
56
+ - **Zero config**: color always on, stats always on, auto-detect terminal vs notebook
57
+
58
+ ## Install
59
+
60
+ ```bash
61
+ pip install arrscope
62
+ ```
63
+
64
+ Only requires `numpy` + `rich`. Torch/TF/JAX/tinygrad are optional.
65
+
66
+ ## Quick start
67
+
68
+ ```python
69
+ from arrscope import scope
70
+ import numpy as np
71
+
72
+ # Auto-detect — last 2 dims form the grid
73
+ scope(np.random.rand(3, 4, 5))
74
+
75
+ # Named axes
76
+ scope(
77
+ np.random.rand(2, 8, 32, 32),
78
+ axes=['batch', 'heads', 'h', 'w'],
79
+ grid=['h', 'w'],
80
+ title='Attention heads',
81
+ )
82
+
83
+ # Custom grid dims
84
+ scope(data, axes=['a', 'b', 'c', 'd'], grid=['a', 'b'])
85
+ ```
86
+
87
+ ## Color modes
88
+
89
+ ```python
90
+ scope(arr, mode='dtype') # default
91
+ scope(arr, mode='heatmap') # diverging colormap
92
+ scope(arr, mode='sparsity') # · for zeros, bold for non-zeros
93
+ ```
94
+
95
+ ## Render styles
96
+
97
+ ```python
98
+ scope(arr) # tree (default) — click-to-expand layers
99
+ scope(arr, render_style='mosaic') # all sub-slices tiled side by side
100
+
101
+ # Method chaining for switching styles
102
+ r = scope(arr, mode='heatmap')
103
+ print(r.tree())
104
+ print(r.mosaic())
105
+ ```
106
+
107
+ ## CLI
108
+
109
+ ```bash
110
+ arrscope 3x4x5
111
+ arrscope 2x3x32x32 --axes batch heads h w --grid h w --mode heatmap
112
+ arrscope 20x4x5 --max-height 6
113
+ ```
114
+
115
+ ## Framework support
116
+
117
+ ```python
118
+ import torch
119
+ scope(torch.randn(2, 3, 4))
120
+
121
+ import tensorflow as tf
122
+ scope(tf.random.uniform((2, 3, 4)))
123
+
124
+ import jax.numpy as jnp
125
+ scope(jnp.array([[1, 2], [3, 4]]))
126
+
127
+ from tinygrad import Tensor
128
+ scope(Tensor.randn(3, 4))
129
+ ```
130
+
131
+ ## API
132
+
133
+ ```python
134
+ scope(
135
+ arr,
136
+ axes=None, # list[str] — name each dimension
137
+ grid=None, # list[str | int] — which dims form the leaf grid
138
+ title=None, # str — heading above the visualization
139
+ max_height=20, # int | None — rows before truncation, None disables
140
+ fmt=None, # str — format spec like '.4f'
141
+ mode='dtype', # 'dtype' | 'heatmap' | 'sparsity'
142
+ render_style='tree', # 'tree' | 'mosaic'
143
+ )
144
+ ```
145
+
146
+ ## Development
147
+
148
+ ```bash
149
+ git clone https://github.com/vizarray/arrscope
150
+ cd arrscope
151
+ uv sync
152
+ uv run pytest
153
+ uv run python main.py
154
+ ```
155
+
156
+ ## License
157
+
158
+ MIT
@@ -0,0 +1,131 @@
1
+ # arrscope
2
+
3
+ Visualize n-dimensional arrays in the terminal and Jupyter — with structural trees, tiled mosaics, and color-coded value maps.
4
+
5
+ ```python
6
+ from arrscope import scope
7
+ import numpy as np
8
+
9
+ scope(np.random.rand(3, 4, 5))
10
+ ```
11
+
12
+ ## Features
13
+
14
+ - **1D → 6D+**: Tiered visual grammar — lists, grids, trees, nested layers
15
+ - **Named axes**: Attach semantics (`batch`, `heads`, `h`, `w`)
16
+ - **Three color modes**:
17
+ - `dtype` — semantic colors by data type (blue=float, green=int, …)
18
+ - `heatmap` — diverging colormap (red → light → blue) by value
19
+ - `sparsity` — zeros as `·`, non-zeros in bold
20
+ - **Two render styles**:
21
+ - `tree` (default) — hierarchical branch view with colored guide lines
22
+ - `mosaic` — all 2D sub-slices tiled side by side as numeric tables
23
+ - **Method chaining**: `scope(arr, mode="heatmap").tree().mosaic()` — switch styles without re-specifying
24
+ - **Stats overlay**: min, max, mean, std, zero%, NaN count (always shown)
25
+ - **Head/tail truncation**: large dims show first/last N slices with `…` (default 20)
26
+ - **Smart precision**: auto-detects significant figures for floats
27
+ - **Terminal + Jupyter**: Rich ANSI + static HTML/CSS with dark mode auto-detect
28
+ - **Multi-framework**: NumPy, PyTorch, TensorFlow, JAX, tinygrad (lazy imports)
29
+ - **Zero config**: color always on, stats always on, auto-detect terminal vs notebook
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ pip install arrscope
35
+ ```
36
+
37
+ Only requires `numpy` + `rich`. Torch/TF/JAX/tinygrad are optional.
38
+
39
+ ## Quick start
40
+
41
+ ```python
42
+ from arrscope import scope
43
+ import numpy as np
44
+
45
+ # Auto-detect — last 2 dims form the grid
46
+ scope(np.random.rand(3, 4, 5))
47
+
48
+ # Named axes
49
+ scope(
50
+ np.random.rand(2, 8, 32, 32),
51
+ axes=['batch', 'heads', 'h', 'w'],
52
+ grid=['h', 'w'],
53
+ title='Attention heads',
54
+ )
55
+
56
+ # Custom grid dims
57
+ scope(data, axes=['a', 'b', 'c', 'd'], grid=['a', 'b'])
58
+ ```
59
+
60
+ ## Color modes
61
+
62
+ ```python
63
+ scope(arr, mode='dtype') # default
64
+ scope(arr, mode='heatmap') # diverging colormap
65
+ scope(arr, mode='sparsity') # · for zeros, bold for non-zeros
66
+ ```
67
+
68
+ ## Render styles
69
+
70
+ ```python
71
+ scope(arr) # tree (default) — click-to-expand layers
72
+ scope(arr, render_style='mosaic') # all sub-slices tiled side by side
73
+
74
+ # Method chaining for switching styles
75
+ r = scope(arr, mode='heatmap')
76
+ print(r.tree())
77
+ print(r.mosaic())
78
+ ```
79
+
80
+ ## CLI
81
+
82
+ ```bash
83
+ arrscope 3x4x5
84
+ arrscope 2x3x32x32 --axes batch heads h w --grid h w --mode heatmap
85
+ arrscope 20x4x5 --max-height 6
86
+ ```
87
+
88
+ ## Framework support
89
+
90
+ ```python
91
+ import torch
92
+ scope(torch.randn(2, 3, 4))
93
+
94
+ import tensorflow as tf
95
+ scope(tf.random.uniform((2, 3, 4)))
96
+
97
+ import jax.numpy as jnp
98
+ scope(jnp.array([[1, 2], [3, 4]]))
99
+
100
+ from tinygrad import Tensor
101
+ scope(Tensor.randn(3, 4))
102
+ ```
103
+
104
+ ## API
105
+
106
+ ```python
107
+ scope(
108
+ arr,
109
+ axes=None, # list[str] — name each dimension
110
+ grid=None, # list[str | int] — which dims form the leaf grid
111
+ title=None, # str — heading above the visualization
112
+ max_height=20, # int | None — rows before truncation, None disables
113
+ fmt=None, # str — format spec like '.4f'
114
+ mode='dtype', # 'dtype' | 'heatmap' | 'sparsity'
115
+ render_style='tree', # 'tree' | 'mosaic'
116
+ )
117
+ ```
118
+
119
+ ## Development
120
+
121
+ ```bash
122
+ git clone https://github.com/vizarray/arrscope
123
+ cd arrscope
124
+ uv sync
125
+ uv run pytest
126
+ uv run python main.py
127
+ ```
128
+
129
+ ## License
130
+
131
+ MIT
@@ -0,0 +1,71 @@
1
+ """arrscope render style examples.
2
+
3
+ Run this file to see both render styles in action.
4
+ Use method chaining to switch styles without re-specifying params.
5
+
6
+ Usage:
7
+ uv run python examples/renders.py
8
+ """
9
+
10
+ import numpy as np
11
+
12
+ from arrscope import scope
13
+
14
+ # ── data ──────────────────────────────────────────────────────────────
15
+ arr_3d = np.arange(60).reshape(3, 4, 5).astype(float)
16
+ eye = np.eye(8)
17
+ sparse = np.zeros((6, 8), dtype=float)
18
+ sparse[0, 0] = 1.5
19
+ sparse[2, 3] = -2.3
20
+ sparse[4, 5] = 42.0
21
+ sparse[5, 7] = 0.7
22
+
23
+
24
+ # ── individual calls ──────────────────────────────────────────────────
25
+ print("=" * 56)
26
+ print("1 tree — hierarchical branch view (default)")
27
+ print("=" * 56)
28
+ print(scope(arr_3d, render_style="tree"))
29
+
30
+ print("=" * 56)
31
+ print("2 mosaic — numeric tables tiled side by side")
32
+ print("=" * 56)
33
+ print(scope(arr_3d, render_style="mosaic"))
34
+
35
+
36
+ # ── method chaining ───────────────────────────────────────────────────
37
+ print("=" * 56)
38
+ print("3 method chaining — scope().tree() / .mosaic()")
39
+ print("=" * 56)
40
+
41
+ r = scope(eye, title="Identity", mode="heatmap")
42
+
43
+ print("--- .tree() ---")
44
+ print(r.tree())
45
+
46
+ print("--- .mosaic() ---")
47
+ print(r.mosaic())
48
+
49
+
50
+ # ── all three modes with mosaic ──────────────────────────────────────
51
+ print("=" * 56)
52
+ print("4 mosaic + all three color modes")
53
+ print("=" * 56)
54
+
55
+ print("--- dtype ---")
56
+ print(scope(sparse, render_style="mosaic", mode="dtype"))
57
+
58
+ print("--- heatmap ---")
59
+ print(scope(sparse, render_style="mosaic", mode="heatmap"))
60
+
61
+ print("--- sparsity ---")
62
+ print(scope(sparse, render_style="mosaic", mode="sparsity"))
63
+
64
+
65
+ # ── large array in mosaic ────────────────────────────────────────────
66
+ print("=" * 56)
67
+ print("5 large array — (8, 8, 8) as mosaic + heatmap")
68
+ print("=" * 56)
69
+ print(scope(np.random.rand(8, 8, 8), render_style="mosaic", mode="heatmap"))
70
+
71
+ print("\nDone!")
@@ -62,8 +62,8 @@ print(scope(sparse, mode="sparsity"))
62
62
  print("\n1️⃣2️⃣ HEATMAP + 3D + global stats")
63
63
  print(scope(np.random.rand(2, 3, 4), mode="heatmap"))
64
64
 
65
- print("\n1️⃣3️⃣ STATS OFF")
66
- print(scope(np.eye(5), stats=False))
65
+ print("\n1️⃣3️⃣ TRUNCATION OFF (max_height=None)")
66
+ print(scope(np.arange(60).reshape(3, 4, 5).astype(float), max_height=None))
67
67
 
68
68
  print("\n1️⃣4️⃣ MOSAIC — 3×4×5 tiled (no tree)")
69
69
  arr = np.arange(60).reshape(3, 4, 5).astype(float)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "arrscope"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "Beautiful n-dimensional array visualization for Python"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -1,8 +1,5 @@
1
- from __future__ import annotations
2
-
3
1
  from typing import Literal
4
2
 
5
- from arrscope._config import config
6
3
  from arrscope._format import format_value
7
4
  from arrscope._layout import build_layout, compute_stats
8
5
  from arrscope._types import VizOutput
@@ -19,14 +16,10 @@ def scope(
19
16
  axes: list[str] | None = None,
20
17
  grid: list[str | int] | None = None,
21
18
  title: str | None = None,
22
- max_width: int | None = None,
23
- max_height: int | None = None,
19
+ max_height: int | None = 20,
24
20
  fmt: str | None = None,
25
- color: bool | None = None,
26
- style: Literal["auto", "terminal", "html"] = "auto",
27
21
  mode: Mode | None = None,
28
22
  render_style: RenderStyle | None = None,
29
- stats: bool | None = None,
30
23
  ) -> VizOutput:
31
24
  """Visualize an n-dimensional array in the terminal and/or Jupyter.
32
25
 
@@ -45,41 +38,30 @@ def scope(
45
38
  title: Optional heading displayed above the visualization.
46
39
  max_height: Max tree rows before truncation. The first half and
47
40
  last half of children are shown with ``... (N more)`` in between.
48
- max_width: Max character width (terminal only). Not yet enforced.
41
+ Defaults to 20. Set to ``None`` to disable truncation.
49
42
  fmt: Format spec for float values, e.g. ``".4f"``, ``".2e"``.
50
43
  Auto-detected from value range when not set.
51
- color: Enable or disable ANSI / CSS color output.
52
- Defaults to ``True``.
53
- style: Output target. ``"auto"`` detects Jupyter and renders
54
- HTML there, ANSI elsewhere. ``"terminal"`` forces ANSI,
55
- ``"html"`` forces HTML.
56
44
  mode: Colorization strategy:
57
45
 
58
- - ``"dtype"`` — Semantic colors by data type (blue=float,
59
- green=int, magenta=bool, yellow=str, red=complex).
46
+ - ``"dtype"`` (default) — Semantic colors by data type
47
+ (blue=float, green=int, magenta=bool, yellow=str).
60
48
  Negative values tinted red, positive tinted blue.
61
49
  - ``"heatmap"`` — Diverging colormap (red → light → blue)
62
- scaled to the array's global min/max range. Best for
63
- spotting value patterns.
50
+ scaled to the array's global min/max range.
64
51
  - ``"sparsity"`` — Zeros rendered as dim ``·``, non-zero
65
- values in bold. Best for inspecting sparse or masked arrays.
66
-
67
- render_style: Visual layout style:
52
+ values in bold.
68
53
 
69
- - ``"tree"`` (default) — Hierarchical branch view with 2D
70
- grids nested at the leaves. Each depth level gets a
71
- distinct branch color for readability.
72
- - ``"mosaic"`` — All 2D sub-slices tiled side by side in a
73
- contact-sheet grid. Best for comparing slices in 3D/4D
74
- arrays (batches, attention heads, channels).
54
+ render_style: Visual layout:
75
55
 
76
- stats: Show summary statistics below the tree (min, max, mean,
77
- std, zeros %, NaN count). Defaults to ``True``.
56
+ - ``"tree"`` (default) Hierarchical branch view with
57
+ click-to-expand nested layers.
58
+ - ``"mosaic"`` — All 2D sub-slices tiled side by side as
59
+ numeric tables.
78
60
 
79
61
  Returns:
80
- A ``VizOutput`` object with ``.ansi`` (str) and ``.html`` (str)
81
- attributes. In Jupyter it auto-displays via ``_repr_html_``.
82
- In the terminal, ``print()`` or ``str()`` renders the ANSI output.
62
+ A ``VizOutput`` with ``.ansi`` and ``.html`` attributes.
63
+ Use ``.tree()`` or ``.mosaic()`` to switch render styles
64
+ without re-specifying parameters.
83
65
 
84
66
  Examples:
85
67
  >>> import numpy as np
@@ -96,12 +78,8 @@ def scope(
96
78
  """
97
79
  arr_np = to_numpy(arr)
98
80
 
99
- color = config.color if color is None else color
100
- max_width = max_width or config.max_width
101
- max_height = max_height or config.max_height
102
- mode = mode or config.mode
103
- rs = render_style or config.render_style
104
- show_stats = config.stats if stats is None else stats
81
+ mode = mode or "dtype"
82
+ rs = render_style or "tree"
105
83
 
106
84
  if mode not in ("dtype", "heatmap", "sparsity"):
107
85
  raise ValueError(f"Unknown mode '{mode}'. Expected one of: dtype, heatmap, sparsity")
@@ -110,37 +88,25 @@ def scope(
110
88
  raise ValueError(f"Unknown render_style '{rs}'. Expected one of: tree, mosaic")
111
89
 
112
90
  grid_dims = _resolve_grid_dims(arr_np, axes, grid)
91
+ use_html = _in_jupyter()
113
92
 
114
- node = build_layout(
115
- arr_np,
116
- grid_dims=grid_dims,
117
- max_height=max_height,
118
- )
119
-
120
- global_stats = compute_stats(arr_np) if (show_stats or mode == "heatmap") else None
121
- if global_stats and show_stats:
122
- node.stats = global_stats
123
-
124
- use_html = _use_html(style)
125
- use_terminal = _use_terminal(style)
93
+ def _render(style: str) -> VizOutput:
94
+ node = build_layout(arr_np, grid_dims=grid_dims, max_height=max_height)
95
+ gs = compute_stats(arr_np)
96
+ if gs:
97
+ node.stats = gs
126
98
 
127
- output = VizOutput()
99
+ out = VizOutput(_rerender=_render)
100
+ if use_html:
101
+ out.html = _wrap_html(render_html(node, mode=mode, global_stats=gs, render_style=style), title)
102
+ out.ansi = _wrap_ansi(render_terminal(node, mode=mode, global_stats=gs, render_style=style), title)
103
+ return out
128
104
 
129
- if use_html:
130
- output.html = _wrap_html(
131
- render_html(node, color=color, mode=mode, global_stats=global_stats, render_style=rs), title
132
- )
133
-
134
- if use_terminal:
135
- output.ansi = _wrap_ansi(
136
- render_terminal(node, color=color, mode=mode, global_stats=global_stats, render_style=rs), title
137
- )
138
-
139
- return output
105
+ return _render(rs)
140
106
 
141
107
 
142
108
  def _resolve_grid_dims(
143
- arr: np.ndarray,
109
+ arr,
144
110
  axes: list[str] | None,
145
111
  grid: list[str | int] | None,
146
112
  ) -> list[int] | None:
@@ -166,22 +132,6 @@ def _resolve_grid_dims(
166
132
  return resolved
167
133
 
168
134
 
169
- def _use_html(style: str) -> bool:
170
- if style == "html":
171
- return True
172
- if style == "terminal":
173
- return False
174
- return _in_jupyter()
175
-
176
-
177
- def _use_terminal(style: str) -> bool:
178
- if style == "terminal":
179
- return True
180
- if style == "html":
181
- return False
182
- return True
183
-
184
-
185
135
  def _in_jupyter() -> bool:
186
136
  try:
187
137
  from IPython import get_ipython
@@ -0,0 +1,10 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class Config:
6
+ mode: str = "dtype"
7
+ render_style: str = "tree" # tree | mosaic
8
+
9
+
10
+ config: Config = Config()
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from collections.abc import Callable
3
4
  from dataclasses import dataclass, field
4
5
 
5
6
  import numpy as np
@@ -18,11 +19,15 @@ class VizNode:
18
19
  stats: dict | None = None
19
20
 
20
21
 
22
+ _RerenderFn = Callable[[str], "VizOutput"]
23
+
24
+
21
25
  @dataclass
22
26
  class VizOutput:
23
27
  html: str = ""
24
28
  ansi: str = ""
25
29
  metadata: dict = field(default_factory=dict)
30
+ _rerender: _RerenderFn | None = None
26
31
 
27
32
  def _repr_html_(self) -> str:
28
33
  return self.html
@@ -37,3 +42,9 @@ class VizOutput:
37
42
 
38
43
  def __repr__(self) -> str:
39
44
  return self.ansi
45
+
46
+ def tree(self) -> VizOutput:
47
+ return self._rerender("tree") if self._rerender else self
48
+
49
+ def mosaic(self) -> VizOutput:
50
+ return self._rerender("mosaic") if self._rerender else self
@@ -10,7 +10,6 @@ from arrscope._types import VizNode
10
10
 
11
11
  def render_html(
12
12
  node: VizNode,
13
- color: bool = True,
14
13
  mode: str = "dtype",
15
14
  global_stats: dict | None = None,
16
15
  render_style: str = "tree",
@@ -94,13 +93,6 @@ def _css() -> str:
94
93
  }
95
94
  .arrscope-row { display: flex; flex-wrap: wrap; gap: 12px; }
96
95
  .arrscope-tree { margin-left: 16px; }
97
- .arrscope-level-0 { }
98
- .arrscope-level-1 { border-left: 2px solid #00bcd4; padding-left: 8px; }
99
- .arrscope-level-2 { border-left: 2px solid #4caf50; padding-left: 8px; }
100
- .arrscope-level-3 { border-left: 2px solid #ffc107; padding-left: 8px; }
101
- .arrscope-level-4 { border-left: 2px solid #e91e63; padding-left: 8px; }
102
- .arrscope-level-5 { border-left: 2px solid #9c27b0; padding-left: 8px; }
103
- .arrscope-level-6 { border-left: 2px solid #2196f3; padding-left: 8px; }
104
96
  .arrscope-ellipsis { color: #999; font-style: italic; margin: 2px 0; }
105
97
  .arrscope-header {
106
98
  font-weight: 600;
@@ -133,12 +125,6 @@ details.arrscope-details[open] > summary {
133
125
  .arrscope-shape { color: #777; }
134
126
  .arrscope-stats { color: #999; }
135
127
  .arrscope-header { border-bottom-color: #444; }
136
- .arrscope-level-1 { border-left-color: #26c6da; }
137
- .arrscope-level-2 { border-left-color: #66bb6a; }
138
- .arrscope-level-3 { border-left-color: #ffd54f; }
139
- .arrscope-level-4 { border-left-color: #f06292; }
140
- .arrscope-level-5 { border-left-color: #ab47bc; }
141
- .arrscope-level-6 { border-left-color: #42a5f5; }
142
128
  }
143
129
  """
144
130
 
@@ -169,7 +155,7 @@ def _render_node_html(
169
155
  if not node.children and node.truncated:
170
156
  return f'<div class="arrscope-ellipsis">{html_mod.escape(node.label)}</div>'
171
157
 
172
- is_large_tree = depth > 0 and len(node.children) > 4
158
+ is_large_tree = depth > 0 and len(node.children) > 0
173
159
 
174
160
  parts: list[str] = []
175
161
  if depth == 0:
@@ -184,8 +170,7 @@ def _render_node_html(
184
170
  parts.append(
185
171
  f"<summary>{html_mod.escape(node.label or _format_header(node))}</summary>"
186
172
  )
187
- level_class = f"arrscope-level-{(depth + 1) % 7}"
188
- parts.append(f'<div class="arrscope-tree {level_class}">')
173
+ parts.append('<div class="arrscope-tree">')
189
174
 
190
175
  for child in node.children:
191
176
  parts.append(_render_node_html(child, depth + 1, mode, global_stats))
@@ -17,24 +17,23 @@ BRANCH_COLORS = ["grey50", "cyan", "green", "yellow", "magenta", "blue"]
17
17
 
18
18
  def render_terminal(
19
19
  node: VizNode,
20
- color: bool = True,
21
20
  mode: str = "dtype",
22
21
  global_stats: dict | None = None,
23
22
  render_style: str = "tree",
24
23
  ) -> str:
25
24
  from rich.console import Console
26
25
 
27
- console = Console(width=120, color_system="truecolor" if color else None)
26
+ console = Console(width=120, color_system="truecolor")
28
27
  parts: list = []
29
28
 
30
29
  if render_style == "mosaic":
31
- body = _render_mosaic(node, color, mode, global_stats)
30
+ body = _render_mosaic(node, mode, global_stats)
32
31
  else:
33
- body = _render_node(node, 0, color, mode, global_stats)
32
+ body = _render_node(node, 0, mode, global_stats)
34
33
  parts.append(body)
35
34
 
36
35
  if global_stats and node.stats:
37
- parts.append(_stats_text(global_stats, color))
36
+ parts.append(_stats_text(global_stats))
38
37
 
39
38
  with console.capture() as capture:
40
39
  for p in parts:
@@ -53,7 +52,6 @@ def _collect_leaves(node: VizNode) -> list[VizNode]:
53
52
 
54
53
  def _render_mosaic(
55
54
  node: VizNode,
56
- color: bool,
57
55
  mode: str,
58
56
  global_stats: dict | None,
59
57
  ) -> Columns | Text:
@@ -64,14 +62,14 @@ def _render_mosaic(
64
62
  tables: list[Table] = []
65
63
  for leaf in leaves:
66
64
  if leaf.grid_data is not None:
67
- t = _render_grid(leaf.grid_data, leaf.label, color, mode, global_stats)
65
+ t = _render_grid(leaf.grid_data, leaf.label, mode, global_stats)
68
66
  tables.append(t)
69
67
 
70
68
  return Columns(tables, equal=True, expand=False)
71
69
 
72
70
 
73
- def _stats_text(stats: dict, color: bool) -> Text:
74
- dim = Style(dim=True, color="grey50") if color else Style(dim=True)
71
+ def _stats_text(stats: dict) -> Text:
72
+ dim = Style(dim=True, color="grey50")
75
73
  t = Text()
76
74
  fmt = ".4f" if stats.get("dtype", "").startswith(("float", "int")) else ".4f"
77
75
 
@@ -99,12 +97,11 @@ def _stats_text(stats: dict, color: bool) -> Text:
99
97
  def _render_node(
100
98
  node: VizNode,
101
99
  depth: int,
102
- color: bool,
103
100
  mode: str,
104
101
  global_stats: dict | None,
105
102
  ) -> Tree | Table | Text:
106
103
  if node.grid_data is not None:
107
- return _render_grid(node.grid_data, node.label, color, mode, global_stats)
104
+ return _render_grid(node.grid_data, node.label, mode, global_stats)
108
105
 
109
106
  if not node.children and node.truncated:
110
107
  t = Text(f" {node.label}")
@@ -112,25 +109,22 @@ def _render_node(
112
109
  return t
113
110
 
114
111
  guide_color = BRANCH_COLORS[(depth) % len(BRANCH_COLORS)]
115
- guide = Style(dim=True, color=guide_color) if color else Style(dim=True)
112
+ guide = Style(dim=True, color=guide_color)
116
113
 
117
- tree = Tree(
118
- _make_header(node, color),
119
- guide_style=guide,
120
- )
114
+ tree = Tree(_make_header(node), guide_style=guide)
121
115
  for child in node.children:
122
- child_renderable = _render_node(child, depth + 1, color, mode, global_stats)
116
+ child_renderable = _render_node(child, depth + 1, mode, global_stats)
123
117
  tree.add(child_renderable)
124
118
  return tree
125
119
 
126
120
 
127
- def _make_header(node: VizNode, color: bool) -> Text:
121
+ def _make_header(node: VizNode) -> Text:
128
122
  parts = []
129
123
  if node.label:
130
- parts.append((node.label, "bold" if color else ""))
124
+ parts.append((node.label, "bold"))
131
125
  shape_str = " × ".join(str(s) for s in node.shape)
132
126
  if shape_str:
133
- dim_style = Style(dim=True, color="grey50") if color else Style(dim=True)
127
+ dim_style = Style(dim=True, color="grey50")
134
128
  parts.append((f" ({shape_str})", dim_style))
135
129
  t = Text()
136
130
  for text, style in parts:
@@ -141,7 +135,6 @@ def _make_header(node: VizNode, color: bool) -> Text:
141
135
  def _render_grid(
142
136
  data: np.ndarray,
143
137
  label: str,
144
- color: bool,
145
138
  mode: str,
146
139
  global_stats: dict | None,
147
140
  ) -> Text | Table:
@@ -149,21 +142,20 @@ def _render_grid(
149
142
  return Text(format_value(data.item()))
150
143
 
151
144
  if data.ndim == 1:
152
- return _render_1d(data, color, mode, global_stats)
145
+ return _render_1d(data, mode, global_stats)
153
146
 
154
- return _render_2d(data, label, color, mode, global_stats)
147
+ return _render_2d(data, label, mode, global_stats)
155
148
 
156
149
 
157
150
  def _render_1d(
158
151
  data: np.ndarray,
159
- color: bool,
160
152
  mode: str,
161
153
  global_stats: dict | None,
162
154
  ) -> Text:
163
155
  items = []
164
156
  for v in data:
165
157
  text = _format_cell(v, mode)
166
- items.append(_style_value(text, v, color, mode, global_stats))
158
+ items.append(_style_value(text, v, mode, global_stats))
167
159
 
168
160
  t = Text("[")
169
161
  for i, item in enumerate(items):
@@ -177,7 +169,6 @@ def _render_1d(
177
169
  def _render_2d(
178
170
  data: np.ndarray,
179
171
  label: str,
180
- color: bool,
181
172
  mode: str,
182
173
  global_stats: dict | None,
183
174
  ) -> Table:
@@ -199,7 +190,6 @@ def _render_2d(
199
190
  _style_value(
200
191
  _format_cell(data[row_idx, col_idx], mode),
201
192
  data[row_idx, col_idx],
202
- color,
203
193
  mode,
204
194
  global_stats,
205
195
  )
@@ -229,13 +219,9 @@ def _is_zero(val) -> bool:
229
219
  def _style_value(
230
220
  text: str,
231
221
  val,
232
- color: bool,
233
222
  mode: str,
234
223
  global_stats: dict | None,
235
224
  ) -> Text:
236
- if not color:
237
- return Text(text)
238
-
239
225
  if mode == "heatmap":
240
226
  cell_style = _heatmap_color(val, global_stats)
241
227
  elif mode == "sparsity":
@@ -18,7 +18,7 @@ wheels = [
18
18
 
19
19
  [[package]]
20
20
  name = "arrscope"
21
- version = "0.1.0"
21
+ version = "0.2.0"
22
22
  source = { editable = "." }
23
23
  dependencies = [
24
24
  { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
arrscope-0.2.0/PKG-INFO DELETED
@@ -1,185 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: arrscope
3
- Version: 0.2.0
4
- Summary: Beautiful n-dimensional array visualization for Python
5
- Project-URL: Homepage, https://github.com/vizarray/arrscope
6
- Project-URL: Repository, https://github.com/vizarray/arrscope
7
- Author: arrscope contributors
8
- License: MIT
9
- Keywords: arrays,data-science,machine-learning,numpy,visualization
10
- Classifier: Development Status :: 3 - Alpha
11
- Classifier: Intended Audience :: Science/Research
12
- Classifier: License :: OSI Approved :: MIT License
13
- Classifier: Programming Language :: Python :: 3.11
14
- Classifier: Programming Language :: Python :: 3.12
15
- Classifier: Programming Language :: Python :: 3.13
16
- Classifier: Topic :: Scientific/Engineering :: Visualization
17
- Requires-Python: >=3.11
18
- Requires-Dist: numpy>=1.24
19
- Requires-Dist: rich>=13.0
20
- Provides-Extra: jax
21
- Requires-Dist: jax>=0.4; extra == 'jax'
22
- Provides-Extra: tf
23
- Requires-Dist: tensorflow>=2.12; extra == 'tf'
24
- Provides-Extra: torch
25
- Requires-Dist: torch>=2.0; extra == 'torch'
26
- Description-Content-Type: text/markdown
27
-
28
- # arrscope
29
-
30
- Beautiful n-dimensional array visualization for Python — in the terminal and Jupyter.
31
-
32
- ```python
33
- from arrscope import scope
34
- import numpy as np
35
-
36
- scope(np.random.rand(2, 3, 8, 8), axes=['batch', 'heads', 'h', 'w'])
37
- ```
38
-
39
- ```
40
- ├── [0] (3, 8, 8)
41
- │ ├── [0,0]: 8×8 grid
42
- │ ├── [0,1]: 8×8 grid
43
- │ └── [0,2]: 8×8 grid
44
- └── [1] (3, 8, 8)
45
- ...
46
- min=0.001 max=0.999 mean=0.5 std=0.29 zeros=0.0%
47
- ```
48
-
49
- ## Features
50
-
51
- - **1D → 6D+**: Tiered visual grammar — lists, grids, trees, collapsed hierarchies
52
- - **Named axes**: Attach semantics to dimensions (`batch`, `heads`, `h`, `w`)
53
- - **Configurable grid**: Pick which axes form the leaf 2D matrix
54
- - **Three color modes**:
55
- - `dtype` — semantic colors by data type (float=blue, int=green, bool=magenta, …)
56
- - `heatmap` — diverging colormap (red→light→blue) by value magnitude
57
- - `sparsity` — zeros as `·`, non-zeros highlighted in bold
58
- - **Stats overlay**: min, max, mean, std, zero%, NaN count
59
- - **Head/tail truncation**: large dimensions show first/last N slices with `…`
60
- - **Smart precision**: auto-detects significant figures for floats
61
- - **Terminal + Jupyter**: Rich ANSI output + static HTML/CSS with dark mode
62
- - **Multi-framework**: NumPy, PyTorch, TensorFlow, JAX (lazy imports, no hard deps)
63
-
64
- ## Install
65
-
66
- ```bash
67
- pip install arrscope
68
- ```
69
-
70
- Only requires `numpy` + `rich`. Torch/TF/JAX are optional — pass any array type, it just works.
71
-
72
- ## Quick start
73
-
74
- ```python
75
- from arrscope import scope
76
- import numpy as np
77
-
78
- # Auto-detect — last 2 dims form the grid
79
- scope(np.random.rand(3, 4, 5))
80
-
81
- # Named axes for clarity
82
- scope(
83
- np.random.rand(2, 8, 32, 32),
84
- axes=['batch', 'heads', 'h', 'w'],
85
- grid=['h', 'w'],
86
- title='Attention heads',
87
- )
88
-
89
- # Pick any dims as the leaf grid
90
- scope(data, axes=['a', 'b', 'c', 'd'], grid=['a', 'b'])
91
- ```
92
-
93
- ## Color modes
94
-
95
- ```python
96
- scope(arr, mode='dtype') # default — blue floats, green ints, etc.
97
- scope(arr, mode='heatmap') # diverging colormap by value
98
- scope(arr, mode='sparsity') # · for zeros, bold for non-zeros
99
- ```
100
-
101
- ## Stats overlay
102
-
103
- Stats are shown by default. Hide with:
104
-
105
- ```python
106
- scope(arr, stats=False)
107
- ```
108
-
109
- Shows: `min=0.0 max=1.0 mean=0.5 std=0.29 zeros=12.5%`
110
-
111
- ## Truncation
112
-
113
- ```python
114
- scope(np.random.rand(100, 32, 32), max_height=8)
115
- ```
116
-
117
- Shows first 4 + last 4 slices with `… (92 more)` in between.
118
-
119
- ## Custom formatting
120
-
121
- ```python
122
- scope(arr, fmt='.2f') # fixed precision
123
- scope(arr, color=False) # monochrome
124
- scope(arr, style='html') # force HTML output in terminal
125
- ```
126
-
127
- ## CLI
128
-
129
- ```bash
130
- # Install globally (ships with the library)
131
- pip install arrscope
132
-
133
- # Use from anywhere
134
- arrscope 3x4x5
135
- arrscope 2x3x32x32 --axes batch heads h w --grid h w --mode heatmap
136
- arrscope 20x4x5 --max-height 6 --no-stats
137
- ```
138
-
139
- ## Framework support
140
-
141
- Pass any array-like — conversion is automatic:
142
-
143
- ```python
144
- import torch
145
- scope(torch.randn(2, 3, 4)) # PyTorch
146
-
147
- import tensorflow as tf
148
- scope(tf.random.uniform((2, 3, 4))) # TensorFlow
149
-
150
- import jax.numpy as jnp
151
- scope(jnp.array([[1, 2], [3, 4]])) # JAX
152
- ```
153
-
154
- ## API
155
-
156
- ```python
157
- scope(
158
- arr, # np.ndarray | torch.Tensor | tf.Tensor | jax.Array
159
- axes=None, # list[str] — name each dimension
160
- grid=None, # list[str | int] — which dims form the leaf grid
161
- title=None, # str — heading above the visualization
162
- max_width=None, # int — max characters wide
163
- max_height=None, # int — max rows before truncation
164
- fmt=None, # str — format spec like '.4f'
165
- color=True, # bool — enable/disable color
166
- mode='dtype', # 'dtype' | 'heatmap' | 'sparsity'
167
- stats=True, # bool — show min/max/mean/std/zeros
168
- style='auto', # 'auto' | 'terminal' | 'html'
169
- )
170
- ```
171
-
172
- ## Development
173
-
174
- ```bash
175
- git clone https://github.com/vizarray/arrscope
176
- cd arrscope
177
- uv sync
178
- uv run pytest
179
- uv run python main.py # demo script
180
- uv run jupyter notebook test.ipynb # notebook demo
181
- ```
182
-
183
- ## License
184
-
185
- MIT
arrscope-0.2.0/README.md DELETED
@@ -1,158 +0,0 @@
1
- # arrscope
2
-
3
- Beautiful n-dimensional array visualization for Python — in the terminal and Jupyter.
4
-
5
- ```python
6
- from arrscope import scope
7
- import numpy as np
8
-
9
- scope(np.random.rand(2, 3, 8, 8), axes=['batch', 'heads', 'h', 'w'])
10
- ```
11
-
12
- ```
13
- ├── [0] (3, 8, 8)
14
- │ ├── [0,0]: 8×8 grid
15
- │ ├── [0,1]: 8×8 grid
16
- │ └── [0,2]: 8×8 grid
17
- └── [1] (3, 8, 8)
18
- ...
19
- min=0.001 max=0.999 mean=0.5 std=0.29 zeros=0.0%
20
- ```
21
-
22
- ## Features
23
-
24
- - **1D → 6D+**: Tiered visual grammar — lists, grids, trees, collapsed hierarchies
25
- - **Named axes**: Attach semantics to dimensions (`batch`, `heads`, `h`, `w`)
26
- - **Configurable grid**: Pick which axes form the leaf 2D matrix
27
- - **Three color modes**:
28
- - `dtype` — semantic colors by data type (float=blue, int=green, bool=magenta, …)
29
- - `heatmap` — diverging colormap (red→light→blue) by value magnitude
30
- - `sparsity` — zeros as `·`, non-zeros highlighted in bold
31
- - **Stats overlay**: min, max, mean, std, zero%, NaN count
32
- - **Head/tail truncation**: large dimensions show first/last N slices with `…`
33
- - **Smart precision**: auto-detects significant figures for floats
34
- - **Terminal + Jupyter**: Rich ANSI output + static HTML/CSS with dark mode
35
- - **Multi-framework**: NumPy, PyTorch, TensorFlow, JAX (lazy imports, no hard deps)
36
-
37
- ## Install
38
-
39
- ```bash
40
- pip install arrscope
41
- ```
42
-
43
- Only requires `numpy` + `rich`. Torch/TF/JAX are optional — pass any array type, it just works.
44
-
45
- ## Quick start
46
-
47
- ```python
48
- from arrscope import scope
49
- import numpy as np
50
-
51
- # Auto-detect — last 2 dims form the grid
52
- scope(np.random.rand(3, 4, 5))
53
-
54
- # Named axes for clarity
55
- scope(
56
- np.random.rand(2, 8, 32, 32),
57
- axes=['batch', 'heads', 'h', 'w'],
58
- grid=['h', 'w'],
59
- title='Attention heads',
60
- )
61
-
62
- # Pick any dims as the leaf grid
63
- scope(data, axes=['a', 'b', 'c', 'd'], grid=['a', 'b'])
64
- ```
65
-
66
- ## Color modes
67
-
68
- ```python
69
- scope(arr, mode='dtype') # default — blue floats, green ints, etc.
70
- scope(arr, mode='heatmap') # diverging colormap by value
71
- scope(arr, mode='sparsity') # · for zeros, bold for non-zeros
72
- ```
73
-
74
- ## Stats overlay
75
-
76
- Stats are shown by default. Hide with:
77
-
78
- ```python
79
- scope(arr, stats=False)
80
- ```
81
-
82
- Shows: `min=0.0 max=1.0 mean=0.5 std=0.29 zeros=12.5%`
83
-
84
- ## Truncation
85
-
86
- ```python
87
- scope(np.random.rand(100, 32, 32), max_height=8)
88
- ```
89
-
90
- Shows first 4 + last 4 slices with `… (92 more)` in between.
91
-
92
- ## Custom formatting
93
-
94
- ```python
95
- scope(arr, fmt='.2f') # fixed precision
96
- scope(arr, color=False) # monochrome
97
- scope(arr, style='html') # force HTML output in terminal
98
- ```
99
-
100
- ## CLI
101
-
102
- ```bash
103
- # Install globally (ships with the library)
104
- pip install arrscope
105
-
106
- # Use from anywhere
107
- arrscope 3x4x5
108
- arrscope 2x3x32x32 --axes batch heads h w --grid h w --mode heatmap
109
- arrscope 20x4x5 --max-height 6 --no-stats
110
- ```
111
-
112
- ## Framework support
113
-
114
- Pass any array-like — conversion is automatic:
115
-
116
- ```python
117
- import torch
118
- scope(torch.randn(2, 3, 4)) # PyTorch
119
-
120
- import tensorflow as tf
121
- scope(tf.random.uniform((2, 3, 4))) # TensorFlow
122
-
123
- import jax.numpy as jnp
124
- scope(jnp.array([[1, 2], [3, 4]])) # JAX
125
- ```
126
-
127
- ## API
128
-
129
- ```python
130
- scope(
131
- arr, # np.ndarray | torch.Tensor | tf.Tensor | jax.Array
132
- axes=None, # list[str] — name each dimension
133
- grid=None, # list[str | int] — which dims form the leaf grid
134
- title=None, # str — heading above the visualization
135
- max_width=None, # int — max characters wide
136
- max_height=None, # int — max rows before truncation
137
- fmt=None, # str — format spec like '.4f'
138
- color=True, # bool — enable/disable color
139
- mode='dtype', # 'dtype' | 'heatmap' | 'sparsity'
140
- stats=True, # bool — show min/max/mean/std/zeros
141
- style='auto', # 'auto' | 'terminal' | 'html'
142
- )
143
- ```
144
-
145
- ## Development
146
-
147
- ```bash
148
- git clone https://github.com/vizarray/arrscope
149
- cd arrscope
150
- uv sync
151
- uv run pytest
152
- uv run python main.py # demo script
153
- uv run jupyter notebook test.ipynb # notebook demo
154
- ```
155
-
156
- ## License
157
-
158
- MIT
@@ -1,15 +0,0 @@
1
- from dataclasses import dataclass
2
-
3
-
4
- @dataclass
5
- class Config:
6
- max_width: int | None = None
7
- max_height: int | None = None
8
- color: bool = True
9
- precision: int | None = None
10
- mode: str = "dtype"
11
- render_style: str = "tree"
12
- stats: bool = True
13
-
14
-
15
- config: Config = Config()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes