From 5190182e6ea4c28ceeb45cc17cf2e55fe3e30f4b Mon Sep 17 00:00:00 2001
From: Kyle Sunden <git@ksunden.space>
Date: Fri, 4 Apr 2025 17:51:53 -0500
Subject: [PATCH 01/10] fix patch examples

---
 data_prototype/patches.py | 6 +++---
 examples/simple_patch.py  | 4 ----
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/data_prototype/patches.py b/data_prototype/patches.py
index d83262f..e14f225 100644
--- a/data_prototype/patches.py
+++ b/data_prototype/patches.py
@@ -51,8 +51,8 @@ def draw(self, renderer, graph: Graph) -> None:
             "x": desc,
             "y": desc,
             "codes": desc,
-            "facecolor": Desc((), "display"),
-            "edgecolor": Desc(("M",), "display"),
+            "facecolor": scalar,
+            "edgecolor": scalar,
             "linewidth": scalar,
             "linestyle": scalar,
             "hatch": scalar,
@@ -93,7 +93,7 @@ def draw(self, renderer, graph: Graph) -> None:
 
             if evald["hatch"] is not None:
                 gc.set_hatch(evald["hatch"])
-                gc.set_hatch_color(evald["hatch_color"])
+                # gc.set_hatch_color(evald["hatch_color"])
 
             # if self.get_sketch_params() is not None:
             #     gc.set_sketch_params(*self.get_sketch_params())
diff --git a/examples/simple_patch.py b/examples/simple_patch.py
index ebfe959..63b9057 100644
--- a/examples/simple_patch.py
+++ b/examples/simple_patch.py
@@ -25,12 +25,10 @@
     upper_right_x=np.array(-1),
     upper_right_y=np.array(3),
     edgecolor=np.array([0, 0, 0]),
-    hatch_color=np.array([0, 0, 0]),
     facecolor="green",
     linewidth=3,
     linestyle="-",
     antialiased=np.array([True]),
-    hatch="*",
     fill=np.array([True]),
     capstyle=np.array(["round"]),
     joinstyle=np.array(["miter"]),
@@ -46,12 +44,10 @@
     rotation_point_x=np.array(1),
     rotation_point_y=np.array(3.5),
     edgecolor=np.array([0.5, 0.2, 0]),
-    hatch_color=np.array([0, 0, 0]),
     facecolor="red",
     linewidth=6,
     linestyle="-",
     antialiased=np.array([True]),
-    hatch="",
     fill=np.array([True]),
     capstyle=np.array(["round"]),
     joinstyle=np.array(["miter"]),

From 463a7f11e9fa441805aa7db4ecb2e293340f798c Mon Sep 17 00:00:00 2001
From: Kyle Sunden <git@ksunden.space>
Date: Fri, 4 Apr 2025 16:42:34 -0500
Subject: [PATCH 02/10] New graph visualization tools

---
 data_prototype/introspection.py | 142 ++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)
 create mode 100644 data_prototype/introspection.py

diff --git a/data_prototype/introspection.py b/data_prototype/introspection.py
new file mode 100644
index 0000000..4480122
--- /dev/null
+++ b/data_prototype/introspection.py
@@ -0,0 +1,142 @@
+from __future__ import annotations
+
+from dataclasses import dataclass, field
+import graphlib
+from pprint import pformat
+
+import matplotlib.pyplot as plt
+
+from .conversion_edge import Edge, Graph
+from .description import Desc
+
+
+@dataclass
+class VisNode:
+    keys: list[str]
+    coordinates: list[str]
+    parents: list[VisNode] = field(default_factory=list)
+    children: list[VisNode] = field(default_factory=list)
+    x: int = 0
+    y: int = 0
+
+    def __eq__(self, other):
+        return self.keys == other.keys and self.coordinates == other.coordinates
+
+    def format(self):
+        return pformat({k: v for k, v in zip(self.keys, self.coordinates)}, width=20)
+
+
+@dataclass
+class VisEdge:
+    name: str
+    parent: VisNode
+    child: VisNode
+
+
+def _position_subgraph(
+    subgraph: tuple(set[str], list[Edge])
+) -> tuple[list[VisNode], list[VisEdge]]:
+    # Build graph
+    nodes: list[VisNode] = []
+    edges: list[VisEdge] = []
+
+    q: list[dict[str, Desc]] = [e.input for e in subgraph[1]]
+    explored: set[tuple[tuple[str, str], ...]] = set()
+    explored.add(tuple(sorted(((k, v.coordinates) for k, v in q[0].items()))))
+
+    for e in subgraph[1]:
+        nodes.append(
+            VisNode(list(e.input.keys()), [x.coordinates for x in e.input.values()])
+        )
+
+    while q:
+        n = q.pop()
+        vn = VisNode(list(n.keys()), [x.coordinates for x in n.values()])
+        for nn in nodes:
+            if vn == nn:
+                vn = nn
+
+        for e in subgraph[1]:
+            # Shortcut default edges appearing all over the place
+            if e.input == {} and vn.keys != []:
+                continue
+            if Desc.compatible(n, e.input):
+                w = e.output
+                vw = VisNode(list(w.keys()), [x.coordinates for x in w.values()])
+                for nn in nodes:
+                    if vw == nn:
+                        vw = nn
+
+                if vw not in nodes:
+                    nodes.append(vw)
+                    explored.add(
+                        tuple(sorted(((k, v.coordinates) for k, v in w.items())))
+                    )
+                    q.append(w)
+                if vw != vn:
+                    edges.append(VisEdge(e.name, vn, vw))
+                    vw.parents.append(vn)
+                    vn.children.append(vw)
+
+    # adapt graph for total ording
+    def hash_node(n):
+        return (tuple(n.keys), tuple(n.coordinates))
+
+    to_graph = {hash_node(n): set() for n in nodes}
+    for e in edges:
+        to_graph[hash_node(e.child)] |= {hash_node(e.parent)}
+
+    # evaluate total ordering
+    topological_sorter = graphlib.TopologicalSorter(to_graph)
+
+    # position horizontally by 1+ highest parent, vertically by 1+ highest sibling
+    def get_node(n):
+        for node in nodes:
+            if n[0] == tuple(node.keys) and n[1] == tuple(node.coordinates):
+                return node
+
+    static_order = list(topological_sorter.static_order())
+
+    for n in static_order:
+        node = get_node(n)
+        if node.parents != []:
+            node.y = max(p.y for p in node.parents) + 1
+    x_pos = {}
+    for n in static_order:
+        node = get_node(n)
+        if node.y in x_pos:
+            node.x = x_pos[node.y]
+            x_pos[node.y] += 1.25
+        else:
+            x_pos[node.y] = 1.25
+
+    return nodes, edges
+
+
+def draw_graph(graph: Graph, ax=None):
+    if ax is None:
+        fig, ax = plt.subplots()
+
+    origin_y = 0
+
+    for sg in graph._subgraphs:
+        nodes, edges = _position_subgraph(sg)
+        # Draw nodes
+        for node in nodes:
+            ax.annotate(
+                node.format(), (node.x, node.y + origin_y), bbox={"boxstyle": "round"}
+            )
+
+        # Draw edges
+        for edge in edges:
+            ax.annotate(
+                "",
+                (edge.child.x, edge.child.y + origin_y),
+                (edge.parent.x, edge.parent.y + origin_y),
+                arrowprops={"arrowstyle": "->"},
+            )
+            mid_x = (edge.child.x + edge.parent.x) / 2
+            mid_y = (edge.child.y + edge.parent.y) / 2
+            ax.text(mid_x, mid_y + origin_y, edge.name)
+
+        origin_y += max(node.y for node in nodes) + 1

