Skip to content

Commit 7f85b52

Browse files
committed
Begin shifting group edges, not working yet
1 parent e09c108 commit 7f85b52

File tree

3 files changed

+102
-7
lines changed

3 files changed

+102
-7
lines changed

iplotx/groups.py

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
from .heuristics import normalise_layout, normalise_grouping
1515
from .styles import get_style
1616
from .tools.geometry import convex_hull
17+
from .tools.geometry import _compute_group_path_with_vertex_padding
1718

1819

1920
class GroupingArtist(PatchCollection):
2021
def __init__(
2122
self,
2223
grouping: GroupingType,
2324
layout: LayoutType,
25+
vertexpadding: Union[None, int] = None,
2426
*args,
2527
**kwargs,
2628
):
@@ -34,6 +36,11 @@ def __init__(
3436
vertices are assumed to have IDs corresponding to integers starting from
3537
zero.
3638
"""
39+
if vertexpadding is not None:
40+
self._vertexpadding = vertexpadding
41+
else:
42+
style = get_style(".grouping")
43+
self._vertexpadding = style.get("vertexpadding", 10)
3744
patches, grouping, layout = self._create_patches(grouping, layout, **kwargs)
3845
self._grouping = grouping
3946
self._layout = layout
@@ -45,6 +52,7 @@ def _create_patches(self, grouping, layout, **kwargs):
4552
layout = normalise_layout(layout)
4653
grouping = normalise_grouping(grouping, layout)
4754
style = get_style(".grouping")
55+
style.pop("vertexpadding", None)
4856

4957
style.update(kwargs)
5058

@@ -57,15 +65,55 @@ def _create_patches(self, grouping, layout, **kwargs):
5765
idx_hull = convex_hull(coords)
5866
coords_hull = coords[idx_hull]
5967

60-
patches.append(
61-
mpl.patches.Polygon(
62-
coords_hull,
63-
label=name,
64-
# NOTE: the transform is set later on
65-
**style,
66-
)
68+
# NOTE: the transform is set later on
69+
patch = _compute_group_patch_stub(
70+
coords_hull,
71+
self._vertexpadding,
72+
label=name,
73+
**style,
6774
)
75+
76+
patches.append(patch)
6877
return patches, grouping, layout
6978

7079
def _process(self):
7180
self.set_transform(self.axes.transData)
81+
if self._vertexpadding > 0:
82+
for i, path in enumerate(self._paths):
83+
self._paths[i].vertices = _compute_group_path_with_vertex_padding(
84+
path.vertices,
85+
self.get_transform(),
86+
vertexpadding=self._vertexpadding,
87+
)
88+
89+
90+
def _compute_group_patch_stub(
91+
points,
92+
vertexpadding,
93+
**kwargs,
94+
):
95+
if vertexpadding == 0:
96+
return mpl.patches.Polygon(
97+
points,
98+
**kwargs,
99+
)
100+
101+
vertices = []
102+
codes = []
103+
for point in points:
104+
vertices.extend([point] * 3)
105+
codes.extend(["LINETO", "CURVE3", "CURVE3"])
106+
codes[0] = "MOVETO"
107+
vertices.append(vertices[0])
108+
codes.append("CLOSEPOLY")
109+
110+
codes = [getattr(mpl.path.Path, x) for x in codes]
111+
patch = mpl.patches.PathPatch(
112+
mpl.path.Path(
113+
vertices,
114+
codes=codes,
115+
),
116+
**kwargs,
117+
)
118+
119+
return patch

iplotx/styles.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"edgecolor": "black",
3535
"linewidth": 1.5,
3636
"alpha": 0.5,
37+
"vertexpadding": 10,
3738
},
3839
}
3940

iplotx/tools/geometry.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from math import tan, atan2
12
import numpy as np
23

34

@@ -132,3 +133,48 @@ def _convex_hull_Graham_scan(points):
132133
stack = np.asarray(stack)
133134

134135
return stack
136+
137+
138+
def _compute_group_path_with_vertex_padding(
139+
points,
140+
transform,
141+
vertexpadding=10,
142+
):
143+
"""Offset path for a group based on vertex padding.
144+
145+
At the input, the structure is [v1, v1, v1, v2, v2, v2, ...]
146+
"""
147+
148+
# Transform into figure coordinates
149+
trans = transform.transform
150+
trans_inv = transform.inverted().transform
151+
points = trans(points)
152+
153+
# Compute all shift vectors by diff, arctan2, then add 90 degrees, tan, norm
154+
# This maintains chirality
155+
156+
# Diff
157+
vpoints = points[:-1:3].copy()
158+
vpoints[1:] -= vpoints[:-1]
159+
vpoints[0] -= vpoints[-1]
160+
161+
# Argtan etc
162+
angles = np.arctan2(vpoints[:, 1], vpoints[:, 0])
163+
angles_orth = angles + np.pi / 2
164+
m_orth = np.tan(angles_orth)
165+
166+
# Normalise to 1
167+
vpads = (np.vstack([np.ones_like(m_orth), m_orth]) / (1 + m_orth**2) ** 0.5).T
168+
vpads_rot = np.zeros_like(vpads)
169+
vpads_rot[:-1] = vpads[1:]
170+
vpads_rot[-1] = vpads[0]
171+
172+
# Shift the points
173+
points[:-1:3] += vpads_rot * vertexpadding
174+
points[1:-1:3] += (vpads + vpads_rot) * vertexpadding
175+
points[2:-1:3] += vpads * vertexpadding
176+
177+
# Transform back to data coordinates
178+
points = trans_inv(points)
179+
180+
return points

0 commit comments

Comments
 (0)