marsilea 0.3.2__py3-none-any.whl → 0.3.3__py3-none-any.whl
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.
- marsilea/__init__.py +3 -2
- marsilea/_api.py +3 -2
- marsilea/_deform.py +44 -38
- marsilea/base.py +702 -118
- marsilea/dataset.py +49 -23
- marsilea/dendrogram.py +119 -84
- marsilea/exceptions.py +5 -6
- marsilea/heatmap.py +85 -25
- marsilea/layers.py +77 -69
- marsilea/layout.py +132 -102
- marsilea/plotter/__init__.py +29 -0
- marsilea/plotter/_images.py +37 -7
- marsilea/plotter/_seaborn.py +35 -24
- marsilea/plotter/_utils.py +3 -2
- marsilea/plotter/arc.py +29 -19
- marsilea/plotter/area.py +80 -0
- marsilea/plotter/bar.py +113 -90
- marsilea/plotter/base.py +76 -49
- marsilea/plotter/bio.py +40 -30
- marsilea/plotter/mesh.py +184 -88
- marsilea/plotter/text.py +303 -194
- marsilea/upset.py +229 -151
- marsilea/utils.py +23 -10
- {marsilea-0.3.2.dist-info → marsilea-0.3.3.dist-info}/LICENSE +1 -1
- marsilea-0.3.3.dist-info/METADATA +74 -0
- marsilea-0.3.3.dist-info/RECORD +27 -0
- marsilea-0.3.2.dist-info/METADATA +0 -50
- marsilea-0.3.2.dist-info/RECORD +0 -26
- {marsilea-0.3.2.dist-info → marsilea-0.3.3.dist-info}/WHEEL +0 -0
marsilea/plotter/_seaborn.py
CHANGED
|
@@ -14,10 +14,17 @@ class _SeabornBase(StatsBase):
|
|
|
14
14
|
hue = None
|
|
15
15
|
data = None
|
|
16
16
|
|
|
17
|
-
def __init__(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
data,
|
|
20
|
+
hue_order=None,
|
|
21
|
+
palette=None,
|
|
22
|
+
orient=None,
|
|
23
|
+
label=None,
|
|
24
|
+
legend_kws=None,
|
|
25
|
+
group_kws=None,
|
|
26
|
+
**kwargs,
|
|
27
|
+
):
|
|
21
28
|
if isinstance(data, Mapping):
|
|
22
29
|
datasets = []
|
|
23
30
|
self.hue = []
|
|
@@ -25,8 +32,7 @@ class _SeabornBase(StatsBase):
|
|
|
25
32
|
hue_order = data.keys()
|
|
26
33
|
for name in hue_order:
|
|
27
34
|
self.hue.append(name)
|
|
28
|
-
datasets.append(
|
|
29
|
-
self.data_validator(data[name]))
|
|
35
|
+
datasets.append(self.data_validator(data[name]))
|
|
30
36
|
if isinstance(palette, Mapping):
|
|
31
37
|
self.palette = palette
|
|
32
38
|
else:
|
|
@@ -35,16 +41,16 @@ class _SeabornBase(StatsBase):
|
|
|
35
41
|
else:
|
|
36
42
|
colors = color_palette(palette, as_cmap=False)
|
|
37
43
|
self.palette = dict(zip(self.hue, colors))
|
|
38
|
-
kwargs[
|
|
44
|
+
kwargs["palette"] = self.palette
|
|
39
45
|
self.set_data(*datasets)
|
|
40
46
|
else:
|
|
41
47
|
data = self.data_validator(data)
|
|
42
48
|
self.set_data(data)
|
|
43
|
-
kwargs.setdefault('color', 'C0')
|
|
49
|
+
# kwargs.setdefault('color', 'C0')
|
|
44
50
|
# if (palette is None) and ('color' not in kwargs):
|
|
45
51
|
# kwargs['palette'] = "dark:C0"
|
|
46
52
|
if palette is not None:
|
|
47
|
-
kwargs[
|
|
53
|
+
kwargs["palette"] = palette
|
|
48
54
|
|
|
49
55
|
kwargs.pop("x", None)
|
|
50
56
|
kwargs.pop("y", None)
|
|
@@ -71,40 +77,45 @@ class _SeabornBase(StatsBase):
|
|
|
71
77
|
return CatLegend(colors=colors, labels=labels, **options)
|
|
72
78
|
|
|
73
79
|
def render_ax(self, spec):
|
|
74
|
-
|
|
75
80
|
ax = spec.ax
|
|
76
81
|
data = spec.data
|
|
77
82
|
gp = spec.group_params
|
|
78
83
|
if gp is None:
|
|
79
84
|
gp = {}
|
|
80
|
-
|
|
85
|
+
x, y = "var", "value"
|
|
81
86
|
if self.hue is not None:
|
|
82
|
-
|
|
83
|
-
x, y = "var", "value"
|
|
84
87
|
dfs = []
|
|
85
88
|
for d, hue in zip(data, self.hue):
|
|
86
89
|
df = pd.DataFrame(d)
|
|
87
90
|
df = df.melt(var_name="var", value_name="value")
|
|
88
|
-
df[
|
|
91
|
+
df["hue"] = hue
|
|
89
92
|
dfs.append(df)
|
|
90
93
|
|
|
91
94
|
pdata = pd.concat(dfs)
|
|
92
|
-
self.kws[
|
|
93
|
-
self.kws[
|
|
95
|
+
self.kws["hue"] = "hue"
|
|
96
|
+
self.kws["hue_order"] = self.hue
|
|
94
97
|
if self.get_orient() == "h":
|
|
95
98
|
x, y = y, x
|
|
96
|
-
self.kws[
|
|
97
|
-
self.kws[
|
|
99
|
+
self.kws["x"] = x
|
|
100
|
+
self.kws["y"] = y
|
|
101
|
+
options = {**self.kws, **gp}
|
|
98
102
|
|
|
99
103
|
else:
|
|
100
|
-
pdata = pd.DataFrame(data)
|
|
104
|
+
pdata = pd.DataFrame(data).melt(var_name="var", value_name="value")
|
|
105
|
+
if self.get_orient() == "h":
|
|
106
|
+
x, y = y, x
|
|
107
|
+
self.kws["x"] = x
|
|
108
|
+
self.kws["y"] = y
|
|
109
|
+
options = {**self.kws, **gp}
|
|
110
|
+
if options.get("palette") is not None:
|
|
111
|
+
options["hue"] = "var"
|
|
101
112
|
|
|
102
113
|
orient = self.get_orient()
|
|
103
114
|
if self.side == "left":
|
|
104
115
|
ax.invert_xaxis()
|
|
105
116
|
# barplot(data=data, orient=orient, ax=ax, **self.kws)
|
|
106
117
|
plotter = getattr(seaborn, self._seaborn_plot)
|
|
107
|
-
|
|
118
|
+
|
|
108
119
|
plotter(data=pdata, orient=orient, ax=ax, **options)
|
|
109
120
|
ax.set(xlabel=None, ylabel=None)
|
|
110
121
|
leg = ax.get_legend()
|
|
@@ -122,13 +133,13 @@ def _seaborn_doc(obj: _SeabornBase):
|
|
|
122
133
|
|
|
123
134
|
if cls_name == "Swarm":
|
|
124
135
|
sdata = "np.random.rand(50, 10)"
|
|
125
|
-
kws = "
|
|
126
|
-
h_kws = "group_kws={'
|
|
136
|
+
kws = "color='#DB4D6D', size=2, dodge=True"
|
|
137
|
+
h_kws = "group_kws={'color': colors}, size=2"
|
|
127
138
|
|
|
128
139
|
elif cls_name == "Strip":
|
|
129
140
|
sdata = "np.random.rand(50, 10)"
|
|
130
|
-
kws = "
|
|
131
|
-
h_kws = "group_kws={'
|
|
141
|
+
kws = "color='#DB4D6D', size=2, dodge=True"
|
|
142
|
+
h_kws = "group_kws={'color': colors}, size=2"
|
|
132
143
|
|
|
133
144
|
elif cls_name == "Point":
|
|
134
145
|
hue_data = "{'a': sdata, 'b': sdata * 2}"
|
marsilea/plotter/_utils.py
CHANGED
marsilea/plotter/arc.py
CHANGED
|
@@ -15,8 +15,7 @@ class LinkAttrs:
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class Links:
|
|
18
|
-
def __init__(self, links, weights=None, width=None,
|
|
19
|
-
colors=None, labels=None):
|
|
18
|
+
def __init__(self, links, weights=None, width=None, colors=None, labels=None):
|
|
20
19
|
self._links = {}
|
|
21
20
|
self._links_attr = {}
|
|
22
21
|
|
|
@@ -34,16 +33,20 @@ class Links:
|
|
|
34
33
|
self.colors = [colors for _ in links]
|
|
35
34
|
else:
|
|
36
35
|
if len(colors) != len(links):
|
|
37
|
-
msg =
|
|
38
|
-
|
|
36
|
+
msg = (
|
|
37
|
+
f"Length of colors ({len(colors)}) does not "
|
|
38
|
+
f"match length of links ({len(links)})"
|
|
39
|
+
)
|
|
39
40
|
raise ValueError(msg)
|
|
40
41
|
self.colors = colors
|
|
41
42
|
|
|
42
43
|
self.legend_entries = None
|
|
43
44
|
if labels is not None:
|
|
44
45
|
if len(labels) != len(links):
|
|
45
|
-
msg =
|
|
46
|
-
|
|
46
|
+
msg = (
|
|
47
|
+
f"Length of labels ({len(labels)}) does not "
|
|
48
|
+
f"match length of links ({len(links)})"
|
|
49
|
+
)
|
|
47
50
|
raise ValueError(msg)
|
|
48
51
|
self.legend_entries = dict(zip(labels, colors))
|
|
49
52
|
|
|
@@ -120,7 +123,7 @@ class Arc(StatsBase):
|
|
|
120
123
|
label_loc : str, optional
|
|
121
124
|
Location of the label. Must be one of the following:
|
|
122
125
|
"left", "right", "top", "bottom", "center".
|
|
123
|
-
|
|
126
|
+
label_props : dict, optional
|
|
124
127
|
Keyword arguments passed to `matplotlib.text.Text`.
|
|
125
128
|
**kwargs
|
|
126
129
|
Keyword arguments passed to `matplotlib.patches.Arc`.
|
|
@@ -148,22 +151,31 @@ class Arc(StatsBase):
|
|
|
148
151
|
|
|
149
152
|
render_main = False
|
|
150
153
|
|
|
151
|
-
def __init__(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
154
|
+
def __init__(
|
|
155
|
+
self,
|
|
156
|
+
anchors,
|
|
157
|
+
links,
|
|
158
|
+
weights=None,
|
|
159
|
+
width=None,
|
|
160
|
+
colors=None,
|
|
161
|
+
labels=None,
|
|
162
|
+
legend_kws=None,
|
|
163
|
+
label=None,
|
|
164
|
+
label_loc=None,
|
|
165
|
+
label_props=None,
|
|
166
|
+
**kwargs,
|
|
167
|
+
):
|
|
155
168
|
if len(np.unique(anchors)) != len(anchors):
|
|
156
169
|
raise ValueError("`anchors` must be unique")
|
|
157
170
|
anchors = self.data_validator(anchors, target="1d")
|
|
158
171
|
self.set_data(anchors)
|
|
159
|
-
self.links = Links(
|
|
160
|
-
|
|
172
|
+
self.links = Links(
|
|
173
|
+
links, weights=weights, width=width, colors=colors, labels=labels
|
|
174
|
+
)
|
|
161
175
|
self.options = kwargs
|
|
162
176
|
self.legend_kws = {} if legend_kws is None else legend_kws
|
|
163
177
|
|
|
164
|
-
self.label
|
|
165
|
-
self.label_loc = label_loc
|
|
166
|
-
self.props = props
|
|
178
|
+
self.set_label(label, label_loc, label_props)
|
|
167
179
|
|
|
168
180
|
def render_ax(self, spec):
|
|
169
181
|
ax = spec.ax
|
|
@@ -183,7 +195,6 @@ class Arc(StatsBase):
|
|
|
183
195
|
for link in links:
|
|
184
196
|
link_in_data = anchors_coords.get(link)
|
|
185
197
|
if link_in_data is not None:
|
|
186
|
-
|
|
187
198
|
arc_start = anchors_coords[anchor]
|
|
188
199
|
arc_end = link_in_data
|
|
189
200
|
if arc_end < arc_start:
|
|
@@ -210,8 +221,7 @@ class Arc(StatsBase):
|
|
|
210
221
|
xy = (arc_mid, 0)
|
|
211
222
|
angle = 0
|
|
212
223
|
sizes.append(arc_width)
|
|
213
|
-
arc = mArc(xy, arc_width, arc_width * 2,
|
|
214
|
-
angle=angle, **options)
|
|
224
|
+
arc = mArc(xy, arc_width, arc_width * 2, angle=angle, **options)
|
|
215
225
|
ax.add_patch(arc)
|
|
216
226
|
|
|
217
227
|
lim = np.max(sizes)
|
marsilea/plotter/area.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from marsilea.plotter.base import StatsBase
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Area(StatsBase):
|
|
7
|
+
"""Area plot
|
|
8
|
+
|
|
9
|
+
Parameters
|
|
10
|
+
----------
|
|
11
|
+
data : array-like
|
|
12
|
+
The data to be plotted.
|
|
13
|
+
color : color-like
|
|
14
|
+
The color of the area
|
|
15
|
+
add_outline : bool
|
|
16
|
+
Whether to add outline to the area
|
|
17
|
+
alpha : float
|
|
18
|
+
The transparency of the area
|
|
19
|
+
linecolor : color-like
|
|
20
|
+
The color of the outline
|
|
21
|
+
linewidth : float
|
|
22
|
+
The width of the outline
|
|
23
|
+
group_kws : dict
|
|
24
|
+
The configurations that apply to each group
|
|
25
|
+
**kwargs :
|
|
26
|
+
Additional configurations for the area plot, \
|
|
27
|
+
see :func:`matplotlib.pyplot.fill_between`
|
|
28
|
+
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, data, color=None, add_outline=True, alpha=.4,
|
|
32
|
+
linecolor=None, linewidth=1,
|
|
33
|
+
group_kws=None, label=None, label_loc=None, label_props=None,
|
|
34
|
+
**kwargs):
|
|
35
|
+
|
|
36
|
+
if color is None:
|
|
37
|
+
color = "skyblue"
|
|
38
|
+
if linecolor is None:
|
|
39
|
+
linecolor = "Slateblue"
|
|
40
|
+
|
|
41
|
+
self.color = color
|
|
42
|
+
self.add_outline = add_outline
|
|
43
|
+
self.alpha = alpha
|
|
44
|
+
self.linecolor = linecolor
|
|
45
|
+
self.linewidth = linewidth
|
|
46
|
+
self.kws = kwargs
|
|
47
|
+
|
|
48
|
+
self.set_data(data)
|
|
49
|
+
if group_kws is not None:
|
|
50
|
+
self.set_group_params(group_kws)
|
|
51
|
+
|
|
52
|
+
def render_ax(self, spec):
|
|
53
|
+
ax = spec.ax
|
|
54
|
+
data = spec.data
|
|
55
|
+
gp = spec.group_params
|
|
56
|
+
if gp is None:
|
|
57
|
+
gp = {}
|
|
58
|
+
|
|
59
|
+
fill_options = {'colo': self.color, 'alpha': self.alpha, **self.kws, **gp}
|
|
60
|
+
line_options = {'color': self.linecolor, 'linewidth': self.linewidth, **gp}
|
|
61
|
+
|
|
62
|
+
x = np.arange(len(data))
|
|
63
|
+
if self.get_orient() == "h":
|
|
64
|
+
ax.fill_betweenx(x, data, **fill_options)
|
|
65
|
+
if self.add_outline:
|
|
66
|
+
ax.plot(data, x, **line_options)
|
|
67
|
+
ax.set_ylim(-.5, len(data)-.5)
|
|
68
|
+
if self.side == "left":
|
|
69
|
+
ax.invert_xaxis()
|
|
70
|
+
else:
|
|
71
|
+
ax.fill_between(x, data, **fill_options)
|
|
72
|
+
if self.add_outline:
|
|
73
|
+
ax.plot(x, data, **line_options)
|
|
74
|
+
ax.set_xlim(-.5, len(data)-.5)
|
|
75
|
+
return ax
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# TODO: Implement StackArea
|
|
79
|
+
class StackArea(StatsBase):
|
|
80
|
+
pass
|
marsilea/plotter/bar.py
CHANGED
|
@@ -12,16 +12,17 @@ from .base import StatsBase
|
|
|
12
12
|
from ..utils import ECHARTS16
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
def simple_bar(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
def simple_bar(
|
|
16
|
+
data,
|
|
17
|
+
ax: Axes = None,
|
|
18
|
+
orient="v",
|
|
19
|
+
width=0.8,
|
|
20
|
+
show_value=True,
|
|
21
|
+
fmt=None,
|
|
22
|
+
label_pad=2,
|
|
23
|
+
text_props=None,
|
|
24
|
+
**kwargs,
|
|
25
|
+
):
|
|
25
26
|
if ax is None:
|
|
26
27
|
ax = plt.gca()
|
|
27
28
|
if text_props is None:
|
|
@@ -29,18 +30,22 @@ def simple_bar(data,
|
|
|
29
30
|
bar = ax.bar if orient == "v" else ax.barh
|
|
30
31
|
bars = bar(np.arange(0, len(data)) + 0.5, data, width, **kwargs)
|
|
31
32
|
if show_value:
|
|
32
|
-
ax.bar_label(bars, data, fmt=fmt,
|
|
33
|
-
padding=label_pad,
|
|
34
|
-
**text_props)
|
|
33
|
+
ax.bar_label(bars, data, fmt=fmt, padding=label_pad, **text_props)
|
|
35
34
|
return ax
|
|
36
35
|
|
|
37
36
|
|
|
38
37
|
class _BarBase(StatsBase):
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
def _process_params(
|
|
39
|
+
self,
|
|
40
|
+
width=0.7,
|
|
41
|
+
orient=None,
|
|
42
|
+
show_value=True,
|
|
43
|
+
fmt=None,
|
|
44
|
+
label=None,
|
|
45
|
+
value_pad=2.0,
|
|
46
|
+
props=None,
|
|
47
|
+
**kwargs,
|
|
48
|
+
):
|
|
44
49
|
self.width = width
|
|
45
50
|
self.orient = orient
|
|
46
51
|
self.show_value = show_value
|
|
@@ -86,18 +91,29 @@ class Numbers(_BarBase):
|
|
|
86
91
|
>>> data = np.random.randint(1, 10, 10)
|
|
87
92
|
>>> _, ax = plt.subplots()
|
|
88
93
|
>>> Numbers(data).render(ax)
|
|
89
|
-
|
|
94
|
+
|
|
90
95
|
"""
|
|
91
96
|
|
|
92
|
-
def __init__(
|
|
93
|
-
|
|
94
|
-
|
|
97
|
+
def __init__(
|
|
98
|
+
self,
|
|
99
|
+
data,
|
|
100
|
+
width=0.8,
|
|
101
|
+
color="C0",
|
|
102
|
+
orient=None,
|
|
103
|
+
show_value=True,
|
|
104
|
+
fmt=None,
|
|
105
|
+
label=None,
|
|
106
|
+
value_pad=2.0,
|
|
107
|
+
props=None,
|
|
108
|
+
**kwargs,
|
|
109
|
+
):
|
|
95
110
|
self.set_data(self.data_validator(data, target="1d"))
|
|
96
111
|
self.color = color
|
|
97
112
|
self.bars = None
|
|
98
113
|
|
|
99
|
-
self._process_params(
|
|
100
|
-
|
|
114
|
+
self._process_params(
|
|
115
|
+
width, orient, show_value, fmt, label, value_pad, props, **kwargs
|
|
116
|
+
)
|
|
101
117
|
|
|
102
118
|
def render_ax(self, spec):
|
|
103
119
|
ax = spec.ax
|
|
@@ -108,8 +124,9 @@ class Numbers(_BarBase):
|
|
|
108
124
|
bar = ax.bar if orient == "v" else ax.barh
|
|
109
125
|
if orient == "h":
|
|
110
126
|
data = data[::-1]
|
|
111
|
-
self.bars = bar(
|
|
112
|
-
|
|
127
|
+
self.bars = bar(
|
|
128
|
+
np.arange(0, lim) + 0.5, data, self.width, color=self.color, **self.options
|
|
129
|
+
)
|
|
113
130
|
|
|
114
131
|
if orient == "v":
|
|
115
132
|
ax.set_xlim(0, lim)
|
|
@@ -120,9 +137,7 @@ class Numbers(_BarBase):
|
|
|
120
137
|
ax.invert_xaxis()
|
|
121
138
|
|
|
122
139
|
if self.show_value:
|
|
123
|
-
ax.bar_label(self.bars, fmt=self.fmt,
|
|
124
|
-
padding=self.value_pad,
|
|
125
|
-
**self.props)
|
|
140
|
+
ax.bar_label(self.bars, fmt=self.fmt, padding=self.value_pad, **self.props)
|
|
126
141
|
|
|
127
142
|
|
|
128
143
|
class CenterBar(_BarBase):
|
|
@@ -175,10 +190,20 @@ class CenterBar(_BarBase):
|
|
|
175
190
|
|
|
176
191
|
"""
|
|
177
192
|
|
|
178
|
-
def __init__(
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
193
|
+
def __init__(
|
|
194
|
+
self,
|
|
195
|
+
data,
|
|
196
|
+
names=None,
|
|
197
|
+
width=0.8,
|
|
198
|
+
colors=None,
|
|
199
|
+
orient=None,
|
|
200
|
+
show_value=True,
|
|
201
|
+
fmt=None,
|
|
202
|
+
label=None,
|
|
203
|
+
value_pad=2.0,
|
|
204
|
+
props=None,
|
|
205
|
+
**kwargs,
|
|
206
|
+
):
|
|
182
207
|
self.set_data(self.data_validator(data.T, target="2d"))
|
|
183
208
|
if names is None:
|
|
184
209
|
if isinstance(data, pd.DataFrame):
|
|
@@ -188,11 +213,11 @@ class CenterBar(_BarBase):
|
|
|
188
213
|
colors = ["C0", "C1"]
|
|
189
214
|
self.colors = colors
|
|
190
215
|
|
|
191
|
-
self._process_params(
|
|
192
|
-
|
|
216
|
+
self._process_params(
|
|
217
|
+
width, orient, show_value, fmt, label, value_pad, props, **kwargs
|
|
218
|
+
)
|
|
193
219
|
|
|
194
220
|
def render_ax(self, spec):
|
|
195
|
-
|
|
196
221
|
ax = spec.ax
|
|
197
222
|
data = spec.data
|
|
198
223
|
|
|
@@ -212,36 +237,28 @@ class CenterBar(_BarBase):
|
|
|
212
237
|
left_bar, right_bar = data[0], data[1]
|
|
213
238
|
locs = np.arange(0, len(left_bar)) + 0.5
|
|
214
239
|
|
|
215
|
-
bar1 = bar(locs, left_bar, self.width,
|
|
216
|
-
|
|
217
|
-
bar2 = bar(locs, -right_bar, self.width,
|
|
218
|
-
color=self.colors[1], **self.options)
|
|
240
|
+
bar1 = bar(locs, left_bar, self.width, color=self.colors[0], **self.options)
|
|
241
|
+
bar2 = bar(locs, -right_bar, self.width, color=self.colors[1], **self.options)
|
|
219
242
|
line(0, color="black", lw=1)
|
|
220
243
|
if self.names is not None:
|
|
221
244
|
n1, n2 = self.names
|
|
222
245
|
if orient == "h" and spec.is_first:
|
|
223
|
-
ax.text(.45, 1, n1, ha="right", va="bottom",
|
|
224
|
-
|
|
225
|
-
ax.text(.55, 1, n2, ha="left", va="bottom",
|
|
226
|
-
transform=ax.transAxes)
|
|
246
|
+
ax.text(0.45, 1, n1, ha="right", va="bottom", transform=ax.transAxes)
|
|
247
|
+
ax.text(0.55, 1, n2, ha="left", va="bottom", transform=ax.transAxes)
|
|
227
248
|
elif orient == "v" and spec.is_last:
|
|
228
|
-
ax.text(1, .75, n1, ha="left", va="center",
|
|
229
|
-
|
|
230
|
-
ax.text(1, .25, n2, ha="left", va="center",
|
|
231
|
-
transform=ax.transAxes)
|
|
249
|
+
ax.text(1, 0.75, n1, ha="left", va="center", transform=ax.transAxes)
|
|
250
|
+
ax.text(1, 0.25, n2, ha="left", va="center", transform=ax.transAxes)
|
|
232
251
|
|
|
233
252
|
lim_value = np.max(data) * 1.05
|
|
234
253
|
|
|
235
254
|
if orient == "v":
|
|
236
255
|
ax.set_xlim(0, len(left_bar))
|
|
237
256
|
ax.set_ylim(-lim_value, lim_value)
|
|
238
|
-
ax.yaxis.set_major_formatter(
|
|
239
|
-
FuncFormatter(lambda x, p: f"{np.abs(x):g}"))
|
|
257
|
+
ax.yaxis.set_major_formatter(FuncFormatter(lambda x, p: f"{np.abs(x):g}"))
|
|
240
258
|
else:
|
|
241
259
|
ax.set_ylim(0, len(left_bar))
|
|
242
260
|
ax.set_xlim(-lim_value, lim_value)
|
|
243
|
-
ax.xaxis.set_major_formatter(
|
|
244
|
-
FuncFormatter(lambda x, p: f"{np.abs(x):g}"))
|
|
261
|
+
ax.xaxis.set_major_formatter(FuncFormatter(lambda x, p: f"{np.abs(x):g}"))
|
|
245
262
|
|
|
246
263
|
if self.is_flank:
|
|
247
264
|
ax.invert_yaxis()
|
|
@@ -249,12 +266,8 @@ class CenterBar(_BarBase):
|
|
|
249
266
|
if self.show_value:
|
|
250
267
|
left_label = _format_labels(left_bar, self.fmt)
|
|
251
268
|
right_label = _format_labels(right_bar, self.fmt)
|
|
252
|
-
ax.bar_label(bar1, left_label,
|
|
253
|
-
|
|
254
|
-
**self.props)
|
|
255
|
-
ax.bar_label(bar2, right_label,
|
|
256
|
-
padding=self.value_pad,
|
|
257
|
-
**self.props)
|
|
269
|
+
ax.bar_label(bar1, left_label, padding=self.value_pad, **self.props)
|
|
270
|
+
ax.bar_label(bar2, right_label, padding=self.value_pad, **self.props)
|
|
258
271
|
|
|
259
272
|
|
|
260
273
|
class StackBar(_BarBase):
|
|
@@ -282,7 +295,7 @@ class StackBar(_BarBase):
|
|
|
282
295
|
The spacing between value and the bar
|
|
283
296
|
props : dict
|
|
284
297
|
See :class:`matplotlib.text.Text`
|
|
285
|
-
kwargs:
|
|
298
|
+
kwargs :
|
|
286
299
|
Other keyword arguments passed to :meth:`matplotlib.axes.Axes.bar`
|
|
287
300
|
|
|
288
301
|
|
|
@@ -299,8 +312,7 @@ class StackBar(_BarBase):
|
|
|
299
312
|
>>> StackBar(stack_data).render(ax)
|
|
300
313
|
|
|
301
314
|
|
|
302
|
-
You may find the text is too big for a bar to display on, to not display
|
|
303
|
-
certain value.
|
|
315
|
+
You may find the text is too big for a bar to display on, to not display certain value.
|
|
304
316
|
|
|
305
317
|
.. plot::
|
|
306
318
|
:context: close-figs
|
|
@@ -309,23 +321,25 @@ class StackBar(_BarBase):
|
|
|
309
321
|
>>> _, ax = plt.subplots()
|
|
310
322
|
>>> StackBar(stack_data, show_value=True, fmt=fmt).render(ax)
|
|
311
323
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
def __init__(
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
324
|
+
"""
|
|
325
|
+
|
|
326
|
+
def __init__(
|
|
327
|
+
self,
|
|
328
|
+
data,
|
|
329
|
+
items=None,
|
|
330
|
+
colors=None,
|
|
331
|
+
orient=None,
|
|
332
|
+
show_value=False,
|
|
333
|
+
value_loc="center",
|
|
334
|
+
width=0.8,
|
|
335
|
+
value_size=6,
|
|
336
|
+
fmt=None,
|
|
337
|
+
props=None,
|
|
338
|
+
label=None,
|
|
339
|
+
value_pad=0,
|
|
340
|
+
legend_kws=None,
|
|
341
|
+
**kwargs,
|
|
342
|
+
):
|
|
329
343
|
# TODO: Support bare bone numpy array as input
|
|
330
344
|
item_names = None
|
|
331
345
|
if isinstance(data, pd.DataFrame):
|
|
@@ -341,8 +355,10 @@ class StackBar(_BarBase):
|
|
|
341
355
|
else:
|
|
342
356
|
if isinstance(colors, Mapping):
|
|
343
357
|
if item_names is None:
|
|
344
|
-
raise ValueError(
|
|
345
|
-
|
|
358
|
+
raise ValueError(
|
|
359
|
+
"Please provide the name of each item "
|
|
360
|
+
"before assigning color."
|
|
361
|
+
)
|
|
346
362
|
bar_colors = [colors[name] for name in item_names]
|
|
347
363
|
else:
|
|
348
364
|
bar_colors = colors
|
|
@@ -359,8 +375,9 @@ class StackBar(_BarBase):
|
|
|
359
375
|
value_props = dict(label_type=value_loc)
|
|
360
376
|
value_props.update(props)
|
|
361
377
|
|
|
362
|
-
self._process_params(
|
|
363
|
-
|
|
378
|
+
self._process_params(
|
|
379
|
+
width, orient, show_value, fmt, label, value_pad, value_props, **kwargs
|
|
380
|
+
)
|
|
364
381
|
|
|
365
382
|
self.value_size = value_size
|
|
366
383
|
self._legend_kws = dict(title=self.label, size=1)
|
|
@@ -369,8 +386,9 @@ class StackBar(_BarBase):
|
|
|
369
386
|
|
|
370
387
|
def get_legends(self):
|
|
371
388
|
if self.labels is not None:
|
|
372
|
-
return CatLegend(
|
|
373
|
-
|
|
389
|
+
return CatLegend(
|
|
390
|
+
colors=self.bar_colors, labels=self.labels, **self._legend_kws
|
|
391
|
+
)
|
|
374
392
|
|
|
375
393
|
def render_ax(self, spec):
|
|
376
394
|
ax = spec.ax
|
|
@@ -399,13 +417,18 @@ class StackBar(_BarBase):
|
|
|
399
417
|
labels = self.labels[::-1]
|
|
400
418
|
else:
|
|
401
419
|
labels = [None for _ in range(len(data))]
|
|
402
|
-
colors = self.bar_colors[:len(data)]
|
|
420
|
+
colors = self.bar_colors[: len(data)]
|
|
403
421
|
for ix, row in enumerate(data):
|
|
404
|
-
bars = bar(
|
|
405
|
-
|
|
406
|
-
|
|
422
|
+
bars = bar(
|
|
423
|
+
locs,
|
|
424
|
+
row,
|
|
425
|
+
self.width,
|
|
426
|
+
bottom,
|
|
427
|
+
fc=colors[ix],
|
|
428
|
+
label=labels[ix],
|
|
429
|
+
**self.options,
|
|
430
|
+
)
|
|
407
431
|
bottom += row
|
|
408
432
|
|
|
409
433
|
if self.show_value:
|
|
410
|
-
ax.bar_label(bars, fmt=self.fmt, padding=self.value_pad,
|
|
411
|
-
**self.props)
|
|
434
|
+
ax.bar_label(bars, fmt=self.fmt, padding=self.value_pad, **self.props)
|