From 387ecc4186d4975329f56cc501055f1d9fd733e5 Mon Sep 17 00:00:00 2001
From: Kyle Sunden <git@ksunden.space>
Date: Fri, 18 Apr 2025 13:55:03 -0500
Subject: [PATCH 03/10] Adjust formatting of introspection plots

---
 data_prototype/introspection.py | 37 +++++++++++++++++++++++++--------
 1 file changed, 28 insertions(+), 9 deletions(-)

diff --git a/data_prototype/introspection.py b/data_prototype/introspection.py
index 4480122..7db323e 100644
--- a/data_prototype/introspection.py
+++ b/data_prototype/introspection.py
@@ -113,30 +113,49 @@ def get_node(n):
     return nodes, edges
 
 
-def draw_graph(graph: Graph, ax=None):
+def draw_graph(graph: Graph, ax=None, *, adjust_axes=None):
     if ax is None:
         fig, ax = plt.subplots()
+        if adjust_axes is None:
+            adjust_axes = True
+
+    inverted = adjust_axes or ax.yaxis.get_inverted()
 
     origin_y = 0
+    xmax = 0
 
     for sg in graph._subgraphs:
         nodes, edges = _position_subgraph(sg)
+        annotations = {}
         # Draw nodes
         for node in nodes:
-            ax.annotate(
-                node.format(), (node.x, node.y + origin_y), bbox={"boxstyle": "round"}
+            annotations[node.format()] = ax.annotate(
+                node.format(),
+                (node.x, node.y + origin_y),
+                ha="center",
+                va="center",
+                bbox={"boxstyle": "round", "facecolor": "none"},
             )
 
         # Draw edges
         for edge in edges:
-            ax.annotate(
+            arr = ax.annotate(
                 "",
-                (edge.child.x, edge.child.y + origin_y),
-                (edge.parent.x, edge.parent.y + origin_y),
+                (0.5, 1.05 if inverted else -0.05),
+                (0.5, -0.05 if inverted else 1.05),
+                xycoords=annotations[edge.child.format()],
+                textcoords=annotations[edge.parent.format()],
                 arrowprops={"arrowstyle": "->"},
+                annotation_clip=True,
             )
-            mid_x = (edge.child.x + edge.parent.x) / 2
-            mid_y = (edge.child.y + edge.parent.y) / 2
-            ax.text(mid_x, mid_y + origin_y, edge.name)
+            ax.annotate(edge.name, (0.5, 0.5), xytext=(0.5, 0.5), textcoords=arr)
 
         origin_y += max(node.y for node in nodes) + 1
+        xmax = max(xmax, max(node.x for node in nodes))
+
+    if adjust_axes:
+        ax.set_ylim(origin_y, -1)
+        ax.set_xlim(-1, xmax + 1)
+        ax.spines[:].set_visible(False)
+        ax.set_xticks([])
+        ax.set_yticks([])

From a9c35cb36421f70a7c48a6550b059ba8c2f88218 Mon Sep 17 00:00:00 2001
From: Kyle Sunden <git@ksunden.space>
Date: Fri, 18 Apr 2025 13:56:22 -0500
Subject: [PATCH 04/10] Use introspection plots in Graph.visualize

Does still use networkx based plots if given an input dictionary (and networkx is available), falls introspection plot if networkx is unavailable
---
 data_prototype/conversion_edge.py | 65 ++++++++++++++++---------------
 1 file changed, 33 insertions(+), 32 deletions(-)

diff --git a/data_prototype/conversion_edge.py b/data_prototype/conversion_edge.py
index 8f850b0..8562dc2 100644
--- a/data_prototype/conversion_edge.py
+++ b/data_prototype/conversion_edge.py
@@ -372,7 +372,20 @@ def edges(self):
         return SequenceEdge.from_edges("eval", out_edges, output)
 
     def visualize(self, input: dict[str, Desc] | None = None):
-        import networkx as nx
+        if input is None:
+            from .introspection import draw_graph
+
+            draw_graph(self)
+            return
+
+        try:
+            import networkx as nx
+        except ImportError:
+            from .introspection import draw_graph
+
+            draw_graph(self)
+            return
+
         import matplotlib.pyplot as plt
 
         from pprint import pformat
@@ -382,38 +395,26 @@ def node_format(x):
 
         G = nx.DiGraph()
 
-        if input is not None:
-            for _, edges in self._subgraphs:
-                q: list[dict[str, Desc]] = [input]
-                explored: set[tuple[tuple[str, str], ...]] = set()
-                explored.add(
-                    tuple(sorted(((k, v.coordinates) for k, v in q[0].items())))
-                )
-                G.add_node(node_format(q[0]))
-                while q:
-                    n = q.pop()
-                    for e in edges:
-                        if Desc.compatible(n, e.input):
-                            w = n | e.output
-                            if node_format(w) not in G:
-                                G.add_node(node_format(w))
-                                explored.add(
-                                    tuple(
-                                        sorted(
-                                            ((k, v.coordinates) for k, v in w.items())
-                                        )
-                                    )
+        for _, edges in self._subgraphs:
+            q: list[dict[str, Desc]] = [input]
+            explored: set[tuple[tuple[str, str], ...]] = set()
+            explored.add(tuple(sorted(((k, v.coordinates) for k, v in q[0].items()))))
+            G.add_node(node_format(q[0]))
+            while q:
+                n = q.pop()
+                for e in edges:
+                    if Desc.compatible(n, e.input):
+                        w = n | e.output
+                        if node_format(w) not in G:
+                            G.add_node(node_format(w))
+                            explored.add(
+                                tuple(
+                                    sorted(((k, v.coordinates) for k, v in w.items()))
                                 )
-                                q.append(w)
-                            if node_format(w) != node_format(n):
-                                G.add_edge(node_format(n), node_format(w), name=e.name)
-        else:
-            # don't bother separating subgraphs,as the end result is exactly the same here
-            for edge in self._edges:
-                G.add_edge(
-                    node_format(edge.input), node_format(edge.output), name=edge.name
-                )
-
+                            )
+                            q.append(w)
+                        if node_format(w) != node_format(n):
+                            G.add_edge(node_format(n), node_format(w), name=e.name)
         try:
             pos = nx.shell_layout(G)
         except Exception:

From 1f54d867875a6285f868f0a687fafcaff94b5c37 Mon Sep 17 00:00:00 2001
From: Kyle Sunden <git@ksunden.space>
Date: Fri, 18 Apr 2025 14:09:03 -0500
Subject: [PATCH 05/10] Black formatting

---
 data_prototype/introspection.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/data_prototype/introspection.py b/data_prototype/introspection.py
index 7db323e..c9545ac 100644
--- a/data_prototype/introspection.py
+++ b/data_prototype/introspection.py
@@ -34,7 +34,7 @@ class VisEdge:
 
 
 def _position_subgraph(
-    subgraph: tuple(set[str], list[Edge])
+    subgraph: tuple(set[str], list[Edge]),
 ) -> tuple[list[VisNode], list[VisEdge]]:
     # Build graph
     nodes: list[VisNode] = []

From 965c82b80432e2b5ddff3c7349e56a58398a6caf Mon Sep 17 00:00:00 2001
From: Kyle Sunden <git@ksunden.space>
Date: Thu, 24 Apr 2025 14:02:11 -0500
Subject: [PATCH 06/10] Build docs on ubuntu-latest instead of pinned
 old/outdated version

---
 .github/workflows/docs.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 398e6bf..49a479d 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -5,7 +5,7 @@ on: [push, pull_request]
 
 jobs:
   build:
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v2
       - name: "Set up Python 3.10"

From b4086207175a4ee4241ac636056312a966f2f0d5 Mon Sep 17 00:00:00 2001
From: Kyle Sunden <git@ksunden.space>
Date: Thu, 24 Apr 2025 13:58:11 -0500
Subject: [PATCH 07/10] Rename data-prototype to mpl-data-containers

---
 .gitignore                                    |  2 +-
 CONTRIBUTING.rst                              | 22 ++++++-------
 MANIFEST.in                                   |  2 +-
 README.rst                                    |  2 +-
 docs/source/api/index.rst                     |  6 ++--
 docs/source/conf.py                           | 32 +++++++++++--------
 docs/source/index.rst                         |  2 +-
 docs/source/installation.rst                  |  2 +-
 examples/2Dfunc.py                            |  6 ++--
 examples/animation.py                         | 12 +++----
 examples/data_frame.py                        |  6 ++--
 examples/errorbar.py                          |  4 +--
 examples/first.py                             |  6 ++--
 examples/hist.py                              |  4 +--
 examples/lissajous.py                         |  6 ++--
 examples/mandelbrot.py                        |  6 ++--
 examples/mapped.py                            | 12 +++----
 examples/mulivariate_cmap.py                  | 10 +++---
 examples/new_patch.py                         |  6 ++--
 examples/scatter_with_custom_axes.py          |  6 ++--
 examples/simple_patch.py                      |  6 ++--
 examples/simple_scatter.py                    |  4 +--
 examples/subsample.py                         |  8 ++---
 examples/units.py                             | 10 +++---
 examples/widgets.py                           | 10 +++---
 .../__init__.py                               |  0
 .../artist.py                                 |  0
 .../axes.py                                   |  4 +--
 .../containers.py                             |  0
 .../conversion_edge.py                        |  2 +-
 .../conversion_node.py                        |  0
 .../description.py                            |  0
 .../image.py                                  |  0
 .../introspection.py                          |  0
 .../line.py                                   |  0
 .../patches.py                                |  0
 .../tests/__init__.py                         |  0
 .../tests/conftest.py                         |  0
 .../tests/test_check_shape.py                 |  2 +-
 .../tests/test_containers.py                  |  0
 .../tests/test_examples.py                    |  0
 .../text.py                                   |  0
 .../wrappers.py                               |  8 ++---
 setup.py                                      | 14 ++++----
 44 files changed, 113 insertions(+), 109 deletions(-)
 rename {data_prototype => mpl_data_containers}/__init__.py (100%)
 rename {data_prototype => mpl_data_containers}/artist.py (100%)
 rename {data_prototype => mpl_data_containers}/axes.py (98%)
 rename {data_prototype => mpl_data_containers}/containers.py (100%)
 rename {data_prototype => mpl_data_containers}/conversion_edge.py (99%)
 rename {data_prototype => mpl_data_containers}/conversion_node.py (100%)
 rename {data_prototype => mpl_data_containers}/description.py (100%)
 rename {data_prototype => mpl_data_containers}/image.py (100%)
 rename {data_prototype => mpl_data_containers}/introspection.py (100%)
 rename {data_prototype => mpl_data_containers}/line.py (100%)
 rename {data_prototype => mpl_data_containers}/patches.py (100%)
 rename {data_prototype => mpl_data_containers}/tests/__init__.py (100%)
 rename {data_prototype => mpl_data_containers}/tests/conftest.py (100%)
 rename {data_prototype => mpl_data_containers}/tests/test_check_shape.py (98%)
 rename {data_prototype => mpl_data_containers}/tests/test_containers.py (100%)
 rename {data_prototype => mpl_data_containers}/tests/test_examples.py (100%)
 rename {data_prototype => mpl_data_containers}/text.py (100%)
 rename {data_prototype => mpl_data_containers}/wrappers.py (98%)

diff --git a/.gitignore b/.gitignore
index 0c85e40..1162c72 100644
--- a/.gitignore
+++ b/.gitignore
@@ -103,4 +103,4 @@ doc/_static/constrained_layout*.png
 
 # setuptools_scm collateral
 
-data_prototype/_version.py
\ No newline at end of file
+mpl_data_containers/_version.py
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 4f757ba..184baf9 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -13,7 +13,7 @@ Types of Contributions
 Report Bugs
 ~~~~~~~~~~~
 
-Report bugs at https://github.com/tacaswell/data_prototype/issues.
+Report bugs at https://github.com/matplotlib/data-prototype/issues.
 
 If you are reporting a bug, please include:
 
@@ -35,14 +35,14 @@ is open to whoever wants to implement it.
 Write Documentation
 ~~~~~~~~~~~~~~~~~~~
 
-data_prototype could always use more documentation, whether
-as part of the official data_prototype docs, in docstrings,
+mpl_data_containers could always use more documentation, whether
+as part of the official mpl_data_containers docs, in docstrings,
 or even on the web in blog posts, articles, and such.
 
 Submit Feedback
 ~~~~~~~~~~~~~~~
 
-The best way to send feedback is to file an issue at https://github.com/tacaswell/data_prototype/issues.
+The best way to send feedback is to file an issue at https://github.com/matplotlib/mpl_data_containers/issues.
 
 If you are proposing a feature:
 
@@ -54,17 +54,17 @@ If you are proposing a feature:
 Get Started!
 ------------
 
-Ready to contribute? Here's how to set up `data_prototype` for local development.
+Ready to contribute? Here's how to set up `mpl_data_containers` for local development.
 
-1. Fork the `data_prototype` repo on GitHub.
+1. Fork the `mpl_data_containers` repo on GitHub.
 2. Clone your fork locally::
 
-    $ git clone git@github.com:your_name_here/data_prototype.git
+    $ git clone git@github.com:your_name_here/mpl_data_containers.git
 
 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development::
 
-    $ mkvirtualenv data_prototype
-    $ cd data_prototype/
+    $ mkvirtualenv mpl_data_containers
+    $ cd mpl_data_containers/
     $ python setup.py develop
 
 4. Create a branch for local development::
@@ -98,7 +98,5 @@ Before you submit a pull request, check that it meets these guidelines:
 2. If the pull request adds functionality, the docs should be updated. Put
    your new functionality into a function with a docstring, and add the
    feature to the list in README.rst.
-3. The pull request should work for Python 2.7, 3.3, 3.4, 3.5 and for PyPy. Check
-   https://travis-ci.org/tacaswell/data_prototype/pull_requests
-   and make sure that the tests pass for all supported Python versions.
+3. The pull request should work for all supported python versions.
 
diff --git a/MANIFEST.in b/MANIFEST.in
index 71fcfae..fcb8c6d 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -9,7 +9,7 @@ recursive-exclude * *.py[co]
 
 recursive-include docs *.rst conf.py Makefile make.bat
 
-include data_prototype/_version.py
+include mpl_data_containers/_version.py
 
 # If including data files in the package, add them like:
 # include path/to/data_file
diff --git a/README.rst b/README.rst
index d9059ef..a454e5c 100644
--- a/README.rst
+++ b/README.rst
@@ -1,5 +1,5 @@
 ==============
-data_prototype
+mpl_data_containers
 ==============
 
 Experimental code for the upcoming Matplotlib data refactor.
diff --git a/docs/source/api/index.rst b/docs/source/api/index.rst
index aea4358..a1e3bfd 100644
--- a/docs/source/api/index.rst
+++ b/docs/source/api/index.rst
@@ -7,7 +7,7 @@ API
 Containers
 ==========
 
-.. automodule:: data_prototype.containers
+.. automodule:: mpl_data_containers.containers
    :members:
    :undoc-members:
 
@@ -16,10 +16,10 @@ Containers
 Wrappers
 ========
 
-.. automodule:: data_prototype.wrappers
+.. automodule:: mpl_data_containers.wrappers
    :members:
    :undoc-members:
 
-.. automodule:: data_prototype.patches
+.. automodule:: mpl_data_containers.patches
    :members:
    :undoc-members:
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 5530ac9..bcdde7a 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 #
-# data_prototype documentation build configuration file, created by
+# mpl_data_containers documentation build configuration file, created by
 # sphinx-quickstart on Thu Jun 28 12:35:56 2018.
 #
 # This file is execfile()d with the current directory set to its
@@ -23,7 +23,7 @@
 # sys.path.insert(0, os.path.abspath('.'))
 from pathlib import Path
 
-import data_prototype
+import mpl_data_containers
 
 # are we running circle CI?
 CIRCLECI = "CIRCLECI" in os.environ
@@ -72,7 +72,7 @@
     ],
     "filename_pattern": "^((?!sgskip).)*$",
     "gallery_dirs": ["gallery"],
-    "doc_module": ("data_prototype",),
+    "doc_module": ("mpl_data_containers",),
     "reference_url": {
         "matplotlib": None,
     },
@@ -104,7 +104,7 @@
 master_doc = "index"
 
 # General information about the project.
-project = "data_prototype"
+project = "mpl_data_containers"
 copyright = "2022, Thomas A Caswell"
 author = "Thomas A Caswell"
 
@@ -114,9 +114,9 @@
 #
 
 # The short X.Y version.
-version = data_prototype.__version__
+version = mpl_data_containers.__version__
 # The full version, including alpha/beta/rc tags.
-release = data_prototype.__version__
+release = mpl_data_containers.__version__
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -179,7 +179,7 @@
 # -- Options for HTMLHelp output ------------------------------------------
 
 # Output file base name for HTML help builder.
-htmlhelp_basename = "data_prototype"
+htmlhelp_basename = "mpl_data_containers"
 
 
 # -- Options for LaTeX output ---------------------------------------------
@@ -205,8 +205,8 @@
 latex_documents = [
     (
         master_doc,
-        "data_prototype.tex",
-        "data_prototype Documentation",
+        "mpl_data_containers.tex",
+        "mpl_data_containers Documentation",
         "Contributors",
         "manual",
     ),
@@ -218,7 +218,13 @@
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
 man_pages = [
-    (master_doc, "data_prototype", "data_prototype Documentation", [author], 1)
+    (
+        master_doc,
+        "mpl_data_containers",
+        "mpl_data_containers Documentation",
+        [author],
+        1,
+    )
 ]
 
 
@@ -230,10 +236,10 @@
 texinfo_documents = [
     (
         master_doc,
-        "data_prototype",
-        "data_prototype Documentation",
+        "mpl_data_containers",
+        "mpl_data_containers Documentation",
         author,
-        "data_prototype",
+        "mpl_data_containers",
         "Experimental code for the upcoming Matplotlib data refactor.",
         "Miscellaneous",
     ),
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 1c91676..6443db1 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -3,7 +3,7 @@
    You can adapt this file completely to your liking, but it should at least
    contain the root `toctree` directive.
 
-data_prototype Documentation
+mpl_data_containers Documentation
 ============================
 
 This is prototype development for the next generation of data structures for
diff --git a/docs/source/installation.rst b/docs/source/installation.rst
index c52bee5..c33a471 100644
--- a/docs/source/installation.rst
+++ b/docs/source/installation.rst
@@ -4,4 +4,4 @@ Installation
 
 At the command line::
 
-    $ pip install git+https://github.com/tacaswell/data-prototype.git@main
+    $ pip install git+https://github.com/matplotlib/data-prototype.git@main
diff --git a/examples/2Dfunc.py b/examples/2Dfunc.py
index 883b932..a033252 100644
--- a/examples/2Dfunc.py
+++ b/examples/2Dfunc.py
@@ -10,9 +10,9 @@
 import matplotlib.pyplot as plt
 import numpy as np
 
-from data_prototype.artist import CompatibilityAxes
-from data_prototype.image import Image
-from data_prototype.containers import FuncContainer
+from mpl_data_containers.artist import CompatibilityAxes
+from mpl_data_containers.image import Image
+from mpl_data_containers.containers import FuncContainer
 
 from matplotlib.colors import Normalize
 
diff --git a/examples/animation.py b/examples/animation.py
index ee2cf45..74b5b82 100644
--- a/examples/animation.py
+++ b/examples/animation.py
@@ -17,14 +17,14 @@
 import matplotlib.pyplot as plt
 from matplotlib.animation import FuncAnimation
 
-from data_prototype.conversion_edge import Graph
-from data_prototype.description import Desc
+from mpl_data_containers.conversion_edge import Graph
+from mpl_data_containers.description import Desc
 
 
-from data_prototype.artist import CompatibilityAxes
-from data_prototype.line import Line
-from data_prototype.text import Text
-from data_prototype.conversion_edge import FuncEdge
+from mpl_data_containers.artist import CompatibilityAxes
+from mpl_data_containers.line import Line
+from mpl_data_containers.text import Text
+from mpl_data_containers.conversion_edge import FuncEdge
 
 
 class SinOfTime:
diff --git a/examples/data_frame.py b/examples/data_frame.py
index 201a33f..f65617e 100644
--- a/examples/data_frame.py
+++ b/examples/data_frame.py
@@ -11,9 +11,9 @@
 import numpy as np
 import pandas as pd
 
-from data_prototype.artist import CompatibilityArtist as CA
-from data_prototype.line import Line
-from data_prototype.containers import DataFrameContainer
+from mpl_data_containers.artist import CompatibilityArtist as CA
+from mpl_data_containers.line import Line
+from mpl_data_containers.containers import DataFrameContainer
 
 th = np.linspace(0, 4 * np.pi, 256)
 
diff --git a/examples/errorbar.py b/examples/errorbar.py
index fcf03ff..b4f1a4f 100644
--- a/examples/errorbar.py
+++ b/examples/errorbar.py
@@ -11,8 +11,8 @@
 import numpy as np
 
 
-from data_prototype.wrappers import ErrorbarWrapper
-from data_prototype.containers import ArrayContainer
+from mpl_data_containers.wrappers import ErrorbarWrapper
+from mpl_data_containers.containers import ArrayContainer
 
 x = np.arange(10)
 y = x**2
diff --git a/examples/first.py b/examples/first.py
index d8baf8d..3a9deb8 100644
--- a/examples/first.py
+++ b/examples/first.py
@@ -11,9 +11,9 @@
 import numpy as np
 import pandas as pd
 
-from data_prototype.artist import CompatibilityAxes
-from data_prototype.line import Line
-from data_prototype.containers import FuncContainer, SeriesContainer
+from mpl_data_containers.artist import CompatibilityAxes
+from mpl_data_containers.line import Line
+from mpl_data_containers.containers import FuncContainer, SeriesContainer
 
 
 fc = FuncContainer({"x": (("N",), lambda x: x), "y": (("N",), lambda x: np.sin(1 / x))})
diff --git a/examples/hist.py b/examples/hist.py
index 4fd45d3..7381f32 100644
--- a/examples/hist.py
+++ b/examples/hist.py
@@ -10,8 +10,8 @@
 import matplotlib.pyplot as plt
 import numpy as np
 
-from data_prototype.wrappers import StepWrapper
-from data_prototype.containers import HistContainer
+from mpl_data_containers.wrappers import StepWrapper
+from mpl_data_containers.containers import HistContainer
 
 hc = HistContainer(
     np.concatenate([np.random.randn(5000), 0.1 * np.random.randn(500) + 5]), 25
diff --git a/examples/lissajous.py b/examples/lissajous.py
index 777838e..2c58d99 100644
--- a/examples/lissajous.py
+++ b/examples/lissajous.py
@@ -19,10 +19,10 @@
 import matplotlib.markers as mmarkers
 from matplotlib.animation import FuncAnimation
 
-from data_prototype.conversion_edge import Graph
-from data_prototype.description import Desc
+from mpl_data_containers.conversion_edge import Graph
+from mpl_data_containers.description import Desc
 
-from data_prototype.wrappers import PathCollectionWrapper
+from mpl_data_containers.wrappers import PathCollectionWrapper
 
 
 class Lissajous:
diff --git a/examples/mandelbrot.py b/examples/mandelbrot.py
index 9f447e2..eca2094 100644
--- a/examples/mandelbrot.py
+++ b/examples/mandelbrot.py
@@ -13,9 +13,9 @@
 import matplotlib.pyplot as plt
 import numpy as np
 
-from data_prototype.artist import CompatibilityAxes
-from data_prototype.image import Image
-from data_prototype.containers import FuncContainer
+from mpl_data_containers.artist import CompatibilityAxes
+from mpl_data_containers.image import Image
+from mpl_data_containers.containers import FuncContainer
 
 from matplotlib.colors import Normalize
 
diff --git a/examples/mapped.py b/examples/mapped.py
index 4800019..90c0998 100644
--- a/examples/mapped.py
+++ b/examples/mapped.py
@@ -12,12 +12,12 @@
 
 from matplotlib.colors import Normalize
 
-from data_prototype.artist import CompatibilityAxes
-from data_prototype.line import Line
-from data_prototype.containers import ArrayContainer
-from data_prototype.description import Desc
-from data_prototype.conversion_edge import FuncEdge
-from data_prototype.text import Text
+from mpl_data_containers.artist import CompatibilityAxes
+from mpl_data_containers.line import Line
+from mpl_data_containers.containers import ArrayContainer
+from mpl_data_containers.description import Desc
+from mpl_data_containers.conversion_edge import FuncEdge
+from mpl_data_containers.text import Text
 
 
 cmap = plt.colormaps["viridis"]
diff --git a/examples/mulivariate_cmap.py b/examples/mulivariate_cmap.py
index 8b33ca8..f5ec57d 100644
--- a/examples/mulivariate_cmap.py
+++ b/examples/mulivariate_cmap.py
@@ -11,11 +11,11 @@
 import matplotlib.pyplot as plt
 import numpy as np
 
-from data_prototype.image import Image
-from data_prototype.artist import CompatibilityAxes
-from data_prototype.description import Desc
-from data_prototype.containers import FuncContainer
-from data_prototype.conversion_edge import FuncEdge
+from mpl_data_containers.image import Image
+from mpl_data_containers.artist import CompatibilityAxes
+from mpl_data_containers.description import Desc
+from mpl_data_containers.containers import FuncContainer
+from mpl_data_containers.conversion_edge import FuncEdge
 
 from matplotlib.colors import hsv_to_rgb
 
diff --git a/examples/new_patch.py b/examples/new_patch.py
index 2c9d4c3..124265f 100644
--- a/examples/new_patch.py
+++ b/examples/new_patch.py
@@ -12,9 +12,9 @@
 import matplotlib.pyplot as plt
 
 
-from data_prototype.artist import CompatibilityAxes
-from data_prototype.patches import Patch
-from data_prototype.containers import ArrayContainer
+from mpl_data_containers.artist import CompatibilityAxes
+from mpl_data_containers.patches import Patch
+from mpl_data_containers.containers import ArrayContainer
 
 from matplotlib.path import Path
 
diff --git a/examples/scatter_with_custom_axes.py b/examples/scatter_with_custom_axes.py
index a5122d4..a781b2d 100644
--- a/examples/scatter_with_custom_axes.py
+++ b/examples/scatter_with_custom_axes.py
@@ -4,19 +4,19 @@
 =========================================
 
 This is a quick comparison between the current Matplotlib `scatter` and
-the version in :file:`data_prototype/axes.py`, which uses data containers
+the version in :file:`mpl_data_containers/axes.py`, which uses data containers
 and a conversion pipeline.
 
 This is here to show what does work and what does not work with the current
 implementation of container-based artist drawing.
 """
 
-import data_prototype.axes  # side-effect registers projection # noqa
+import mpl_data_containers.axes  # side-effect registers projection # noqa
 
 import matplotlib.pyplot as plt
 
 fig = plt.figure()
-newstyle = fig.add_subplot(2, 1, 1, projection="data-prototype")
+newstyle = fig.add_subplot(2, 1, 1, projection="mpl-data-containers")
 oldstyle = fig.add_subplot(2, 1, 2)
 
 newstyle.scatter([0, 1, 2], [2, 5, 1])
diff --git a/examples/simple_patch.py b/examples/simple_patch.py
index 63b9057..1c1febb 100644
--- a/examples/simple_patch.py
+++ b/examples/simple_patch.py
@@ -14,10 +14,10 @@
 import matplotlib.pyplot as plt
 import matplotlib.patches as mpatches
 
-from data_prototype.containers import ArrayContainer
-from data_prototype.artist import CompatibilityAxes
+from mpl_data_containers.containers import ArrayContainer
+from mpl_data_containers.artist import CompatibilityAxes
 
-from data_prototype.patches import Rectangle
+from mpl_data_containers.patches import Rectangle
 
 cont1 = ArrayContainer(
     lower_left_x=np.array(-3),
diff --git a/examples/simple_scatter.py b/examples/simple_scatter.py
index 9b3fd90..ee21a30 100644
--- a/examples/simple_scatter.py
+++ b/examples/simple_scatter.py
@@ -12,9 +12,9 @@
 import matplotlib.pyplot as plt
 import matplotlib.markers as mmarkers
 
-from data_prototype.containers import ArrayContainer
+from mpl_data_containers.containers import ArrayContainer
 
-from data_prototype.wrappers import PathCollectionWrapper
+from mpl_data_containers.wrappers import PathCollectionWrapper
 
 marker_obj = mmarkers.MarkerStyle("o")
 
diff --git a/examples/subsample.py b/examples/subsample.py
index 97a67d7..0357176 100644
--- a/examples/subsample.py
+++ b/examples/subsample.py
@@ -20,10 +20,10 @@
 
 import numpy as np
 
-from data_prototype.description import Desc, desc_like
-from data_prototype.artist import CompatibilityArtist as CA
-from data_prototype.image import Image
-from data_prototype.containers import ArrayContainer
+from mpl_data_containers.description import Desc, desc_like
+from mpl_data_containers.artist import CompatibilityArtist as CA
+from mpl_data_containers.image import Image
+from mpl_data_containers.containers import ArrayContainer
 
 from skimage.transform import downscale_local_mean
 
diff --git a/examples/units.py b/examples/units.py
index 74a246f..ff4d2c6 100644
--- a/examples/units.py
+++ b/examples/units.py
@@ -12,12 +12,12 @@
 import matplotlib.pyplot as plt
 import matplotlib.markers as mmarkers
 
-from data_prototype.artist import CompatibilityAxes
-from data_prototype.containers import ArrayContainer
-from data_prototype.conversion_edge import FuncEdge
-from data_prototype.description import Desc
+from mpl_data_containers.artist import CompatibilityAxes
+from mpl_data_containers.containers import ArrayContainer
+from mpl_data_containers.conversion_edge import FuncEdge
+from mpl_data_containers.description import Desc
 
-from data_prototype.line import Line
+from mpl_data_containers.line import Line
 
 import pint
 
diff --git a/examples/widgets.py b/examples/widgets.py
index ac19874..5043e12 100644
--- a/examples/widgets.py
+++ b/examples/widgets.py
@@ -14,11 +14,11 @@
 import matplotlib.pyplot as plt
 from matplotlib.widgets import Slider, Button
 
-from data_prototype.artist import CompatibilityArtist as CA
-from data_prototype.line import Line
-from data_prototype.containers import FuncContainer
-from data_prototype.description import Desc
-from data_prototype.conversion_edge import FuncEdge
+from mpl_data_containers.artist import CompatibilityArtist as CA
+from mpl_data_containers.line import Line
+from mpl_data_containers.containers import FuncContainer
+from mpl_data_containers.description import Desc
+from mpl_data_containers.conversion_edge import FuncEdge
 
 
 class SliderContainer(FuncContainer):
diff --git a/data_prototype/__init__.py b/mpl_data_containers/__init__.py
similarity index 100%
rename from data_prototype/__init__.py
rename to mpl_data_containers/__init__.py
diff --git a/data_prototype/artist.py b/mpl_data_containers/artist.py
similarity index 100%
rename from data_prototype/artist.py
rename to mpl_data_containers/artist.py
diff --git a/data_prototype/axes.py b/mpl_data_containers/axes.py
similarity index 98%
rename from data_prototype/axes.py
rename to mpl_data_containers/axes.py
index 5659701..68093c7 100644
--- a/data_prototype/axes.py
+++ b/mpl_data_containers/axes.py
@@ -19,7 +19,7 @@
 
 class Axes(MPLAxes):
     # Name for registering as a projection so we can experiment with it
-    name = "data-prototype"
+    name = "mpl-data-containers"
 
     @_preprocess_data(
         replace_names=[
@@ -143,5 +143,5 @@ def scatter(
         return pcw
 
 
-# This is a handy trick to allow e.g. plt.subplots(subplot_kw={'projection': 'data-prototype'})
+# This is a handy trick to allow e.g. plt.subplots(subplot_kw={'projection': 'mpl-data-containers'})
 mprojections.register_projection(Axes)
diff --git a/data_prototype/containers.py b/mpl_data_containers/containers.py
similarity index 100%
rename from data_prototype/containers.py
rename to mpl_data_containers/containers.py
diff --git a/data_prototype/conversion_edge.py b/mpl_data_containers/conversion_edge.py
similarity index 99%
rename from data_prototype/conversion_edge.py
rename to mpl_data_containers/conversion_edge.py
index 8562dc2..4c074d5 100644
--- a/data_prototype/conversion_edge.py
+++ b/mpl_data_containers/conversion_edge.py
@@ -7,7 +7,7 @@
 from typing import Any
 import numpy as np
 
-from data_prototype.description import Desc, desc_like, ShapeSpec
+from mpl_data_containers.description import Desc, desc_like, ShapeSpec
 
 from matplotlib.transforms import Transform
 
diff --git a/data_prototype/conversion_node.py b/mpl_data_containers/conversion_node.py
similarity index 100%
rename from data_prototype/conversion_node.py
rename to mpl_data_containers/conversion_node.py
diff --git a/data_prototype/description.py b/mpl_data_containers/description.py
similarity index 100%
rename from data_prototype/description.py
rename to mpl_data_containers/description.py
diff --git a/data_prototype/image.py b/mpl_data_containers/image.py
similarity index 100%
rename from data_prototype/image.py
rename to mpl_data_containers/image.py
diff --git a/data_prototype/introspection.py b/mpl_data_containers/introspection.py
similarity index 100%
rename from data_prototype/introspection.py
rename to mpl_data_containers/introspection.py
diff --git a/data_prototype/line.py b/mpl_data_containers/line.py
similarity index 100%
rename from data_prototype/line.py
rename to mpl_data_containers/line.py
diff --git a/data_prototype/patches.py b/mpl_data_containers/patches.py
similarity index 100%
rename from data_prototype/patches.py
rename to mpl_data_containers/patches.py
diff --git a/data_prototype/tests/__init__.py b/mpl_data_containers/tests/__init__.py
similarity index 100%
rename from data_prototype/tests/__init__.py
rename to mpl_data_containers/tests/__init__.py
diff --git a/data_prototype/tests/conftest.py b/mpl_data_containers/tests/conftest.py
similarity index 100%
rename from data_prototype/tests/conftest.py
rename to mpl_data_containers/tests/conftest.py
diff --git a/data_prototype/tests/test_check_shape.py b/mpl_data_containers/tests/test_check_shape.py
similarity index 98%
rename from data_prototype/tests/test_check_shape.py
rename to mpl_data_containers/tests/test_check_shape.py
index f499761..47d8d0f 100644
--- a/data_prototype/tests/test_check_shape.py
+++ b/mpl_data_containers/tests/test_check_shape.py
@@ -1,6 +1,6 @@
 import pytest
 
-from data_prototype.description import Desc
+from mpl_data_containers.description import Desc
 
 
 @pytest.mark.parametrize(
diff --git a/data_prototype/tests/test_containers.py b/mpl_data_containers/tests/test_containers.py
similarity index 100%
rename from data_prototype/tests/test_containers.py
rename to mpl_data_containers/tests/test_containers.py
diff --git a/data_prototype/tests/test_examples.py b/mpl_data_containers/tests/test_examples.py
similarity index 100%
rename from data_prototype/tests/test_examples.py
rename to mpl_data_containers/tests/test_examples.py
diff --git a/data_prototype/text.py b/mpl_data_containers/text.py
similarity index 100%
rename from data_prototype/text.py
rename to mpl_data_containers/text.py
diff --git a/data_prototype/wrappers.py b/mpl_data_containers/wrappers.py
similarity index 98%
rename from data_prototype/wrappers.py
rename to mpl_data_containers/wrappers.py
index f80eb9b..de66c46 100644
--- a/data_prototype/wrappers.py
+++ b/mpl_data_containers/wrappers.py
@@ -18,10 +18,10 @@
 )
 from matplotlib.artist import Artist as _Artist
 
-from data_prototype.containers import DataContainer, _MatplotlibTransform
-from data_prototype.description import Desc, desc_like
-from data_prototype.conversion_edge import TransformEdge, Graph
-from data_prototype.conversion_node import (
+from mpl_data_containers.containers import DataContainer, _MatplotlibTransform
+from mpl_data_containers.description import Desc, desc_like
+from mpl_data_containers.conversion_edge import TransformEdge, Graph
+from mpl_data_containers.conversion_node import (
     ConversionNode,
     RenameConversionNode,
     evaluate_pipeline,
diff --git a/setup.py b/setup.py
index eb88ad7..814e73c 100644
--- a/setup.py
+++ b/setup.py
@@ -9,7 +9,7 @@
 min_version = (3, 10)
 if sys.version_info < min_version:
     error = """
-data_prototype does not support Python {0}.{1}.
+mpl_data_containers does not support Python {0}.{1}.
 Python {2}.{3} and above is required. Check your Python version like so:
 
 python3 --version
@@ -38,12 +38,12 @@
 
 
 setup(
-    name="data_prototype",
+    name="mpl_data_containers",
     description="Experimental code for the upcoming Matplotlib data refactor.",
     long_description=readme,
-    author="Thomas A Caswell",
-    author_email="tcaswell@gmail.com",
-    url="https://github.com/tacaswell/data_prototype",
+    author="Kyle Sunden",
+    author_email="pypi@ksunden.space",
+    url="https://github.com/matplotlib/data-prototype",
     python_requires=">={}".format(".".join(str(n) for n in min_version)),
     packages=find_packages(exclude=["docs", "tests"]),
     entry_points={
@@ -59,12 +59,12 @@
     use_scm_version={
         "version_scheme": "release-branch-semver",
         "local_scheme": "node-and-date",
-        "write_to": "data_prototype/_version.py",
+        "write_to": "mpl_data_containers/_version.py",
         "fallback_version": "0.0+UNKNOWN",
     },
     include_package_data=True,
     package_data={
-        "data_prototype": [
+        "mpl_data_containers": [
             # When adding files here, remember to update MANIFEST.in as well,
             # or else they will not be included in the distribution on PyPI!
             # 'path/to/data_file',

From 2733b858cf0914c07d434745bfad5b9851ac35f9 Mon Sep 17 00:00:00 2001
From: Kyle Sunden <git@ksunden.space>
Date: Fri, 25 Apr 2025 14:30:02 -0500
Subject: [PATCH 08/10] fix dotfiles which reference old path

---
 .coveragerc | 2 +-
 .flake8     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.coveragerc b/.coveragerc
index 9712b4f..6678b95 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,6 +1,6 @@
 [run]
 source =
-    data_prototype
+    mpl_data_containers
 [report]
 omit =
     */python?.?/*
diff --git a/.flake8 b/.flake8
index 2399875..f283183 100644
--- a/.flake8
+++ b/.flake8
@@ -5,7 +5,7 @@ exclude =
     build,
     dist,
     versioneer.py,
-    data_prototype/_version.py,
+    mpl_data_containers/_version.py,
     docs/source/conf.py
     setup.py
     .eggs

From be53f0cb16adb1bb4e91bd5069d132d86a1a1d7a Mon Sep 17 00:00:00 2001
From: Kyle Sunden <git@ksunden.space>
Date: Fri, 25 Apr 2025 14:33:15 -0500
Subject: [PATCH 09/10] fix doc rst underline

---
 docs/source/index.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/source/index.rst b/docs/source/index.rst
index 6443db1..feef25a 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -4,7 +4,7 @@
    contain the root `toctree` directive.
 
 mpl_data_containers Documentation
-============================
+=================================
 
 This is prototype development for the next generation of data structures for
 Matplotlib.  This is the version "to throw away".  Everything in this

From 879277a680c7e29fe5da39a6bea69ac2e84c4757 Mon Sep 17 00:00:00 2001
From: Kyle Sunden <git@ksunden.space>
Date: Thu, 1 May 2025 14:01:21 -0500
Subject: [PATCH 10/10] Review comments

---
 README.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/README.rst b/README.rst
index a454e5c..2f809de 100644
--- a/README.rst
+++ b/README.rst
@@ -1,6 +1,6 @@
-==============
+===================
 mpl_data_containers
-==============
+===================
 
 Experimental code for the upcoming Matplotlib data refactor.