Here is my picture. I need to make label for those bars however every upper layer contains lower layer – so the label should containt grouped colors, i.e. blue – dataset 1, blue/orange – dataset 2, blue/orange/green – dataset 3 and finally blue/orange/green/purple – dataset 4. Is it plausible to make it? Thank you.
JavaScript
x
14
14
1
binwidth = 1
2
n, bins, patches = ax1.hist(C, bins=range(81, 105, binwidth),
3
density=False, histtype='barstacked' ,
4
edgecolor='gray',
5
color=barvy_histogram,linewidth=0.3)
6
7
hatches = ['//','x','..','oo']
8
for patch_set, hatch in zip(patches, hatches):
9
for patch in patch_set.patches:
10
patch.set_hatch(hatch)
11
patch.set_linewidth=0.1
12
patch.set_color='gray'
13
mpl.rcParams['hatch.linewidth'] = 0.5
14
Advertisement
Answer
The following approach uses the tuple legend handler (HandlerTuple
) to combine the legend handles. It produces a horizontal layout, while maybe a vertical stacking would be more interesting.
The code starts with creating some test data, supposing C
is an Nx4
array of integers. The bin edges are set at halves to make sure that floating point accuracy wouldn’t place values in the wrong bin.
JavaScript
1
30
30
1
import matplotlib as mpl
2
import matplotlib.pyplot as plt
3
from matplotlib.legend_handler import HandlerTuple
4
import numpy as np
5
6
# first, create some test data
7
C = (np.random.normal(0.001, 1, (100, 20)).cumsum(axis=0) * 1.2 + 90).astype(int).reshape(-1, 4)
8
c_min = C.min()
9
c_max = C.max()
10
11
mpl.rcParams['hatch.linewidth'] = 0.5
12
fig, ax1 = plt.subplots(figsize=(12, 5))
13
binwidth = 1
14
colors = plt.cm.Set2.colors[:C.shape[1]]
15
_, _, patches = ax1.hist(C, bins=np.arange(c_min - 0.5, c_max + binwidth, binwidth),
16
density=False, histtype='barstacked',
17
edgecolor='gray', color=colors, linewidth=0.3,
18
label=[f'N={p}' for p in range(25, 101, 25)])
19
20
hatches = ['//', 'x', '..', 'oo']
21
for patch_set, hatch in zip(patches, hatches):
22
for patch in patch_set.patches:
23
patch.set_hatch(hatch)
24
patch.set_linewidth = 0.1
25
26
handles, labels = ax1.get_legend_handles_labels()
27
ax1.legend(handles=[tuple(handles[:i + 1]) for i in range(C.shape[1])], labels=labels,
28
handlelength=6, handler_map={tuple: HandlerTuple(ndivide=None, pad=0)})
29
plt.show()
30