py2ls 0.1.6.2__py3-none-any.whl → 0.1.6.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.
- py2ls/ips.py +0 -344
- py2ls/plot.py +1109 -0
- {py2ls-0.1.6.2.dist-info → py2ls-0.1.6.3.dist-info}/METADATA +1 -1
- {py2ls-0.1.6.2.dist-info → py2ls-0.1.6.3.dist-info}/RECORD +5 -8
- py2ls/plot/catplot.py +0 -437
- py2ls/plot/figsets.py +0 -372
- py2ls/plot/get_color.py +0 -68
- py2ls/plot/stdshade.py +0 -227
- {py2ls-0.1.6.2.dist-info → py2ls-0.1.6.3.dist-info}/WHEEL +0 -0
py2ls/plot.py
ADDED
@@ -0,0 +1,1109 @@
|
|
1
|
+
import matplotlib.pyplot as plt
|
2
|
+
import numpy as np
|
3
|
+
from matplotlib.colors import to_rgba
|
4
|
+
from scipy.stats import gaussian_kde
|
5
|
+
|
6
|
+
def catplot(data, *args, **kwargs):
|
7
|
+
"""
|
8
|
+
catplot(data, opt=None, ax=None)
|
9
|
+
|
10
|
+
Args:
|
11
|
+
data (array): data matrix
|
12
|
+
"""
|
13
|
+
def plot_bars(data_m, opt_b, xloc, ax):
|
14
|
+
bar_positions = get_positions(xloc, opt_b['loc'], opt_b['x_width'], data.shape[0])
|
15
|
+
bar_positions=np.nanmean(bar_positions,axis=0)
|
16
|
+
for i, (x, y) in enumerate(zip(bar_positions, data_m)):
|
17
|
+
color = to_rgba(opt_b['FaceColor'][i % len(opt_b['FaceColor'])])
|
18
|
+
ax.bar(x, y,
|
19
|
+
width=opt_b['x_width'],
|
20
|
+
color=color,
|
21
|
+
edgecolor=opt_b['EdgeColor'],
|
22
|
+
alpha=opt_b['FaceAlpha'])
|
23
|
+
|
24
|
+
def plot_errors(data, data_m, opt_e, xloc, ax):
|
25
|
+
error_positions = get_positions(xloc, opt_e['loc'], opt_e['x_width'], data.shape[0])
|
26
|
+
error_positions=np.nanmean(error_positions,axis=0)
|
27
|
+
errors = np.nanstd(data, axis=0)
|
28
|
+
if opt_e['error'] == 'sem':
|
29
|
+
errors /= np.sqrt(np.sum(~np.isnan(data),axis=0))
|
30
|
+
|
31
|
+
if not isinstance(opt_e['FaceColor'],list):
|
32
|
+
opt_e['FaceColor']=[opt_e['FaceColor']]
|
33
|
+
if not isinstance(opt_e['MarkerEdgeColor'],list):
|
34
|
+
opt_e['MarkerEdgeColor']=[opt_e['MarkerEdgeColor']]
|
35
|
+
for i, (x, y, err) in enumerate(zip(error_positions, data_m, errors)):
|
36
|
+
ax.errorbar(x, y, yerr=err,
|
37
|
+
fmt=opt_e['Marker'],
|
38
|
+
ecolor=opt_e['LineColor'],
|
39
|
+
elinewidth=opt_e['LineWidth'],
|
40
|
+
lw=opt_e['LineWidth'],
|
41
|
+
ls=opt_e['LineStyle'],
|
42
|
+
capsize=opt_e['CapSize'],
|
43
|
+
capthick=opt_e['CapLineWidth'],
|
44
|
+
markersize=opt_e['MarkerSize'],
|
45
|
+
mec=opt_e['MarkerEdgeColor'][i % len(opt_e['MarkerEdgeColor'])],
|
46
|
+
mfc=opt_e['FaceColor'][i % len(opt_e['FaceColor'])],
|
47
|
+
visible=opt_e['Visible']
|
48
|
+
)
|
49
|
+
|
50
|
+
def plot_scatter(data, opt_s, xloc, ax):
|
51
|
+
scatter_positions = get_positions(xloc, opt_s['loc'], opt_s['x_width'], data.shape[0])
|
52
|
+
for i, (x, y) in enumerate(zip(scatter_positions.T, data.T)):
|
53
|
+
color = to_rgba(opt_s['FaceColor'][i % len(opt_s['FaceColor'])])
|
54
|
+
ax.scatter(x, y,
|
55
|
+
color=color,
|
56
|
+
alpha=opt_s['FaceAlpha'],
|
57
|
+
edgecolor=opt_s['MarkerEdgeColor'],
|
58
|
+
s=opt_s['MarkerSize'],
|
59
|
+
marker=opt_s['Marker']
|
60
|
+
)
|
61
|
+
|
62
|
+
def plot_boxplot(data, bx_opt, xloc,ax):
|
63
|
+
if 'l' in bx_opt['loc']:
|
64
|
+
X_bx = xloc - bx_opt['x_width']
|
65
|
+
elif 'r' in bx_opt['loc']:
|
66
|
+
X_bx = xloc + bx_opt['x_width']
|
67
|
+
elif 'i' in bx_opt['loc']:
|
68
|
+
X_bx = xloc
|
69
|
+
X_bx[:, 0] += bx_opt['x_width']
|
70
|
+
X_bx[:, -1] -= bx_opt['x_width']
|
71
|
+
elif 'o' in bx_opt['loc']:
|
72
|
+
X_bx = xloc
|
73
|
+
X_bx[:, 0] -= bx_opt['x_width']
|
74
|
+
X_bx[:, -1] += bx_opt['x_width']
|
75
|
+
elif 'c' in bx_opt['loc'] or 'm' in bx_opt['loc']:
|
76
|
+
X_bx = xloc
|
77
|
+
else:
|
78
|
+
X_bx = xloc
|
79
|
+
|
80
|
+
|
81
|
+
boxprops = dict(color=bx_opt['EdgeColor'],
|
82
|
+
linewidth=bx_opt['BoxLineWidth'])
|
83
|
+
flierprops = dict(marker=bx_opt['OutlierMarker'],
|
84
|
+
markerfacecolor=bx_opt['OutlierColor'],
|
85
|
+
markersize=bx_opt['OutlierSize'])
|
86
|
+
whiskerprops = dict(linestyle=bx_opt['WhiskerLineStyle'],
|
87
|
+
color=bx_opt['WhiskerLineColor'],
|
88
|
+
linewidth=bx_opt['WhiskerLineWidth'])
|
89
|
+
capprops = dict(color=bx_opt['CapLineColor'],
|
90
|
+
linewidth=bx_opt['CapLineWidth'],)
|
91
|
+
medianprops = dict(linestyle=bx_opt['MedianLineStyle'],
|
92
|
+
color=bx_opt['MedianLineColor'],
|
93
|
+
linewidth=bx_opt['MedianLineWidth'])
|
94
|
+
meanprops = dict(linestyle=bx_opt['MeanLineStyle'],
|
95
|
+
color=bx_opt['MeanLineColor'],
|
96
|
+
linewidth=bx_opt['MeanLineWidth'])
|
97
|
+
bxp = ax.boxplot(data,
|
98
|
+
positions=X_bx,
|
99
|
+
notch=bx_opt['Notch'],
|
100
|
+
patch_artist=True,
|
101
|
+
boxprops=boxprops,
|
102
|
+
flierprops=flierprops,
|
103
|
+
whiskerprops=whiskerprops,
|
104
|
+
capwidths=bx_opt['CapSize'],
|
105
|
+
showfliers = bx_opt['Outliers'],
|
106
|
+
showcaps = bx_opt['Caps'],
|
107
|
+
capprops=capprops,
|
108
|
+
medianprops=medianprops,
|
109
|
+
meanline=bx_opt['MeanLine'],
|
110
|
+
showmeans=bx_opt['MeanLine'],
|
111
|
+
meanprops =meanprops,
|
112
|
+
widths=bx_opt['x_width'])
|
113
|
+
|
114
|
+
if bx_opt['BoxLineWidth'] < 0.1:
|
115
|
+
bx_opt['EdgeColor'] = 'none'
|
116
|
+
else:
|
117
|
+
bx_opt['EdgeColor'] = bx_opt['EdgeColor']
|
118
|
+
|
119
|
+
for patch, color in zip(bxp['boxes'], bx_opt['FaceColor']):
|
120
|
+
patch.set_facecolor(to_rgba(color, bx_opt['FaceAlpha']))
|
121
|
+
|
122
|
+
if bx_opt['MedianLineTop']:
|
123
|
+
ax.set_children(ax.get_children()[::-1]) # move median line forward
|
124
|
+
|
125
|
+
def plot_violin(data, opt_v, xloc, ax):
|
126
|
+
violin_positions = get_positions(xloc, opt_v['loc'], opt_v['x_width'], data.shape[0])
|
127
|
+
violin_positions = np.nanmean(violin_positions, axis=0)
|
128
|
+
for i, (x, ys) in enumerate(zip(violin_positions, data.T)):
|
129
|
+
ys = ys[~np.isnan(ys)]
|
130
|
+
if len(ys) > 1:
|
131
|
+
kde = gaussian_kde(ys, bw_method=opt_v['BandWidth'])
|
132
|
+
min_val, max_val = ys.min(), ys.max()
|
133
|
+
y_vals = np.linspace(min_val, max_val, opt_v['NumPoints'])
|
134
|
+
kde_vals = kde(y_vals)
|
135
|
+
kde_vals = kde_vals / kde_vals.max() * opt_v['x_width']
|
136
|
+
if 'r' in opt_v['loc'].lower():
|
137
|
+
ax.fill_betweenx(y_vals, x, x + kde_vals,
|
138
|
+
color=opt_v['FaceColor'][i % len(opt_v['FaceColor'])],
|
139
|
+
alpha=opt_v['FaceAlpha'],
|
140
|
+
edgecolor=opt_v['EdgeColor'])
|
141
|
+
elif 'l' in opt_v['loc'].lower() and not 'f' in opt_v['loc'].lower() :
|
142
|
+
ax.fill_betweenx(y_vals, x - kde_vals, x,
|
143
|
+
color=opt_v['FaceColor'][i % len(opt_v['FaceColor'])],
|
144
|
+
alpha=opt_v['FaceAlpha'],
|
145
|
+
edgecolor=opt_v['EdgeColor'])
|
146
|
+
elif 'o' in opt_v['loc'].lower() or 'both' in opt_v['loc'].lower() :
|
147
|
+
ax.fill_betweenx(y_vals, x - kde_vals, x + kde_vals,
|
148
|
+
color=opt_v['FaceColor'][i % len(opt_v['FaceColor'])],
|
149
|
+
alpha=opt_v['FaceAlpha'],
|
150
|
+
edgecolor=opt_v['EdgeColor'])
|
151
|
+
elif 'i' in opt_v['loc'].lower():
|
152
|
+
if i % 2 == 1: # odd number
|
153
|
+
ax.fill_betweenx(y_vals, x -kde_vals, x,
|
154
|
+
color=opt_v['FaceColor'][i % len(opt_v['FaceColor'])],
|
155
|
+
alpha=opt_v['FaceAlpha'],
|
156
|
+
edgecolor=opt_v['EdgeColor'])
|
157
|
+
else:
|
158
|
+
ax.fill_betweenx(y_vals, x, x+kde_vals,
|
159
|
+
color=opt_v['FaceColor'][i % len(opt_v['FaceColor'])],
|
160
|
+
alpha=opt_v['FaceAlpha'],
|
161
|
+
edgecolor=opt_v['EdgeColor'])
|
162
|
+
elif 'f' in opt_v['loc'].lower():
|
163
|
+
ax.fill_betweenx(y_vals, x - kde_vals, x + kde_vals,
|
164
|
+
color=opt_v['FaceColor'][i % len(opt_v['FaceColor'])],
|
165
|
+
alpha=opt_v['FaceAlpha'],
|
166
|
+
edgecolor=opt_v['EdgeColor'])
|
167
|
+
|
168
|
+
def plot_lines(data, opt_l, opt_s, ax):
|
169
|
+
scatter_positions = get_positions(xloc, opt_s['loc'], opt_s['x_width'], data.shape[0])
|
170
|
+
for incol in range(data.shape[1]-1):
|
171
|
+
for irow in range(data.shape[0]):
|
172
|
+
if not np.isnan(data[irow, incol]):
|
173
|
+
if opt_l['LineStyle'] is not None and not opt_l['LineStyle'] =='none':
|
174
|
+
x_data = [scatter_positions[irow, incol], scatter_positions[irow, incol + 1]]
|
175
|
+
y_data = [data[irow, incol], data[irow, incol + 1]]
|
176
|
+
|
177
|
+
|
178
|
+
ax.plot(x_data, y_data,
|
179
|
+
color=opt_l['LineColor'],
|
180
|
+
linestyle=opt_l['LineStyle'],
|
181
|
+
linewidth=opt_l['LineWidth'],
|
182
|
+
alpha=opt_l['LineAlpha'])
|
183
|
+
|
184
|
+
def get_positions(xloc, loc_type, x_width, n_row=None):
|
185
|
+
if 'rand' in loc_type:
|
186
|
+
scatter_positions = np.zeros((n_row, len(xloc)))
|
187
|
+
np.random.seed(111)
|
188
|
+
for i, x in enumerate(xloc):
|
189
|
+
scatter_positions[:, i] = np.random.uniform(x - x_width, x + x_width, n_row)
|
190
|
+
return scatter_positions
|
191
|
+
elif 'l' in loc_type:
|
192
|
+
return np.tile(xloc - x_width,(n_row,1))
|
193
|
+
elif 'r' in loc_type and not 'd' in loc_type:
|
194
|
+
return np.tile(xloc + x_width,(n_row,1))
|
195
|
+
elif 'i' in loc_type:
|
196
|
+
return np.tile(np.concatenate([xloc[:1] + x_width, xloc[1:-1], xloc[-1:] - x_width]),(n_row,1))
|
197
|
+
elif 'o' in loc_type:
|
198
|
+
return np.tile(np.concatenate([xloc[:1] - x_width, xloc[1:-1], xloc[-1:] + x_width]),(n_row,1))
|
199
|
+
else:
|
200
|
+
return np.tile(xloc,(n_row,1))
|
201
|
+
|
202
|
+
opt = kwargs.get('opt',{})
|
203
|
+
ax = kwargs.get('ax',None)
|
204
|
+
if 'ax' not in locals() or ax is None:
|
205
|
+
ax=plt.gca()
|
206
|
+
|
207
|
+
default_colors = np.array([
|
208
|
+
[0, 0, 0],
|
209
|
+
[234, 37, 46],
|
210
|
+
[0, 154, 222],
|
211
|
+
[175, 89, 186],
|
212
|
+
[255, 198, 37],
|
213
|
+
[242, 133, 34]
|
214
|
+
]) / 255.0
|
215
|
+
|
216
|
+
opt.setdefault('c', default_colors)
|
217
|
+
if len(opt['c']) < data.shape[1]:
|
218
|
+
additional_colors = plt.cm.winter(np.linspace(0, 1, data.shape[1] - len(opt['c'])))
|
219
|
+
opt['c'] = np.vstack([opt['c'], additional_colors[:, :3]])
|
220
|
+
|
221
|
+
opt.setdefault('loc', {})
|
222
|
+
opt['loc'].setdefault('go', 0)
|
223
|
+
opt['loc'].setdefault('xloc', np.arange(1, data.shape[1] + 1))
|
224
|
+
|
225
|
+
# export setting
|
226
|
+
opt.setdefault('export', False)
|
227
|
+
opt['export'].setdefault('path', None)
|
228
|
+
print(opt['export'])
|
229
|
+
|
230
|
+
opt.setdefault('b', {})
|
231
|
+
opt['b'].setdefault('go', 0)
|
232
|
+
opt['b'].setdefault('EdgeColor', 'k')
|
233
|
+
opt['b'].setdefault('FaceAlpha', 1)
|
234
|
+
opt['b'].setdefault('EdgeAlpha', 1)
|
235
|
+
opt['b'].setdefault('LineStyle', '-')
|
236
|
+
opt['b'].setdefault('x_width', 0.5)
|
237
|
+
opt['b'].setdefault('ShowBaseLine', 'off')
|
238
|
+
opt['b'].setdefault('loc', 'c')
|
239
|
+
opt['b'].setdefault('FaceColor', opt['c'])
|
240
|
+
|
241
|
+
opt.setdefault('e', {})
|
242
|
+
opt['e'].setdefault('go', 1)
|
243
|
+
opt['e'].setdefault('LineWidth', 1)
|
244
|
+
opt['e'].setdefault('CapLineWidth', 1)
|
245
|
+
opt['e'].setdefault('CapSize', opt['b']['x_width'] * 100 * 0.1)
|
246
|
+
opt['e'].setdefault('Marker', 'none')
|
247
|
+
opt['e'].setdefault('LineStyle', 'none')
|
248
|
+
opt['e'].setdefault('LineColor', 'k')
|
249
|
+
opt['e'].setdefault('LineJoin', 'round')
|
250
|
+
opt['e'].setdefault('MarkerSize', 'auto')
|
251
|
+
opt['e'].setdefault('FaceColor', opt['c'])
|
252
|
+
opt['e'].setdefault('MarkerEdgeColor', 'none')
|
253
|
+
opt['e'].setdefault('Visible', True)
|
254
|
+
opt['e'].setdefault('Orientation', 'vertical')
|
255
|
+
opt['e'].setdefault('error', 'sem')
|
256
|
+
opt['e'].setdefault('loc', 'c')
|
257
|
+
opt['e'].setdefault('x_width', opt['b']['x_width'] / 5)
|
258
|
+
opt['e'].setdefault('cap_dir', 'b')
|
259
|
+
|
260
|
+
opt.setdefault('s', {})
|
261
|
+
opt['s'].setdefault('go', 1)
|
262
|
+
opt['s'].setdefault('x_width', opt['b']['x_width'] / 5)
|
263
|
+
opt['s'].setdefault('Marker', 'o')
|
264
|
+
opt['s'].setdefault('MarkerSize', 6) # Set default size for markers
|
265
|
+
opt['s'].setdefault('LineWidth', 1)
|
266
|
+
opt['s'].setdefault('FaceColor', opt['c'])
|
267
|
+
opt['s'].setdefault('FaceAlpha', 0.6)
|
268
|
+
opt['s'].setdefault('loc', 'random')
|
269
|
+
opt['s'].setdefault('MarkerEdgeColor', None)
|
270
|
+
|
271
|
+
opt.setdefault('bx', {})
|
272
|
+
opt['bx'].setdefault('go', 0)
|
273
|
+
opt['bx'].setdefault('EdgeColor', 'k')
|
274
|
+
opt['bx'].setdefault('FaceAlpha', 1)
|
275
|
+
opt['bx'].setdefault('EdgeAlpha', 1)
|
276
|
+
opt['bx'].setdefault('LineStyle', '-')
|
277
|
+
opt['bx'].setdefault('x_width', 0.5)
|
278
|
+
opt['bx'].setdefault('ShowBaseLine', 'off')
|
279
|
+
opt['bx'].setdefault('loc', 'c')
|
280
|
+
opt['bx'].setdefault('FaceColor', opt['c'])
|
281
|
+
opt['bx'].setdefault('Notch', False)
|
282
|
+
opt['bx'].setdefault('MedianStyle', 'line')
|
283
|
+
opt['bx'].setdefault('Outliers', 'on')
|
284
|
+
opt['bx'].setdefault('OutlierMarker', '+')
|
285
|
+
opt['bx'].setdefault('OutlierColor', 'r')
|
286
|
+
opt['bx'].setdefault('OutlierSize', 6)
|
287
|
+
opt['bx'].setdefault('PlotStyle', 'traditional')
|
288
|
+
opt['bx'].setdefault('FactorDirection', 'auto')
|
289
|
+
opt['bx'].setdefault('Whisker', 1.5)
|
290
|
+
opt['bx'].setdefault('Orientation', 'vertical')
|
291
|
+
opt['bx'].setdefault('BoxLineWidth', 1.5)
|
292
|
+
opt['bx'].setdefault('FaceColor', 'k')
|
293
|
+
opt['bx'].setdefault('WhiskerLineStyle', '-')
|
294
|
+
opt['bx'].setdefault('WhiskerLineColor', 'k')
|
295
|
+
opt['bx'].setdefault('WhiskerLineWidth', 1.5)
|
296
|
+
opt['bx'].setdefault('Caps', True)
|
297
|
+
opt['bx'].setdefault('CapLineColor', 'k')
|
298
|
+
opt['bx'].setdefault('CapLineWidth', 1.5)
|
299
|
+
opt['bx'].setdefault('CapSize', 0.35)
|
300
|
+
opt['bx'].setdefault('MedianLineStyle', '-')
|
301
|
+
opt['bx'].setdefault('MedianLineColor', 'k')
|
302
|
+
opt['bx'].setdefault('MedianLineWidth', 1.5)
|
303
|
+
opt['bx'].setdefault('MedianLineTop', False)
|
304
|
+
opt['bx'].setdefault('MeanLine', False)
|
305
|
+
opt['bx'].setdefault('showmeans', opt['bx']['MeanLine'])
|
306
|
+
opt['bx'].setdefault('MeanLineStyle', '-')
|
307
|
+
opt['bx'].setdefault('MeanLineColor', 'b')
|
308
|
+
opt['bx'].setdefault('MeanLineWidth', 1.5)
|
309
|
+
|
310
|
+
# Violin plot options
|
311
|
+
opt.setdefault('v', {})
|
312
|
+
opt['v'].setdefault('go', 1)
|
313
|
+
opt['v'].setdefault('x_width', 0.3)
|
314
|
+
opt['v'].setdefault('loc', 'r')
|
315
|
+
opt['v'].setdefault('EdgeColor', 'none')
|
316
|
+
opt['v'].setdefault('FaceColor', opt['c'])
|
317
|
+
opt['v'].setdefault('FaceAlpha', 0.3)
|
318
|
+
opt['v'].setdefault('BandWidth', 'scott')
|
319
|
+
opt['v'].setdefault('Function', 'pdf')
|
320
|
+
opt['v'].setdefault('Kernel', 'gau')
|
321
|
+
opt['v'].setdefault('NumPoints', 500)
|
322
|
+
opt['v'].setdefault('BoundaryCorrection', 'reflection')
|
323
|
+
|
324
|
+
# line plot options
|
325
|
+
opt.setdefault('l', {})
|
326
|
+
opt['l'].setdefault('go', 0)
|
327
|
+
opt['l'].setdefault('LineStyle', '-')
|
328
|
+
opt['l'].setdefault('LineColor', 'k')
|
329
|
+
opt['l'].setdefault('LineWidth', 0.5)
|
330
|
+
opt['l'].setdefault('LineAlpha', 0.5)
|
331
|
+
|
332
|
+
data_m = np.nanmean(data, axis=0)
|
333
|
+
nr, nc = data.shape
|
334
|
+
|
335
|
+
xloc = opt['loc']['xloc']
|
336
|
+
|
337
|
+
if opt['b']['go']:
|
338
|
+
plot_bars(data_m, opt['b'], xloc, ax)
|
339
|
+
|
340
|
+
if opt['e']['go']:
|
341
|
+
plot_errors(data, data_m, opt['e'], xloc, ax)
|
342
|
+
|
343
|
+
if opt['s']['go']:
|
344
|
+
plot_scatter(data, opt['s'], xloc, ax)
|
345
|
+
|
346
|
+
if opt['bx']['go']:
|
347
|
+
plot_boxplot(data, opt['bx'], xloc, ax)
|
348
|
+
if opt['v']['go']:
|
349
|
+
plot_violin(data, opt['v'], xloc, ax)
|
350
|
+
if opt['l']['go'] and opt['s']['go']:
|
351
|
+
plot_lines(data, opt['l'], opt['s'], ax)
|
352
|
+
|
353
|
+
return ax
|
354
|
+
|
355
|
+
# from py2ls.ips import get_color,figsets
|
356
|
+
# opt={}
|
357
|
+
# opt = {
|
358
|
+
# 'export':{'path':get_cwd()},
|
359
|
+
# 'c': get_color(5,cmap='jet',by='linspace'), # Custom colors for 3 categories
|
360
|
+
# 'b': {
|
361
|
+
# 'go': 0,
|
362
|
+
# 'x_width': 0.85,
|
363
|
+
# 'FaceAlpha': 0.7,
|
364
|
+
# 'EdgeColor':'none'
|
365
|
+
# },
|
366
|
+
# 'e': {
|
367
|
+
# 'loc':'r',
|
368
|
+
# 'go': 1,
|
369
|
+
# 'error': 'sem',
|
370
|
+
# 'Marker':'d',
|
371
|
+
# 'CapSize': 1,
|
372
|
+
# 'LineWidth':1,
|
373
|
+
# 'CapLineWidth':8,
|
374
|
+
# 'LineStyle':'--',
|
375
|
+
# 'MarkerSize':6,
|
376
|
+
# 'LineColor':'k',
|
377
|
+
# 'FaceColor':get_color(10),
|
378
|
+
# 'MarkerEdgeColor':'none',
|
379
|
+
# 'Visible':True
|
380
|
+
# },
|
381
|
+
# 's': {
|
382
|
+
# 'go': 1,
|
383
|
+
# 'x_width':0.2,
|
384
|
+
# 'loc':'random',
|
385
|
+
# 'Marker': 'o',
|
386
|
+
# # 'MarkerSize': 20,
|
387
|
+
# 'FaceAlpha': 1,
|
388
|
+
# 'FaceColor':'k',
|
389
|
+
# 'LineWidth':1
|
390
|
+
|
391
|
+
# },
|
392
|
+
# 'bx':{
|
393
|
+
# 'go':1,
|
394
|
+
# 'FaceAlpha':0.8,
|
395
|
+
# 'EdgeColor':'none',
|
396
|
+
# 'loc':'c',
|
397
|
+
# 'x_width':0.2,
|
398
|
+
# 'WhiskerLineWidth':1,
|
399
|
+
# 'MedianLineWidth':2,
|
400
|
+
# # 'MedianLineColor':'r',
|
401
|
+
# 'OutlierMarker':'+',
|
402
|
+
# 'OutlierColor':'r',
|
403
|
+
# 'CapSize':.2,
|
404
|
+
# # 'Caps':False,
|
405
|
+
# # 'CapLineColor':'r',
|
406
|
+
# # 'CapLineWidth':8,
|
407
|
+
# # 'MeanLine':True,
|
408
|
+
# # 'FaceColor':['r','g','b','m','c']
|
409
|
+
# },
|
410
|
+
# 'v':{
|
411
|
+
# 'go':0,
|
412
|
+
# 'loc':'r',
|
413
|
+
# 'x_width':0.2,
|
414
|
+
# 'FaceAlpha':0.51,
|
415
|
+
# },
|
416
|
+
# 'l':{
|
417
|
+
# 'go':1,
|
418
|
+
# 'LineColor':'k'
|
419
|
+
# }
|
420
|
+
# }
|
421
|
+
# data1 = np.random.rand(10, 5)
|
422
|
+
# data2 = np.random.rand(10, 5)
|
423
|
+
# fig, axs=plt.subplots(1,2,figsize=(6,2.5))
|
424
|
+
# catplot(data1, opt=opt,ax=axs[0])
|
425
|
+
# catplot(data2, opt=opt,ax=axs[1])
|
426
|
+
# figsets(sp=5,
|
427
|
+
# ax=axs[0],
|
428
|
+
# xticks=np.arange(1,6,1),
|
429
|
+
# xtickslabel=['glua1','glua2','a','b','c'],
|
430
|
+
# xlabel='proteins',
|
431
|
+
# xangle=90,
|
432
|
+
# yticks=np.arange(0,2,0.5),
|
433
|
+
# xlim=[0.75, 5.1],
|
434
|
+
# ticks=dict(pad=1,c='k'))
|
435
|
+
|
436
|
+
# figsave("/Users/macjianfeng/Dropbox/Downloads/",'test.pdf')
|
437
|
+
|
438
|
+
|
439
|
+
import numpy as np
|
440
|
+
import matplotlib
|
441
|
+
import matplotlib.pyplot as plt
|
442
|
+
import matplotlib.ticker as tck
|
443
|
+
import seaborn as sns
|
444
|
+
from cycler import cycler
|
445
|
+
|
446
|
+
|
447
|
+
def get_cmap():
|
448
|
+
return plt.colormaps()
|
449
|
+
|
450
|
+
def read_mplstyle(style_file):
|
451
|
+
# Load the style file
|
452
|
+
plt.style.use(style_file)
|
453
|
+
|
454
|
+
# Get the current style properties
|
455
|
+
style_dict = plt.rcParams
|
456
|
+
|
457
|
+
# Convert to dictionary
|
458
|
+
style_dict = dict(style_dict)
|
459
|
+
# Print the style dictionary
|
460
|
+
for i, j in style_dict.items():
|
461
|
+
print(f"\n{i}::::{j}")
|
462
|
+
return style_dict
|
463
|
+
# #example usage:
|
464
|
+
# style_file = "/ std-colors.mplstyle"
|
465
|
+
# style_dict = read_mplstyle(style_file)
|
466
|
+
|
467
|
+
def figsets(*args,**kwargs):
|
468
|
+
"""
|
469
|
+
usage:
|
470
|
+
figsets(ax=axs[1],
|
471
|
+
ylim=[0, 10],
|
472
|
+
spine=2,
|
473
|
+
xticklabel=['wake','sleep'],
|
474
|
+
yticksdddd=np.arange(0,316,60),
|
475
|
+
labels_loc=['right','top'],
|
476
|
+
ticks=dict(
|
477
|
+
ax='x',
|
478
|
+
which='minor',
|
479
|
+
direction='out',
|
480
|
+
width=2,
|
481
|
+
length=2,
|
482
|
+
c_tick='m',
|
483
|
+
pad=5,
|
484
|
+
label_size=11),
|
485
|
+
grid=dict(which='minor',
|
486
|
+
ax='x',
|
487
|
+
alpha=.4,
|
488
|
+
c='b',
|
489
|
+
ls='-.',
|
490
|
+
lw=0.75,
|
491
|
+
),
|
492
|
+
supertitleddddd=f'sleep druations\n(min)',
|
493
|
+
c_spine='r',
|
494
|
+
minor_ticks='xy',
|
495
|
+
style='paper',
|
496
|
+
box=['right','bottom'],
|
497
|
+
xrot=-45,
|
498
|
+
yangle=20,
|
499
|
+
font_sz = 2,
|
500
|
+
legend=dict(labels=['group_a','group_b'],
|
501
|
+
loc='upper left',
|
502
|
+
edgecolor='k',
|
503
|
+
facecolor='r',
|
504
|
+
title='title',
|
505
|
+
fancybox=1,
|
506
|
+
shadow=1,
|
507
|
+
ncols=4,
|
508
|
+
bbox_to_anchor=[-0.5,0.7],
|
509
|
+
alignment='left')
|
510
|
+
)
|
511
|
+
"""
|
512
|
+
fig = plt.gcf()
|
513
|
+
fontsize = 11
|
514
|
+
fontname = "Arial"
|
515
|
+
sns_themes = ["white", "whitegrid", "dark", "darkgrid", "ticks"]
|
516
|
+
sns_contexts = ["notebook", "talk", "poster"] # now available "paper"
|
517
|
+
scienceplots_styles = ["science","nature",
|
518
|
+
"scatter","ieee","no-latex","std-colors","high-vis","bright","dark_background","science",
|
519
|
+
"high-vis","vibrant","muted","retro","grid","high-contrast","light","cjk-tc-font","cjk-kr-font",
|
520
|
+
]
|
521
|
+
def set_step_1(ax,key, value):
|
522
|
+
if ("fo" in key) and (("size" in key) or ("sz" in key)):
|
523
|
+
fontsize=value
|
524
|
+
plt.rcParams.update({"font.size": value})
|
525
|
+
# style
|
526
|
+
if "st" in key.lower() or "th" in key.lower():
|
527
|
+
if isinstance(value, str):
|
528
|
+
if (value in plt.style.available) or (value in scienceplots_styles):
|
529
|
+
plt.style.use(value)
|
530
|
+
elif value in sns_themes:
|
531
|
+
sns.set_style(value)
|
532
|
+
elif value in sns_contexts:
|
533
|
+
sns.set_context(value)
|
534
|
+
else:
|
535
|
+
print(
|
536
|
+
f"\nWarning\n'{value}' is not a plt.style,select on below:\n{plt.style.available+sns_themes+sns_contexts+scienceplots_styles}"
|
537
|
+
)
|
538
|
+
if isinstance(value, list):
|
539
|
+
for i in value:
|
540
|
+
if (i in plt.style.available) or (i in scienceplots_styles):
|
541
|
+
plt.style.use(i)
|
542
|
+
elif i in sns_themes:
|
543
|
+
sns.set_style(i)
|
544
|
+
elif i in sns_contexts:
|
545
|
+
sns.set_context(i)
|
546
|
+
else:
|
547
|
+
print(
|
548
|
+
f"\nWarning\n'{i}' is not a plt.style,select on below:\n{plt.style.available+sns_themes+sns_contexts+scienceplots_styles}"
|
549
|
+
)
|
550
|
+
if "la" in key.lower():
|
551
|
+
if "loc" in key.lower() or "po" in key.lower():
|
552
|
+
for i in value:
|
553
|
+
if "l" in i.lower() and not 'g' in i.lower():
|
554
|
+
ax.yaxis.set_label_position("left")
|
555
|
+
if "r" in i.lower() and not 'o' in i.lower():
|
556
|
+
ax.yaxis.set_label_position("right")
|
557
|
+
if "t" in i.lower() and not 'l' in i.lower():
|
558
|
+
ax.xaxis.set_label_position("top")
|
559
|
+
if "b" in i.lower()and not 'o' in i.lower():
|
560
|
+
ax.xaxis.set_label_position("bottom")
|
561
|
+
if ("x" in key.lower()) and (
|
562
|
+
"tic" not in key.lower() and "tk" not in key.lower()
|
563
|
+
):
|
564
|
+
ax.set_xlabel(value, fontname=fontname)
|
565
|
+
if ("y" in key.lower()) and (
|
566
|
+
"tic" not in key.lower() and "tk" not in key.lower()
|
567
|
+
):
|
568
|
+
ax.set_ylabel(value, fontname=fontname)
|
569
|
+
if ("z" in key.lower()) and (
|
570
|
+
"tic" not in key.lower() and "tk" not in key.lower()
|
571
|
+
):
|
572
|
+
ax.set_zlabel(value, fontname=fontname)
|
573
|
+
if key=='xlabel' and isinstance(value,dict):
|
574
|
+
ax.set_xlabel(**value)
|
575
|
+
if key=='ylabel' and isinstance(value,dict):
|
576
|
+
ax.set_ylabel(**value)
|
577
|
+
# tick location
|
578
|
+
if "tic" in key.lower() or "tk" in key.lower():
|
579
|
+
if ("loc" in key.lower()) or ("po" in key.lower()):
|
580
|
+
if isinstance(value,str):
|
581
|
+
value=[value]
|
582
|
+
if isinstance(value, list):
|
583
|
+
loc = []
|
584
|
+
for i in value:
|
585
|
+
if ("l" in i.lower()) and ("a" not in i.lower()):
|
586
|
+
ax.yaxis.set_ticks_position("left")
|
587
|
+
if "r" in i.lower():
|
588
|
+
ax.yaxis.set_ticks_position("right")
|
589
|
+
if "t" in i.lower():
|
590
|
+
ax.xaxis.set_ticks_position("top")
|
591
|
+
if "b" in i.lower():
|
592
|
+
ax.xaxis.set_ticks_position("bottom")
|
593
|
+
if i.lower() in ["a", "both", "all", "al", ":"]:
|
594
|
+
ax.xaxis.set_ticks_position("both")
|
595
|
+
ax.yaxis.set_ticks_position("both")
|
596
|
+
if i.lower() in ["xnone",'xoff',"none"]:
|
597
|
+
ax.xaxis.set_ticks_position("none")
|
598
|
+
if i.lower() in ["ynone",'yoff','none']:
|
599
|
+
ax.yaxis.set_ticks_position("none")
|
600
|
+
# ticks / labels
|
601
|
+
elif "x" in key.lower():
|
602
|
+
if value is None:
|
603
|
+
value=[]
|
604
|
+
if "la" not in key.lower():
|
605
|
+
ax.set_xticks(value)
|
606
|
+
if "la" in key.lower():
|
607
|
+
ax.set_xticklabels(value)
|
608
|
+
elif "y" in key.lower():
|
609
|
+
if value is None:
|
610
|
+
value=[]
|
611
|
+
if "la" not in key.lower():
|
612
|
+
ax.set_yticks(value)
|
613
|
+
if "la" in key.lower():
|
614
|
+
ax.set_yticklabels(value)
|
615
|
+
elif "z" in key.lower():
|
616
|
+
if value is None:
|
617
|
+
value=[]
|
618
|
+
if "la" not in key.lower():
|
619
|
+
ax.set_zticks(value)
|
620
|
+
if "la" in key.lower():
|
621
|
+
ax.set_zticklabels(value)
|
622
|
+
# rotation
|
623
|
+
if "angle" in key.lower() or ("rot" in key.lower()):
|
624
|
+
if "x" in key.lower():
|
625
|
+
if value in [0,90,180,270]:
|
626
|
+
ax.tick_params(axis="x", rotation=value)
|
627
|
+
for tick in ax.get_xticklabels():
|
628
|
+
tick.set_horizontalalignment('center')
|
629
|
+
elif value >0:
|
630
|
+
ax.tick_params(axis="x", rotation=value)
|
631
|
+
for tick in ax.get_xticklabels():
|
632
|
+
tick.set_horizontalalignment('right')
|
633
|
+
elif value <0:
|
634
|
+
ax.tick_params(axis='x', rotation=value)
|
635
|
+
for tick in ax.get_xticklabels():
|
636
|
+
tick.set_horizontalalignment('left')
|
637
|
+
if "y" in key.lower():
|
638
|
+
ax.tick_params(axis="y", rotation=value)
|
639
|
+
for tick in ax.get_yticklabels():
|
640
|
+
tick.set_horizontalalignment('right')
|
641
|
+
|
642
|
+
if "bo" in key in key: # box setting, and ("p" in key or "l" in key):
|
643
|
+
if isinstance(value, (str, list)):
|
644
|
+
locations = []
|
645
|
+
for i in value:
|
646
|
+
if "l" in i.lower() and not 't' in i.lower():
|
647
|
+
locations.append("left")
|
648
|
+
if "r" in i.lower()and not 'o' in i.lower(): # right
|
649
|
+
locations.append("right")
|
650
|
+
if "t" in i.lower() and not 'r' in i.lower(): #top
|
651
|
+
locations.append("top")
|
652
|
+
if "b" in i.lower() and not 't' in i.lower():
|
653
|
+
locations.append("bottom")
|
654
|
+
if i.lower() in ["a", "both", "all", "al", ":"]:
|
655
|
+
[
|
656
|
+
locations.append(x)
|
657
|
+
for x in ["left", "right", "top", "bottom"]
|
658
|
+
]
|
659
|
+
for i in value:
|
660
|
+
if i.lower() in "none":
|
661
|
+
locations = []
|
662
|
+
# check spines
|
663
|
+
for loc, spi in ax.spines.items():
|
664
|
+
if loc in locations:
|
665
|
+
spi.set_position(("outward", 0))
|
666
|
+
else:
|
667
|
+
spi.set_color("none") # no spine
|
668
|
+
if 'tick' in key.lower(): # tick ticks tick_para ={}
|
669
|
+
if isinstance(value, dict):
|
670
|
+
for k, val in value.items():
|
671
|
+
if "wh" in k.lower():
|
672
|
+
ax.tick_params(
|
673
|
+
which=val
|
674
|
+
) # {'major', 'minor', 'both'}, default: 'major'
|
675
|
+
elif "dir" in k.lower():
|
676
|
+
ax.tick_params(direction=val) # {'in', 'out', 'inout'}
|
677
|
+
elif "len" in k.lower():# length
|
678
|
+
ax.tick_params(length=val)
|
679
|
+
elif ("wid" in k.lower()) or ("wd" in k.lower()): # width
|
680
|
+
ax.tick_params(width=val)
|
681
|
+
elif "ax" in k.lower(): # ax
|
682
|
+
ax.tick_params(axis=val) # {'x', 'y', 'both'}, default: 'both'
|
683
|
+
elif ("c" in k.lower()) and ("ect" not in k.lower()):
|
684
|
+
ax.tick_params(colors=val) # Tick color.
|
685
|
+
elif "pad" in k.lower() or 'space' in k.lower():
|
686
|
+
ax.tick_params(
|
687
|
+
pad=val
|
688
|
+
) # float, distance in points between tick and label
|
689
|
+
elif (
|
690
|
+
("lab" in k.lower() or 'text' in k.lower())
|
691
|
+
and ("s" in k.lower())
|
692
|
+
and ("z" in k.lower())
|
693
|
+
): # label_size
|
694
|
+
ax.tick_params(
|
695
|
+
labelsize=val
|
696
|
+
) # float, distance in points between tick and label
|
697
|
+
|
698
|
+
if "mi" in key.lower() and "tic" in key.lower():# minor_ticks
|
699
|
+
if "x" in value.lower() or "x" in key.lower():
|
700
|
+
ax.xaxis.set_minor_locator(tck.AutoMinorLocator()) # ax.minorticks_on()
|
701
|
+
if "y" in value.lower() or "y" in key.lower():
|
702
|
+
ax.yaxis.set_minor_locator(
|
703
|
+
tck.AutoMinorLocator()
|
704
|
+
) # ax.minorticks_off()
|
705
|
+
if value.lower() in ["both", ":", "all", "a", "b", "on"]:
|
706
|
+
ax.minorticks_on()
|
707
|
+
if key == "colormap" or key == "cmap":
|
708
|
+
plt.set_cmap(value)
|
709
|
+
def set_step_2(ax,key, value):
|
710
|
+
if key == "figsize":
|
711
|
+
pass
|
712
|
+
if "xlim" in key.lower():
|
713
|
+
ax.set_xlim(value)
|
714
|
+
if "ylim" in key.lower():
|
715
|
+
ax.set_ylim(value)
|
716
|
+
if "zlim" in key.lower():
|
717
|
+
ax.set_zlim(value)
|
718
|
+
if "sc" in key.lower(): #scale
|
719
|
+
if "x" in key.lower():
|
720
|
+
ax.set_xscale(value)
|
721
|
+
if "y" in key.lower():
|
722
|
+
ax.set_yscale(value)
|
723
|
+
if "z" in key.lower():
|
724
|
+
ax.set_zscale(value)
|
725
|
+
if key == "grid":
|
726
|
+
if isinstance(value, dict):
|
727
|
+
for k, val in value.items():
|
728
|
+
if "wh" in k.lower(): # which
|
729
|
+
ax.grid(
|
730
|
+
which=val
|
731
|
+
) # {'major', 'minor', 'both'}, default: 'major'
|
732
|
+
elif "ax" in k.lower(): # ax
|
733
|
+
ax.grid(axis=val) # {'x', 'y', 'both'}, default: 'both'
|
734
|
+
elif ("c" in k.lower()) and ("ect" not in k.lower()): # c: color
|
735
|
+
ax.grid(color=val) # Tick color.
|
736
|
+
elif "l" in k.lower() and ("s" in k.lower()):# ls:line stype
|
737
|
+
ax.grid(linestyle=val)
|
738
|
+
elif "l" in k.lower() and ("w" in k.lower()): # lw: line width
|
739
|
+
ax.grid(linewidth=val)
|
740
|
+
elif "al" in k.lower():# alpha:
|
741
|
+
ax.grid(alpha=val)
|
742
|
+
else:
|
743
|
+
if value == "on" or value is True:
|
744
|
+
ax.grid(visible=True)
|
745
|
+
elif value == "off" or value is False:
|
746
|
+
ax.grid(visible=False)
|
747
|
+
if "tit" in key.lower():
|
748
|
+
if "sup" in key.lower():
|
749
|
+
plt.suptitle(value)
|
750
|
+
else:
|
751
|
+
ax.set_title(value)
|
752
|
+
if key.lower() in ["spine", "adjust", "ad", "sp", "spi", "adj","spines"]:
|
753
|
+
if isinstance(value, bool) or (value in ["go", "do", "ja", "yes"]):
|
754
|
+
if value:
|
755
|
+
adjust_spines(ax) # dafault distance=2
|
756
|
+
if isinstance(value, (float, int)):
|
757
|
+
adjust_spines(ax=ax, distance=value)
|
758
|
+
if "c" in key.lower() and ("sp" in key.lower() or "ax" in key.lower()):# spine color
|
759
|
+
for loc, spi in ax.spines.items():
|
760
|
+
spi.set_color(value)
|
761
|
+
if 'leg' in key.lower(): # legend
|
762
|
+
legend_kws = kwargs.get('legend', None)
|
763
|
+
if legend_kws:
|
764
|
+
# https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.legend.html
|
765
|
+
ax.legend(**legend_kws)
|
766
|
+
|
767
|
+
for arg in args:
|
768
|
+
if isinstance(arg,matplotlib.axes._axes.Axes):
|
769
|
+
ax=arg
|
770
|
+
args=args[1:]
|
771
|
+
ax = kwargs.get('ax',plt.gca())
|
772
|
+
if 'ax' not in locals() or ax is None:
|
773
|
+
ax=plt.gca()
|
774
|
+
for key, value in kwargs.items():
|
775
|
+
set_step_1(ax, key, value)
|
776
|
+
set_step_2(ax, key, value)
|
777
|
+
for arg in args:
|
778
|
+
if isinstance(arg, dict):
|
779
|
+
for k, val in arg.items():
|
780
|
+
set_step_1(ax,k, val)
|
781
|
+
for k, val in arg.items():
|
782
|
+
set_step_2(ax,k, val)
|
783
|
+
else:
|
784
|
+
Nargin = len(args) // 2
|
785
|
+
ax.labelFontSizeMultiplier = 1
|
786
|
+
ax.titleFontSizeMultiplier = 1
|
787
|
+
ax.set_facecolor("w")
|
788
|
+
|
789
|
+
for ip in range(Nargin):
|
790
|
+
key = args[ip * 2].lower()
|
791
|
+
value = args[ip * 2 + 1]
|
792
|
+
set_step_1(ax,key, value)
|
793
|
+
for ip in range(Nargin):
|
794
|
+
key = args[ip * 2].lower()
|
795
|
+
value = args[ip * 2 + 1]
|
796
|
+
set_step_2(ax,key, value)
|
797
|
+
colors = [
|
798
|
+
"#474747",
|
799
|
+
"#FF2C00",
|
800
|
+
"#0C5DA5",
|
801
|
+
"#845B97",
|
802
|
+
"#58BBCC",
|
803
|
+
"#FF9500",
|
804
|
+
"#D57DBE",
|
805
|
+
]
|
806
|
+
matplotlib.rcParams["axes.prop_cycle"] = cycler(color=colors)
|
807
|
+
if len(fig.get_axes()) > 1:
|
808
|
+
plt.tight_layout()
|
809
|
+
plt.gcf().align_labels()
|
810
|
+
|
811
|
+
|
812
|
+
|
813
|
+
from cycler import cycler
|
814
|
+
|
815
|
+
# set up the colorlist, give the number, or the colormap's name
|
816
|
+
def get_color(n=1, cmap="auto", by="start"):
|
817
|
+
# Extract the colormap as a list
|
818
|
+
def cmap2hex(cmap_name):
|
819
|
+
cmap_ = matplotlib.pyplot.get_cmap(cmap_name)
|
820
|
+
colors = [cmap_(i) for i in range(cmap_.N)]
|
821
|
+
return [matplotlib.colors.rgb2hex(color) for color in colors]
|
822
|
+
# usage: clist = cmap2hex("viridis")
|
823
|
+
# cycle times, total number is n (defaultn=10)
|
824
|
+
def cycle2list(colorlist, n=10):
|
825
|
+
cycler_ = cycler(tmp=colorlist)
|
826
|
+
clist = []
|
827
|
+
for i, c_ in zip(range(n), cycler_()):
|
828
|
+
clist.append(c_["tmp"])
|
829
|
+
if i > n:
|
830
|
+
break
|
831
|
+
return clist
|
832
|
+
def hue2rgb(hex_colors):
|
833
|
+
def hex_to_rgb(hex_color):
|
834
|
+
"""Converts a hexadecimal color code to RGB values."""
|
835
|
+
if hex_colors.startswith("#"):
|
836
|
+
hex_color = hex_color.lstrip("#")
|
837
|
+
return tuple(int(hex_color[i : i + 2], 16) / 255.0 for i in (0, 2, 4))
|
838
|
+
if isinstance(hex_colors, str):
|
839
|
+
return hex_to_rgb(hex_colors)
|
840
|
+
elif isinstance(hex_colors, (list)):
|
841
|
+
"""Converts a list of hexadecimal color codes to a list of RGB values."""
|
842
|
+
rgb_values = [hex_to_rgb(hex_color) for hex_color in hex_colors]
|
843
|
+
return rgb_values
|
844
|
+
if "aut" in cmap:
|
845
|
+
colorlist = [
|
846
|
+
"#474747",
|
847
|
+
"#FF2C00",
|
848
|
+
"#0C5DA5",
|
849
|
+
"#845B97",
|
850
|
+
"#58BBCC",
|
851
|
+
"#FF9500",
|
852
|
+
"#D57DBE",
|
853
|
+
]
|
854
|
+
else:
|
855
|
+
colorlist = cmap2hex(cmap)
|
856
|
+
if "st" in by.lower() or "be" in by.lower():
|
857
|
+
# cycle it
|
858
|
+
clist = cycle2list(colorlist, n=n)
|
859
|
+
if "l" in by.lower() or "p" in by.lower():
|
860
|
+
clist = []
|
861
|
+
[
|
862
|
+
clist.append(colorlist[i])
|
863
|
+
for i in [int(i) for i in np.linspace(0, len(colorlist) - 1, n)]
|
864
|
+
]
|
865
|
+
|
866
|
+
return clist # a color list
|
867
|
+
# example usage: clist = get_color(4,cmap="auto", by="start") # get_color(4, cmap="hot", by="linspace")
|
868
|
+
|
869
|
+
"""
|
870
|
+
# n = 7
|
871
|
+
# clist = get_color(n, cmap="auto", by="linspace") # get_color(100)
|
872
|
+
# plt.figure(figsize=[8, 5], dpi=100)
|
873
|
+
# x = np.linspace(0, 2 * np.pi, 50) * 100
|
874
|
+
# y = np.sin(x)
|
875
|
+
# for i in range(1, n + 1):
|
876
|
+
# plt.plot(x, y + i, c=clist[i - 1], lw=5, label=str(i))
|
877
|
+
# plt.legend()
|
878
|
+
# plt.ylim(-2, 20)
|
879
|
+
# figsets(plt.gca(), {"style": "whitegrid"}) """
|
880
|
+
|
881
|
+
|
882
|
+
|
883
|
+
from scipy.signal import savgol_filter
|
884
|
+
import numpy as np
|
885
|
+
import matplotlib.pyplot as plt
|
886
|
+
|
887
|
+
def stdshade(ax=None,*args, **kwargs):
|
888
|
+
# Separate kws_line and kws_fill if necessary
|
889
|
+
kws_line = kwargs.pop('kws_line', {})
|
890
|
+
kws_fill = kwargs.pop('kws_fill', {})
|
891
|
+
|
892
|
+
# Merge kws_line and kws_fill into kwargs
|
893
|
+
kwargs.update(kws_line)
|
894
|
+
kwargs.update(kws_fill)
|
895
|
+
def str2list(str_):
|
896
|
+
l = []
|
897
|
+
[l.append(x) for x in str_]
|
898
|
+
return l
|
899
|
+
def hue2rgb(hex_colors):
|
900
|
+
def hex_to_rgb(hex_color):
|
901
|
+
"""Converts a hexadecimal color code to RGB values."""
|
902
|
+
if hex_colors.startswith("#"):
|
903
|
+
hex_color = hex_color.lstrip("#")
|
904
|
+
return tuple(int(hex_color[i : i + 2], 16) / 255.0 for i in (0, 2, 4))
|
905
|
+
if isinstance(hex_colors, str):
|
906
|
+
return hex_to_rgb(hex_colors)
|
907
|
+
elif isinstance(hex_colors, (list)):
|
908
|
+
"""Converts a list of hexadecimal color codes to a list of RGB values."""
|
909
|
+
rgb_values = [hex_to_rgb(hex_color) for hex_color in hex_colors]
|
910
|
+
return rgb_values
|
911
|
+
if (
|
912
|
+
isinstance(ax, np.ndarray)
|
913
|
+
and ax.ndim == 2
|
914
|
+
and min(ax.shape) > 1
|
915
|
+
and max(ax.shape) > 1
|
916
|
+
):
|
917
|
+
y = ax
|
918
|
+
ax = plt.gca()
|
919
|
+
if ax is None:
|
920
|
+
ax = plt.gca()
|
921
|
+
alpha = 0.5
|
922
|
+
acolor = "k"
|
923
|
+
paraStdSem = "sem"
|
924
|
+
plotStyle = "-"
|
925
|
+
plotMarker = "none"
|
926
|
+
smth = 1
|
927
|
+
l_c_one = ["r", "g", "b", "m", "c", "y", "k", "w"]
|
928
|
+
l_style2 = ["--", "-."]
|
929
|
+
l_style1 = ["-", ":"]
|
930
|
+
l_mark = ["o", "+", "*", ".", "x", "_", "|", "s", "d", "^", "v", ">", "<", "p", "h"]
|
931
|
+
# Check each argument
|
932
|
+
for iarg in range(len(args)):
|
933
|
+
if (
|
934
|
+
isinstance(args[iarg], np.ndarray)
|
935
|
+
and args[iarg].ndim == 2
|
936
|
+
and min(args[iarg].shape) > 1
|
937
|
+
and max(args[iarg].shape) > 1
|
938
|
+
):
|
939
|
+
y = args[iarg]
|
940
|
+
# Except y, continuous data is 'F'
|
941
|
+
if (isinstance(args[iarg], np.ndarray) and args[iarg].ndim == 1) or isinstance(
|
942
|
+
args[iarg], range
|
943
|
+
):
|
944
|
+
x = args[iarg]
|
945
|
+
if isinstance(x, range):
|
946
|
+
x = np.arange(start=x.start, stop=x.stop, step=x.step)
|
947
|
+
# Only one number( 0~1), 'alpha' / color
|
948
|
+
if isinstance(args[iarg], (int, float)):
|
949
|
+
if np.size(args[iarg]) == 1 and 0 <= args[iarg] <= 1:
|
950
|
+
alpha = args[iarg]
|
951
|
+
if isinstance(args[iarg], (list, tuple)) and np.size(args[iarg]) == 3:
|
952
|
+
acolor = args[iarg]
|
953
|
+
acolor = tuple(acolor) if isinstance(acolor, list) else acolor
|
954
|
+
# Color / plotStyle /
|
955
|
+
if (
|
956
|
+
isinstance(args[iarg], str)
|
957
|
+
and len(args[iarg]) == 1
|
958
|
+
and args[iarg] in l_c_one
|
959
|
+
):
|
960
|
+
acolor = args[iarg]
|
961
|
+
else:
|
962
|
+
if isinstance(args[iarg], str):
|
963
|
+
if args[iarg] in ["sem", "std"]:
|
964
|
+
paraStdSem = args[iarg]
|
965
|
+
if args[iarg].startswith("#"):
|
966
|
+
acolor=hue2rgb(args[iarg])
|
967
|
+
if str2list(args[iarg])[0] in l_c_one:
|
968
|
+
if len(args[iarg]) == 3:
|
969
|
+
k = [i for i in str2list(args[iarg]) if i in l_c_one]
|
970
|
+
if k != []:
|
971
|
+
acolor = k[0]
|
972
|
+
st = [i for i in l_style2 if i in args[iarg]]
|
973
|
+
if st != []:
|
974
|
+
plotStyle = st[0]
|
975
|
+
elif len(args[iarg]) == 2:
|
976
|
+
k = [i for i in str2list(args[iarg]) if i in l_c_one]
|
977
|
+
if k != []:
|
978
|
+
acolor = k[0]
|
979
|
+
mk = [i for i in str2list(args[iarg]) if i in l_mark]
|
980
|
+
if mk != []:
|
981
|
+
plotMarker = mk[0]
|
982
|
+
st = [i for i in l_style1 if i in args[iarg]]
|
983
|
+
if st != []:
|
984
|
+
plotStyle = st[0]
|
985
|
+
if len(args[iarg]) == 1:
|
986
|
+
k = [i for i in str2list(args[iarg]) if i in l_c_one]
|
987
|
+
if k != []:
|
988
|
+
acolor = k[0]
|
989
|
+
mk = [i for i in str2list(args[iarg]) if i in l_mark]
|
990
|
+
if mk != []:
|
991
|
+
plotMarker = mk[0]
|
992
|
+
st = [i for i in l_style1 if i in args[iarg]]
|
993
|
+
if st != []:
|
994
|
+
plotStyle = st[0]
|
995
|
+
if len(args[iarg]) == 2:
|
996
|
+
st = [i for i in l_style2 if i in args[iarg]]
|
997
|
+
if st != []:
|
998
|
+
plotStyle = st[0]
|
999
|
+
# smth
|
1000
|
+
if (
|
1001
|
+
isinstance(args[iarg], (int, float))
|
1002
|
+
and np.size(args[iarg]) == 1
|
1003
|
+
and args[iarg] >= 1
|
1004
|
+
):
|
1005
|
+
smth = args[iarg]
|
1006
|
+
smth = kwargs.get('smth', smth)
|
1007
|
+
if "x" not in locals() or x is None:
|
1008
|
+
x = np.arange(1, y.shape[1] + 1)
|
1009
|
+
elif len(x) < y.shape[1]:
|
1010
|
+
y = y[:, x]
|
1011
|
+
nRow = y.shape[0]
|
1012
|
+
nCol = y.shape[1]
|
1013
|
+
print(f"y was corrected, please confirm that {nRow} row, {nCol} col")
|
1014
|
+
else:
|
1015
|
+
x = np.arange(1, y.shape[1] + 1)
|
1016
|
+
|
1017
|
+
if x.shape[0] != 1:
|
1018
|
+
x = x.T
|
1019
|
+
yMean = np.nanmean(y, axis=0)
|
1020
|
+
if smth > 1:
|
1021
|
+
yMean = savgol_filter(np.nanmean(y, axis=0), smth, 1)
|
1022
|
+
else:
|
1023
|
+
yMean = np.nanmean(y, axis=0)
|
1024
|
+
if paraStdSem == "sem":
|
1025
|
+
if smth > 1:
|
1026
|
+
wings = savgol_filter(np.nanstd(y, axis=0) / np.sqrt(y.shape[0]), smth, 1)
|
1027
|
+
else:
|
1028
|
+
wings = np.nanstd(y, axis=0) / np.sqrt(y.shape[0])
|
1029
|
+
elif paraStdSem == "std":
|
1030
|
+
if smth > 1:
|
1031
|
+
wings = savgol_filter(np.nanstd(y, axis=0), smth, 1)
|
1032
|
+
else:
|
1033
|
+
wings = np.nanstd(y, axis=0)
|
1034
|
+
|
1035
|
+
# fill_kws = kwargs.get('fill_kws', {})
|
1036
|
+
# line_kws = kwargs.get('line_kws', {})
|
1037
|
+
|
1038
|
+
# setting form kwargs
|
1039
|
+
lw = kwargs.get('lw', 1.5)
|
1040
|
+
ls= kwargs.get('ls', plotStyle)
|
1041
|
+
marker=kwargs.get("marker",plotMarker)
|
1042
|
+
label=kwargs.get("label",None)
|
1043
|
+
label_line = kwargs.get("label_line",None)
|
1044
|
+
label_fill = kwargs.get('label_fill',None)
|
1045
|
+
alpha=kwargs.get('alpha',alpha)
|
1046
|
+
color=kwargs.get('color', acolor)
|
1047
|
+
if not label_line and label:
|
1048
|
+
label_line = label
|
1049
|
+
kwargs['lw'] = lw
|
1050
|
+
kwargs['ls'] = ls
|
1051
|
+
kwargs['label_line'] = label_line
|
1052
|
+
kwargs['label_fill'] = label_fill
|
1053
|
+
|
1054
|
+
# set kws_line
|
1055
|
+
if 'color' not in kws_line:
|
1056
|
+
kws_line['color']=color
|
1057
|
+
if 'lw' not in kws_line:
|
1058
|
+
kws_line['lw']=lw
|
1059
|
+
if 'ls' not in kws_line:
|
1060
|
+
kws_line['ls']=ls
|
1061
|
+
if 'marker' not in kws_line:
|
1062
|
+
kws_line['marker']=marker
|
1063
|
+
if 'label' not in kws_line:
|
1064
|
+
kws_line['label']=label_line
|
1065
|
+
|
1066
|
+
# set kws_line
|
1067
|
+
if 'color' not in kws_fill:
|
1068
|
+
kws_fill['color']=color
|
1069
|
+
if 'alpha' not in kws_fill:
|
1070
|
+
kws_fill['alpha']=alpha
|
1071
|
+
if 'lw' not in kws_fill:
|
1072
|
+
kws_fill['lw']=0
|
1073
|
+
if 'label' not in kws_fill:
|
1074
|
+
kws_fill['label']=label_fill
|
1075
|
+
|
1076
|
+
fill = ax.fill_between(x, yMean + wings, yMean - wings, **kws_fill)
|
1077
|
+
line = ax.plot(x, yMean, **kws_line)
|
1078
|
+
return line[0], fill
|
1079
|
+
|
1080
|
+
|
1081
|
+
"""
|
1082
|
+
########## Usage 1 ##########
|
1083
|
+
plot.stdshade(data,
|
1084
|
+
'b',
|
1085
|
+
':',
|
1086
|
+
'd',
|
1087
|
+
0.1,
|
1088
|
+
4,
|
1089
|
+
label='ddd',
|
1090
|
+
label_line='label_line',
|
1091
|
+
label_fill="label-fill")
|
1092
|
+
plt.legend()
|
1093
|
+
|
1094
|
+
########## Usage 2 ##########
|
1095
|
+
plot.stdshade(data,
|
1096
|
+
'm-',
|
1097
|
+
alpha=0.1,
|
1098
|
+
lw=2,
|
1099
|
+
ls=':',
|
1100
|
+
marker='d',
|
1101
|
+
color='b',
|
1102
|
+
smth=4,
|
1103
|
+
label='ddd',
|
1104
|
+
label_line='label_line',
|
1105
|
+
label_fill="label-fill")
|
1106
|
+
plt.legend()
|
1107
|
+
|
1108
|
+
"""
|
1109
|
+
|