
* https://hackmd.io/@story645/scipy2021mpl
* tag: @story645, @matplotlib
---
# Thanks
* CZI EOSS 1 & 3 for supporting Thomas Caswell, Michael Grossberg, and me
* Thomas Caswell & Michael Grossberg
* Sam & Melissa
* YT for making the best presentations to steal ideas from
* the Matplotlib team :hearts:
---
## Rearchitecture Goals
* Identify the different types of transformations
* Formalize the rules of these transformations
* Implement in a way that respects seperation
<!--why? makes it easier to code against, implement, maintain, correctly write these abstractions, improves consistency in complex cases-->
---
### What is Matplotlib's job?
<!--provide components for converting data to graphics-->

---
### How does Matplotlib do it?
<!-- the artist object-->

----
<!-- stress it takes in an object, it forwards to an object, list of objects -->

---
### What is the proposed API?
<!-- is about functions, drop ins, decoupled flexibility -->

---
### Graphic -> Data: Topology
<!-- make the point here that it's about breaking out of the structure, is for a general model -->

----
<!--- dig down into scatter to explain what we mean by topology --->

----
<!---implicit assumption scatter is backed by discrete points-->

----
<!-- made explicit via arrows rather than hard coding any assumption-->

----
<!--- can verify w/ shuffle -->

----
<!-- what happens when we connect?-->

----
<!--- still have map back to data-->

----
<!--- but introduce map that doesn't exist --->

<!--wrap w/ how this allows us to express graphic to data relationships w/o relying on one notion of continuity-->
---
### Data -> Graphic: Equivariance
<!--visualization is structure preserving maps, by structure we mean things like measurment type-->

----
<!--precip is ratio, distance between Jan 1 and Jan 2 and Jan 2 and Jan 3 is proportionally same in data and viz-->

----
<!-- scaling the data induces scaling in the viz-->

---
### Why? Multivariate Multidimensional Data
<!--space + label or change to histogram, add in all points but keep 3 points, top and right to precip -->

----
<!--- bookeeeping problem-->

----
<!--- topology & generalized data model--->

----
<!--- equivariance and consistent updates-->

----

---
### Takeaways
<!--reframe goals, + overall status-->
* decoupling the data, visual encoding, and plot assembly steps
* provides easier to code against interface
* improves reliability, consistency, maintability
* conceptual prototype: https://github.com/story645/proposal
---
### Thank you!!
* contact: @story645, haizenman@gmail.com
* discourse: https://discourse.matplotlib.org/
* gitter: https://gitter.im/matplotlib/matplotlib
---
## Appendix
---
### Functional API model
```python
def fiberbundle(section):
index = section.section.index
def projection(column_name):
def values(): #
if column_name is None:
return pd.Series(index=index, dtype=float)
return section.section[column_name][index]
return values
return projection
return subset_k #s
```
----
```python
@dataclass
class Section:
F = {'fruit': np.dtype('O'),
'calories': np.dtype('int64'),
'juice': np.dtype('bool')}
K = pd.core.indexes.range.RangeIndex
section: pd.DataFrame
def __post_init__(self):
#check the fiber matches
assert self.section.dtypes.to_dict() == self.F
assert isinstance(self.section.index, self.K)
````
----
```python
data = {'fruit': ['apple', 'orange', 'lemon', 'lime'],
'calories':[95, 67, 17, 20],
'juice':[True, True, False, False]}
df = pd.DataFrame(data)
fruit.fiberbundle(fruit.Section(df))(None)('juice')()
```
---
```python
nus = {'position': lambda x : x,
'length' : position.Nominal({'apple': 0, 'orange': 2, 'lemon': 4, 'lime': 6}),
'floor': lambda _: 0,
'width': lambda _ : .8,
'facecolor' : color.Nominal({True: 'orange', False: 'blue'}),
'edgecolor' : lambda _ : 'k',
'linewidth' : lambda _ : 2,
'linestyle' : lambda _ : (None, None)}
```
---
```python
class BarArtist(martist.Artist):
#view is fruit.fiberbundle
def __init__(self, view, orientation, aes, position, length, floor, width, facecolors, edgecolors, linewidths, linestyles):
# some function unpacking/ set parametrs
def assemble(pos, ..., fc):
xval = pos
paths = [[(x, y), (x, y+yo), (x+xo, y+yo), (x+xo, y), (x, y)]
for (x, xo, y, yo) in zip(xval, xoff, yval, yoff)]
return paths, ..., fc
def draw(self, renderer, *args, **kwargs):
#conversion works something like
pos = position(view(self.data)(None)(aes['position']))
# ....
fc = facecolors(view(self.data)(None)(aes['facecolors']))
# all the visual conversion gets pushed to child artists
self.assemble(pos, ..., fc)
```
---
### Topological Equivariant Artist Model
----
<!--sorry didn't have time for alt text yet, these are diagrams of the math. Please bug me for more info if interested-->

----

----

----

----

----

----

----

----

{"metaMigratedAt":"2023-06-16T04:31:53.494Z","metaMigratedFrom":"YAML","title":"mpl maintainers talk","breaks":false,"description":"Scipy2021 Maintainers Track Talk","slideOptions":"{\"theme\":\"simple\"}","contributors":"[{\"id\":\"2d96a489-4097-4766-8206-715ac7bd25bb\",\"add\":15449,\"del\":8081}]"}