py2ls 0.2.4.7__py3-none-any.whl → 0.2.4.8__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/.git/index +0 -0
- py2ls/batman.py +32 -1
- py2ls/bio.py +3 -17
- py2ls/data/usages_sns.json +2 -1
- py2ls/ips.py +1136 -691
- py2ls/ml2ls.py +1841 -390
- py2ls/plot.py +499 -214
- {py2ls-0.2.4.7.dist-info → py2ls-0.2.4.8.dist-info}/METADATA +2 -2
- {py2ls-0.2.4.7.dist-info → py2ls-0.2.4.8.dist-info}/RECORD +10 -10
- {py2ls-0.2.4.7.dist-info → py2ls-0.2.4.8.dist-info}/WHEEL +1 -1
py2ls/plot.py
CHANGED
@@ -1,25 +1,20 @@
|
|
1
|
-
import matplotlib.pyplot as plt
|
2
1
|
import numpy as np
|
3
|
-
import pandas as pd
|
4
|
-
|
5
|
-
from scipy.stats import gaussian_kde
|
6
|
-
import seaborn as sns
|
2
|
+
import pandas as pd
|
3
|
+
import matplotlib.pyplot as plt
|
7
4
|
import matplotlib
|
8
|
-
import
|
9
|
-
|
5
|
+
import seaborn as sns
|
6
|
+
import warnings
|
10
7
|
import logging
|
11
|
-
import os
|
12
|
-
import re
|
13
8
|
from typing import Union
|
14
|
-
from .ips import fsave, fload, mkdir, listdir, figsave, strcmp, unique, get_os, ssplit,flatten,plt_font
|
9
|
+
from .ips import isa, fsave, fload, mkdir, listdir, figsave, strcmp, unique, get_os, ssplit,flatten,plt_font,run_once_within
|
15
10
|
from .stats import *
|
16
|
-
|
17
|
-
|
11
|
+
import os
|
18
12
|
# Suppress INFO messages from fontTools
|
19
13
|
logging.getLogger("fontTools").setLevel(logging.ERROR)
|
20
14
|
logging.getLogger('matplotlib').setLevel(logging.ERROR)
|
21
15
|
|
22
|
-
|
16
|
+
warnings.simplefilter("ignore", category=pd.errors.SettingWithCopyWarning)
|
17
|
+
warnings.filterwarnings("ignore", category=pd.errors.PerformanceWarning)
|
23
18
|
|
24
19
|
def add_text(ax=None, height_offset=0.5, fmt=".1f", **kwargs):
|
25
20
|
"""Adds text annotations for various types of Seaborn and Matplotlib plots.
|
@@ -452,7 +447,9 @@ def catplot(data, *args, **kwargs):
|
|
452
447
|
Args:
|
453
448
|
data (array): data matrix
|
454
449
|
"""
|
455
|
-
|
450
|
+
from matplotlib.colors import to_rgba
|
451
|
+
import os
|
452
|
+
|
456
453
|
def plot_bars(data, data_m, opt_b, xloc, ax, label=None):
|
457
454
|
if "l" in opt_b["loc"]:
|
458
455
|
xloc_s = xloc - opt_b["x_dist"]
|
@@ -757,6 +754,7 @@ def catplot(data, *args, **kwargs):
|
|
757
754
|
label=label[i] if label else None,
|
758
755
|
)
|
759
756
|
else:
|
757
|
+
from scipy.stats import gaussian_kde
|
760
758
|
kde = gaussian_kde(ys, bw_method=opt_v["BandWidth"])
|
761
759
|
min_val, max_val = ys.min(), ys.max()
|
762
760
|
y_vals = np.linspace(min_val, max_val, opt_v["NumPoints"])
|
@@ -1814,53 +1812,9 @@ def read_mplstyle(style_file):
|
|
1814
1812
|
return style_dict
|
1815
1813
|
|
1816
1814
|
|
1817
|
-
def figsets(*args, **kwargs):
|
1818
|
-
"""
|
1819
|
-
usage:
|
1820
|
-
figsets(ax=axs[1],
|
1821
|
-
ylim=[0, 10],
|
1822
|
-
spine=2,
|
1823
|
-
xticklabel=['wake','sleep'],
|
1824
|
-
yticksdddd=np.arange(0,316,60),
|
1825
|
-
labels_loc=['right','top'],
|
1826
|
-
ticks=dict(
|
1827
|
-
ax='x',
|
1828
|
-
which='minor',
|
1829
|
-
direction='out',
|
1830
|
-
width=2,
|
1831
|
-
length=2,
|
1832
|
-
c_tick='m',
|
1833
|
-
pad=5,
|
1834
|
-
label_size=11),
|
1835
|
-
grid=dict(which='minor',
|
1836
|
-
ax='x',
|
1837
|
-
alpha=.4,
|
1838
|
-
c='b',
|
1839
|
-
ls='-.',
|
1840
|
-
lw=0.75,
|
1841
|
-
),
|
1842
|
-
supertitleddddd=f'sleep druations\n(min)',
|
1843
|
-
c_spine='r',
|
1844
|
-
minor_ticks='xy',
|
1845
|
-
style='paper',
|
1846
|
-
box=['right','bottom'],
|
1847
|
-
xrot=-45,
|
1848
|
-
yangle=20,
|
1849
|
-
font_sz = 12,
|
1850
|
-
legend=dict(labels=['group_a','group_b'],
|
1851
|
-
loc='upper left',
|
1852
|
-
edgecolor='k',
|
1853
|
-
facecolor='r',
|
1854
|
-
title='title',
|
1855
|
-
fancybox=1,
|
1856
|
-
shadow=1,
|
1857
|
-
ncols=4,
|
1858
|
-
bbox_to_anchor=[-0.5,0.7],
|
1859
|
-
alignment='left')
|
1860
|
-
)
|
1861
|
-
"""
|
1815
|
+
def figsets(*args, **kwargs):
|
1862
1816
|
import matplotlib
|
1863
|
-
|
1817
|
+
from cycler import cycler
|
1864
1818
|
matplotlib.rc("text", usetex=False)
|
1865
1819
|
|
1866
1820
|
fig = plt.gcf()
|
@@ -1897,7 +1851,16 @@ def figsets(*args, **kwargs):
|
|
1897
1851
|
nonlocal fontsize, fontname
|
1898
1852
|
if ("fo" in key) and (("size" in key) or ("sz" in key)):
|
1899
1853
|
fontsize = value
|
1900
|
-
plt.rcParams.update({"font.size": fontsize
|
1854
|
+
plt.rcParams.update({"font.size": fontsize,
|
1855
|
+
"figure.titlesize":fontsize,
|
1856
|
+
"axes.titlesize":fontsize,
|
1857
|
+
"axes.labelsize": fontsize,
|
1858
|
+
"xtick.labelsize": fontsize,
|
1859
|
+
"ytick.labelsize": fontsize,
|
1860
|
+
"legend.fontsize": fontsize,
|
1861
|
+
"legend.title_fontsize":fontsize
|
1862
|
+
})
|
1863
|
+
|
1901
1864
|
# Customize tick labels
|
1902
1865
|
ax.tick_params(axis='both', which='major', labelsize=fontsize)
|
1903
1866
|
for label in ax.get_xticklabels() + ax.get_yticklabels():
|
@@ -2146,6 +2109,7 @@ def figsets(*args, **kwargs):
|
|
2146
2109
|
# ])
|
2147
2110
|
|
2148
2111
|
if "mi" in key.lower() and "tic" in key.lower(): # minor_ticks
|
2112
|
+
import matplotlib.ticker as tck
|
2149
2113
|
if "x" in value.lower() or "x" in key.lower():
|
2150
2114
|
ax.xaxis.set_minor_locator(tck.AutoMinorLocator()) # ax.minorticks_on()
|
2151
2115
|
if "y" in value.lower() or "y" in key.lower():
|
@@ -2255,24 +2219,77 @@ def figsets(*args, **kwargs):
|
|
2255
2219
|
key = args[ip * 2].lower()
|
2256
2220
|
value = args[ip * 2 + 1]
|
2257
2221
|
set_step_2(ax, key, value)
|
2258
|
-
|
2259
|
-
|
2260
|
-
"#FF2C00",
|
2261
|
-
"#0C5DA5",
|
2262
|
-
"#845B97",
|
2263
|
-
"#58BBCC",
|
2264
|
-
"#FF9500",
|
2265
|
-
"#D57DBE",
|
2266
|
-
]
|
2222
|
+
|
2223
|
+
colors = get_color(8)
|
2267
2224
|
matplotlib.rcParams["axes.prop_cycle"] = cycler(color=colors)
|
2268
2225
|
if len(fig.get_axes()) > 1:
|
2269
2226
|
plt.tight_layout()
|
2270
|
-
plt.gcf().align_labels()
|
2271
2227
|
|
2228
|
+
def split_legend(ax, n=2, loc=None, title=None, bbox=None,ncol=1, **kwargs):
|
2229
|
+
"""
|
2230
|
+
split_legend(
|
2231
|
+
ax,
|
2232
|
+
n=2,
|
2233
|
+
loc=["upper left", "lower right"],
|
2234
|
+
labelcolor="k",
|
2235
|
+
fontsize=6,
|
2236
|
+
)
|
2237
|
+
"""
|
2238
|
+
# Retrieve all lines and labels from the axis
|
2239
|
+
handles, labels = ax.get_legend_handles_labels()
|
2240
|
+
num_labels = len(labels)
|
2241
|
+
|
2242
|
+
# Calculate the number of labels per legend part
|
2243
|
+
labels_per_part = (num_labels + n - 1) // n # Round up
|
2244
|
+
# Create a list to hold each legend object
|
2245
|
+
legends = []
|
2246
|
+
|
2247
|
+
# Default locations and titles if not specified
|
2248
|
+
if loc is None:
|
2249
|
+
loc = ['best'] * n
|
2250
|
+
if title is None:
|
2251
|
+
title = [None] * n
|
2252
|
+
if bbox is None:
|
2253
|
+
bbox = [None] * n
|
2254
|
+
|
2255
|
+
# Loop to create each split legend
|
2256
|
+
for i in range(n):
|
2257
|
+
# Calculate the range of labels for this part
|
2258
|
+
start_idx = i * labels_per_part
|
2259
|
+
end_idx = min(start_idx + labels_per_part, num_labels)
|
2260
|
+
|
2261
|
+
# Skip if no labels in this range
|
2262
|
+
if start_idx >= end_idx:
|
2263
|
+
break
|
2272
2264
|
|
2273
|
-
|
2274
|
-
|
2265
|
+
# Subset handles and labels
|
2266
|
+
part_handles = handles[start_idx:end_idx]
|
2267
|
+
part_labels = labels[start_idx:end_idx]
|
2268
|
+
|
2269
|
+
# Create the legend for this part
|
2270
|
+
legend = ax.legend(handles=part_handles,
|
2271
|
+
labels=part_labels,
|
2272
|
+
loc=loc[i],
|
2273
|
+
title=title[i],
|
2274
|
+
ncol=ncol,
|
2275
|
+
bbox_to_anchor=bbox[i],
|
2276
|
+
**kwargs)
|
2277
|
+
|
2278
|
+
# Add the legend to the axis and save it to the list
|
2279
|
+
ax.add_artist(legend) if i !=(n-1) else None # the lastone will be added automaticaly
|
2280
|
+
legends.append(legend)
|
2281
|
+
return legends
|
2275
2282
|
|
2283
|
+
def get_colors(
|
2284
|
+
n: int = 1,
|
2285
|
+
cmap: str = "auto",
|
2286
|
+
by: str = "start",
|
2287
|
+
alpha: float = 1.0,
|
2288
|
+
output: str = "hue",
|
2289
|
+
*args,
|
2290
|
+
**kwargs,
|
2291
|
+
):
|
2292
|
+
return get_color(n,cmap,alpha,output,*args,**kwargs)
|
2276
2293
|
def get_color(
|
2277
2294
|
n: int = 1,
|
2278
2295
|
cmap: str = "auto",
|
@@ -2282,6 +2299,7 @@ def get_color(
|
|
2282
2299
|
*args,
|
2283
2300
|
**kwargs,
|
2284
2301
|
):
|
2302
|
+
from cycler import cycler
|
2285
2303
|
def cmap2hex(cmap_name):
|
2286
2304
|
cmap_ = matplotlib.pyplot.get_cmap(cmap_name)
|
2287
2305
|
colors = [cmap_(i) for i in range(cmap_.N)]
|
@@ -2329,61 +2347,86 @@ def get_color(
|
|
2329
2347
|
return "#{:02X}{:02X}{:02X}{:02X}".format(r, g, b, a)
|
2330
2348
|
else:
|
2331
2349
|
return "#{:02X}{:02X}{:02X}".format(r, g, b)
|
2332
|
-
|
2350
|
+
|
2351
|
+
# sc.pl.palettes.default_20
|
2352
|
+
cmap_20= ['#1f77b4','#ff7f0e','#279e68','#d62728','#aa40fc','#8c564b','#e377c2','#b5bd61',
|
2353
|
+
'#17becf','#aec7e8','#ffbb78','#98df8a','#ff9896','#c5b0d5','#c49c94','#f7b6d2',
|
2354
|
+
'#dbdb8d','#9edae5','#ad494a','#8c6d31']
|
2355
|
+
# sc.pl.palettes.zeileis_28
|
2356
|
+
cmap_28 = ["#023fa5","#7d87b9","#bec1d4","#d6bcc0","#bb7784","#8e063b","#4a6fe3","#8595e1",
|
2357
|
+
"#b5bbe3","#e6afb9","#e07b91","#d33f6a","#11c638","#8dd593","#c6dec7","#ead3c6",
|
2358
|
+
"#f0b98d","#ef9708","#0fcfc0","#9cded6","#d5eae7","#f3e1eb","#f6c4e1","#f79cd4",
|
2359
|
+
"#7f7f7f","#c7c7c7","#1CE6FF","#336600"]
|
2333
2360
|
if cmap == "gray":
|
2334
2361
|
cmap = "grey"
|
2362
|
+
elif cmap=="20":
|
2363
|
+
cmap=cmap_20
|
2364
|
+
elif cmap=="28":
|
2365
|
+
cmap=cmap_28
|
2335
2366
|
# Determine color list based on cmap parameter
|
2336
|
-
if
|
2337
|
-
if
|
2338
|
-
|
2339
|
-
|
2340
|
-
|
2341
|
-
|
2342
|
-
|
2343
|
-
|
2344
|
-
|
2345
|
-
|
2346
|
-
|
2347
|
-
|
2348
|
-
|
2349
|
-
|
2350
|
-
|
2351
|
-
|
2352
|
-
|
2353
|
-
|
2354
|
-
|
2355
|
-
|
2356
|
-
|
2357
|
-
|
2358
|
-
|
2359
|
-
|
2360
|
-
|
2367
|
+
if isinstance(cmap,str):
|
2368
|
+
if "aut" in cmap:
|
2369
|
+
if n == 1:
|
2370
|
+
colorlist = ["#3A4453"]
|
2371
|
+
elif n == 2:
|
2372
|
+
colorlist = ["#3A4453", "#FF2C00"]
|
2373
|
+
elif n == 3:
|
2374
|
+
colorlist = ["#66c2a5","#fc8d62","#8da0cb"]
|
2375
|
+
elif n == 4:
|
2376
|
+
colorlist = ["#FF2C00","#087cf7", "#FBAF63", "#3C898A"]
|
2377
|
+
elif n == 5:
|
2378
|
+
colorlist = ["#FF2C00","#459AA9", "#B25E9D", "#4B8C3B","#EF8632"]
|
2379
|
+
elif n == 6:
|
2380
|
+
colorlist = ["#FF2C00","#91bfdb", "#B25E9D", "#4B8C3B","#EF8632", "#24578E"]
|
2381
|
+
elif n==7:
|
2382
|
+
colorlist = ["#7F7F7F", "#459AA9", "#B25E9D", "#4B8C3B","#EF8632", "#24578E" "#FF2C00"]
|
2383
|
+
elif n==8:
|
2384
|
+
# colorlist = ['#1f77b4','#ff7f0e','#367B7F','#51B34F','#d62728','#aa40fc','#e377c2','#17becf']
|
2385
|
+
# colorlist = ["#367C7E","#51B34F","#881A11","#E9374C","#EF893C","#010072","#385DCB","#EA43E3"]
|
2386
|
+
colorlist = ["#78BFDA","#D52E6F","#F7D648","#A52D28","#6B9F41","#E18330","#E18B9D","#3C88CC"]
|
2387
|
+
elif n==9:
|
2388
|
+
colorlist = ['#1f77b4','#ff7f0e','#367B7F','#ff9896','#d62728','#aa40fc','#e377c2','#51B34F','#17becf']
|
2389
|
+
elif n==10:
|
2390
|
+
colorlist = ['#1f77b4','#ff7f0e','#367B7F','#ff9896','#51B34F','#d62728''#aa40fc','#e377c2','#375FD2','#17becf']
|
2391
|
+
elif 10<n<=20:
|
2392
|
+
colorlist = cmap_20
|
2393
|
+
else:
|
2394
|
+
colorlist = cmap_28
|
2395
|
+
by = "start"
|
2396
|
+
elif any(["cub" in cmap.lower(), "sns" in cmap.lower()]):
|
2397
|
+
if kwargs:
|
2398
|
+
colorlist = sns.cubehelix_palette(n, **kwargs)
|
2399
|
+
else:
|
2400
|
+
colorlist = sns.cubehelix_palette(
|
2401
|
+
n, start=0.5, rot=-0.75, light=0.85, dark=0.15, as_cmap=False
|
2402
|
+
)
|
2403
|
+
colorlist = [matplotlib.colors.rgb2hex(color) for color in colorlist]
|
2404
|
+
elif any(["hls" in cmap.lower(), "hsl" in cmap.lower()]):
|
2405
|
+
if kwargs:
|
2406
|
+
colorlist = sns.hls_palette(n, **kwargs)
|
2407
|
+
else:
|
2408
|
+
colorlist = sns.hls_palette(n)
|
2409
|
+
colorlist = [matplotlib.colors.rgb2hex(color) for color in colorlist]
|
2410
|
+
elif any(["col" in cmap.lower(), "pal" in cmap.lower()]):
|
2411
|
+
palette, desat, as_cmap = None, None, False
|
2412
|
+
if kwargs:
|
2413
|
+
for k, v in kwargs.items():
|
2414
|
+
if "p" in k:
|
2415
|
+
palette = v
|
2416
|
+
elif "d" in k:
|
2417
|
+
desat = v
|
2418
|
+
elif "a" in k:
|
2419
|
+
as_cmap = v
|
2420
|
+
colorlist = sns.color_palette(
|
2421
|
+
palette=palette, n_colors=n, desat=desat, as_cmap=as_cmap
|
2361
2422
|
)
|
2362
|
-
|
2363
|
-
elif any(["hls" in cmap.lower(), "hsl" in cmap.lower()]):
|
2364
|
-
if kwargs:
|
2365
|
-
colorlist = sns.hls_palette(n, **kwargs)
|
2423
|
+
colorlist = [matplotlib.colors.rgb2hex(color) for color in colorlist]
|
2366
2424
|
else:
|
2367
|
-
|
2368
|
-
|
2369
|
-
|
2370
|
-
|
2371
|
-
|
2372
|
-
for k, v in kwargs.items():
|
2373
|
-
if "p" in k:
|
2374
|
-
palette = v
|
2375
|
-
elif "d" in k:
|
2376
|
-
desat = v
|
2377
|
-
elif "a" in k:
|
2378
|
-
as_cmap = v
|
2379
|
-
colorlist = sns.color_palette(
|
2380
|
-
palette=palette, n_colors=n, desat=desat, as_cmap=as_cmap
|
2381
|
-
)
|
2382
|
-
colorlist = [matplotlib.colors.rgb2hex(color) for color in colorlist]
|
2383
|
-
else:
|
2384
|
-
if by == "start":
|
2385
|
-
by = "linspace"
|
2386
|
-
colorlist = cmap2hex(cmap)
|
2425
|
+
if by == "start":
|
2426
|
+
by = "linspace"
|
2427
|
+
colorlist = cmap2hex(cmap)
|
2428
|
+
elif isinstance(cmap, list):
|
2429
|
+
colorlist=cmap
|
2387
2430
|
|
2388
2431
|
# Determine method for generating color list
|
2389
2432
|
if "st" in by.lower() or "be" in by.lower():
|
@@ -2403,35 +2446,15 @@ def get_color(
|
|
2403
2446
|
return hue_list
|
2404
2447
|
else:
|
2405
2448
|
raise ValueError("Invalid output type. Choose 'rgb' or 'hue'.")
|
2406
|
-
|
2407
|
-
# # Example usage
|
2408
|
-
# colors = get_color(n=5, cmap="viridis", by="linear", alpha=0.5,output='rgb')
|
2409
|
-
# print(colors)
|
2410
|
-
|
2411
|
-
|
2412
|
-
"""
|
2413
|
-
# n = 7
|
2414
|
-
# clist = get_color(n, cmap="auto", by="linspace") # get_color(100)
|
2415
|
-
# plt.figure(figsize=[8, 5], dpi=100)
|
2416
|
-
# x = np.linspace(0, 2 * np.pi, 50) * 100
|
2417
|
-
# y = np.sin(x)
|
2418
|
-
# for i in range(1, n + 1):
|
2419
|
-
# plt.plot(x, y + i, c=clist[i - 1], lw=5, label=str(i))
|
2420
|
-
# plt.legend()
|
2421
|
-
# plt.ylim(-2, 20)
|
2422
|
-
# figsets(plt.gca(), {"style": "whitegrid"}) """
|
2423
|
-
|
2424
|
-
|
2425
|
-
from scipy.signal import savgol_filter
|
2426
|
-
import numpy as np
|
2427
|
-
import matplotlib.pyplot as plt
|
2428
|
-
|
2449
|
+
|
2429
2450
|
|
2430
2451
|
def stdshade(ax=None, *args, **kwargs):
|
2431
2452
|
"""
|
2432
2453
|
usage:
|
2433
2454
|
plot.stdshade(data_array, c=clist[1], lw=2, ls="-.", alpha=0.2)
|
2434
2455
|
"""
|
2456
|
+
from scipy.signal import savgol_filter
|
2457
|
+
|
2435
2458
|
# Separate kws_line and kws_fill if necessary
|
2436
2459
|
kws_line = kwargs.pop("kws_line", {})
|
2437
2460
|
kws_fill = kwargs.pop("kws_fill", {})
|
@@ -2937,6 +2960,7 @@ def thumbnail(dir_img_list: list, figsize=(10, 10), dpi=100, show=False, verbose
|
|
2937
2960
|
|
2938
2961
|
|
2939
2962
|
def get_params_from_func_usage(function_signature):
|
2963
|
+
import re
|
2940
2964
|
# Regular expression to match parameter names, ignoring '*' and '**kwargs'
|
2941
2965
|
keys_pattern = r"(?<!\*\*)\b(\w+)="
|
2942
2966
|
# Find all matches
|
@@ -2963,7 +2987,7 @@ def plotxy(
|
|
2963
2987
|
x=None,
|
2964
2988
|
y=None,
|
2965
2989
|
ax=None,
|
2966
|
-
kind: Union[str, list] =
|
2990
|
+
kind: Union[str, list] = 'scatter', # Specify the kind of plot
|
2967
2991
|
verbose=False,
|
2968
2992
|
**kwargs,
|
2969
2993
|
):
|
@@ -2986,14 +3010,15 @@ def plotxy(
|
|
2986
3010
|
"""
|
2987
3011
|
# Check for valid plot kind
|
2988
3012
|
# Default arguments for various plot types
|
2989
|
-
|
2990
|
-
|
2991
|
-
)
|
2992
|
-
|
2993
|
-
|
2994
|
-
|
2995
|
-
|
2996
|
-
|
3013
|
+
from pathlib import Path
|
3014
|
+
# Get the current script's directory as a Path object
|
3015
|
+
current_directory = Path(__file__).resolve().parent
|
3016
|
+
|
3017
|
+
if not 'default_settings' in locals():
|
3018
|
+
default_settings = fload(current_directory / 'data' / 'usages_sns.json')
|
3019
|
+
if not 'sns_info' in locals():
|
3020
|
+
sns_info = pd.DataFrame(fload(current_directory / 'data' / 'sns_info.json'))
|
3021
|
+
|
2997
3022
|
valid_kinds = list(default_settings.keys())
|
2998
3023
|
print(valid_kinds)
|
2999
3024
|
if kind is not None:
|
@@ -3002,6 +3027,7 @@ def plotxy(
|
|
3002
3027
|
kind = [strcmp(i, valid_kinds)[0] for i in kind]
|
3003
3028
|
else:
|
3004
3029
|
verbose = True
|
3030
|
+
|
3005
3031
|
if verbose:
|
3006
3032
|
if kind is not None:
|
3007
3033
|
for k in kind:
|
@@ -3013,7 +3039,7 @@ def plotxy(
|
|
3013
3039
|
.tolist()[0]
|
3014
3040
|
)
|
3015
3041
|
print()
|
3016
|
-
usage_str = """
|
3042
|
+
usage_str = """plotxy(data=ranked_genes,
|
3017
3043
|
x="log2(fold_change)",
|
3018
3044
|
y="-log10(p-value)",
|
3019
3045
|
palette=get_color(3, cmap="coolwarm"),
|
@@ -3037,24 +3063,15 @@ def plotxy(
|
|
3037
3063
|
kws_add_text = v_arg
|
3038
3064
|
kwargs.pop(k_arg, None)
|
3039
3065
|
break
|
3040
|
-
|
3066
|
+
zorder=0
|
3041
3067
|
for k in kind:
|
3068
|
+
zorder+=1
|
3042
3069
|
# indicate 'col' features
|
3043
3070
|
col = kwargs.get("col", None)
|
3044
|
-
sns_with_col = [
|
3045
|
-
"catplot",
|
3046
|
-
"histplot",
|
3047
|
-
"relplot",
|
3048
|
-
"lmplot",
|
3049
|
-
"pairplot",
|
3050
|
-
"displot",
|
3051
|
-
"kdeplot",
|
3052
|
-
]
|
3071
|
+
sns_with_col = ["catplot","histplot","relplot","lmplot","pairplot","displot","kdeplot"]
|
3053
3072
|
if col is not None:
|
3054
3073
|
if not k in sns_with_col:
|
3055
|
-
print(
|
3056
|
-
f"tips:\n'{k}' has no 'col' param, you could try with {sns_with_col}"
|
3057
|
-
)
|
3074
|
+
print(f"tips:\n'{k}' has no 'col' param, you could try with {sns_with_col}")
|
3058
3075
|
# (1) return FcetGrid
|
3059
3076
|
if k == "jointplot":
|
3060
3077
|
kws_joint = kwargs.pop("kws_joint", kwargs)
|
@@ -3073,7 +3090,6 @@ def plotxy(
|
|
3073
3090
|
# (2) return axis
|
3074
3091
|
if ax is None:
|
3075
3092
|
ax = plt.gca()
|
3076
|
-
|
3077
3093
|
if k == "catplot":
|
3078
3094
|
kws_cat = kwargs.pop("kws_cat", kwargs)
|
3079
3095
|
g = catplot(data=data, x=x, y=y, ax=ax, **kws_cat)
|
@@ -3082,88 +3098,86 @@ def plotxy(
|
|
3082
3098
|
ax = stdshade(ax=ax, **kwargs)
|
3083
3099
|
elif k == "scatterplot":
|
3084
3100
|
kws_scatter = kwargs.pop("kws_scatter", kwargs)
|
3101
|
+
kws_scatter={k: v for k, v in kws_scatter.items() if not k.startswith("kws_")}
|
3085
3102
|
hue = kwargs.pop("hue", None)
|
3086
|
-
|
3087
|
-
"
|
3088
|
-
|
3089
|
-
|
3090
|
-
if hue is not None
|
3091
|
-
else sns.color_palette("tab20")
|
3092
|
-
),
|
3093
|
-
)
|
3103
|
+
if isinstance(kws_scatter, dict): # Check if kws_scatter is a dictionary
|
3104
|
+
kws_scatter.pop("hue", None) # Safely remove 'hue' if it exists
|
3105
|
+
|
3106
|
+
palette = kws_scatter.pop("palette",get_color(data[hue].nunique()) if hue is not None else None)
|
3094
3107
|
s = kws_scatter.pop("s", 10)
|
3095
3108
|
alpha = kws_scatter.pop("alpha", 0.7)
|
3096
|
-
ax = sns.scatterplot(
|
3097
|
-
ax=ax,
|
3098
|
-
data=data,
|
3099
|
-
x=x,
|
3100
|
-
y=y,
|
3101
|
-
hue=hue,
|
3102
|
-
palette=palette,
|
3103
|
-
s=s,
|
3104
|
-
alpha=alpha,
|
3105
|
-
**kws_scatter,
|
3106
|
-
)
|
3109
|
+
ax = sns.scatterplot(ax=ax,data=data,x=x,y=y,hue=hue,palette=palette,s=s,alpha=alpha,zorder=zorder,**kws_scatter)
|
3107
3110
|
elif k == "histplot":
|
3108
3111
|
kws_hist = kwargs.pop("kws_hist", kwargs)
|
3109
|
-
|
3112
|
+
kws_hist={k: v for k, v in kws_hist.items() if not k.startswith("kws_")}
|
3113
|
+
ax = sns.histplot(data=data, x=x, ax=ax,zorder=zorder, **kws_hist)
|
3110
3114
|
elif k == "kdeplot":
|
3111
3115
|
kws_kde = kwargs.pop("kws_kde", kwargs)
|
3112
|
-
|
3116
|
+
kws_kde={k: v for k, v in kws_kde.items() if not k.startswith("kws_")}
|
3117
|
+
ax = sns.kdeplot(data=data, x=x, ax=ax,zorder=zorder, **kws_kde)
|
3113
3118
|
elif k == "ecdfplot":
|
3114
3119
|
kws_ecdf = kwargs.pop("kws_ecdf", kwargs)
|
3115
|
-
|
3120
|
+
kws_ecdf={k: v for k, v in kws_ecdf.items() if not k.startswith("kws_")}
|
3121
|
+
ax = sns.ecdfplot(data=data, x=x, ax=ax,zorder=zorder, **kws_ecdf)
|
3116
3122
|
elif k == "rugplot":
|
3117
3123
|
kws_rug = kwargs.pop("kws_rug", kwargs)
|
3118
|
-
|
3119
|
-
ax = sns.rugplot(data=data, x=x, ax=ax, **kws_rug)
|
3124
|
+
kws_rug={k: v for k, v in kws_rug.items() if not k.startswith("kws_")}
|
3125
|
+
ax = sns.rugplot(data=data, x=x, ax=ax,zorder=zorder, **kws_rug)
|
3120
3126
|
elif k == "stripplot":
|
3121
3127
|
kws_strip = kwargs.pop("kws_strip", kwargs)
|
3128
|
+
kws_strip={k: v for k, v in kws_strip.items() if not k.startswith("kws_")}
|
3122
3129
|
dodge = kws_strip.pop("dodge", True)
|
3123
|
-
ax = sns.stripplot(data=data, x=x, y=y, ax=ax, dodge=dodge, **kws_strip)
|
3130
|
+
ax = sns.stripplot(data=data, x=x, y=y, ax=ax,zorder=zorder, dodge=dodge, **kws_strip)
|
3124
3131
|
elif k == "swarmplot":
|
3125
3132
|
kws_swarm = kwargs.pop("kws_swarm", kwargs)
|
3126
|
-
|
3133
|
+
kws_swarm={k: v for k, v in kws_swarm.items() if not k.startswith("kws_")}
|
3134
|
+
ax = sns.swarmplot(data=data, x=x, y=y, ax=ax,zorder=zorder, **kws_swarm)
|
3127
3135
|
elif k == "boxplot":
|
3128
3136
|
kws_box = kwargs.pop("kws_box", kwargs)
|
3129
|
-
|
3137
|
+
kws_box={k: v for k, v in kws_box.items() if not k.startswith("kws_")}
|
3138
|
+
ax = sns.boxplot(data=data, x=x, y=y, ax=ax,zorder=zorder, **kws_box)
|
3130
3139
|
elif k == "violinplot":
|
3131
3140
|
kws_violin = kwargs.pop("kws_violin", kwargs)
|
3132
|
-
|
3141
|
+
kws_violin={k: v for k, v in kws_violin.items() if not k.startswith("kws_")}
|
3142
|
+
ax = sns.violinplot(data=data, x=x, y=y, ax=ax,zorder=zorder, **kws_violin)
|
3133
3143
|
elif k == "boxenplot":
|
3134
3144
|
kws_boxen = kwargs.pop("kws_boxen", kwargs)
|
3135
|
-
|
3145
|
+
kws_boxen={k: v for k, v in kws_boxen.items() if not k.startswith("kws_")}
|
3146
|
+
ax = sns.boxenplot(data=data, x=x, y=y, ax=ax,zorder=zorder, **kws_boxen)
|
3136
3147
|
elif k == "pointplot":
|
3137
3148
|
kws_point = kwargs.pop("kws_point", kwargs)
|
3138
|
-
|
3149
|
+
kws_point={k: v for k, v in kws_point.items() if not k.startswith("kws_")}
|
3150
|
+
ax = sns.pointplot(data=data, x=x, y=y, ax=ax,zorder=zorder, **kws_point)
|
3139
3151
|
elif k == "barplot":
|
3140
3152
|
kws_bar = kwargs.pop("kws_bar", kwargs)
|
3141
|
-
|
3153
|
+
kws_bar={k: v for k, v in kws_bar.items() if not k.startswith("kws_")}
|
3154
|
+
ax = sns.barplot(data=data, x=x, y=y, ax=ax,zorder=zorder, **kws_bar)
|
3142
3155
|
elif k == "countplot":
|
3143
3156
|
kws_count = kwargs.pop("kws_count", kwargs)
|
3157
|
+
kws_count={k: v for k, v in kws_count.items() if not k.startswith("kws_")}
|
3144
3158
|
if not kws_count.get("hue",None):
|
3145
3159
|
kws_count.pop("palette",None)
|
3146
|
-
ax = sns.countplot(data=data, x=x,y=y, ax=ax, **kws_count)
|
3160
|
+
ax = sns.countplot(data=data, x=x,y=y, ax=ax,zorder=zorder, **kws_count)
|
3147
3161
|
elif k == "regplot":
|
3148
3162
|
kws_reg = kwargs.pop("kws_reg", kwargs)
|
3149
|
-
|
3163
|
+
kws_reg={k: v for k, v in kws_reg.items() if not k.startswith("kws_")}
|
3164
|
+
ax = sns.regplot(data=data, x=x, y=y, ax=ax,zorder=zorder, **kws_reg)
|
3150
3165
|
elif k == "residplot":
|
3151
3166
|
kws_resid = kwargs.pop("kws_resid", kwargs)
|
3152
|
-
|
3167
|
+
kws_resid={k: v for k, v in kws_resid.items() if not k.startswith("kws_")}
|
3168
|
+
ax = sns.residplot(data=data, x=x, y=y, lowess=True,zorder=zorder, ax=ax, **kws_resid)
|
3153
3169
|
elif k == "lineplot":
|
3154
3170
|
kws_line = kwargs.pop("kws_line", kwargs)
|
3155
|
-
|
3171
|
+
kws_line={k: v for k, v in kws_line.items() if not k.startswith("kws_")}
|
3172
|
+
ax = sns.lineplot(ax=ax, data=data, x=x, y=y,zorder=zorder, **kws_line)
|
3156
3173
|
|
3157
3174
|
figsets(ax=ax, **kws_figsets)
|
3158
|
-
|
3159
|
-
|
3160
|
-
|
3161
|
-
|
3162
|
-
|
3163
|
-
"=>\t",
|
3164
|
-
sns_info[sns_info["Functions"].str.contains(k)].iloc[:, -1].tolist()[0],
|
3165
|
-
)
|
3166
|
-
print()
|
3175
|
+
if kws_add_text:
|
3176
|
+
add_text(ax=ax, **kws_add_text) if kws_add_text else None
|
3177
|
+
if run_once_within(60):
|
3178
|
+
print(f"\n{k}⤵ ")
|
3179
|
+
print(default_settings[k])
|
3180
|
+
# print("=>\t",sns_info[sns_info["Functions"].str.contains(k)].iloc[:, -1].tolist()[0],"\n")
|
3167
3181
|
if "g" in locals():
|
3168
3182
|
if ax is not None:
|
3169
3183
|
return g, ax
|
@@ -3815,4 +3829,275 @@ def venn(
|
|
3815
3829
|
patch.set_alpha(alpha)
|
3816
3830
|
if 'none' in edgecolor or 0 in linewidth:
|
3817
3831
|
patch.set_edgecolor("none")
|
3832
|
+
return ax
|
3833
|
+
|
3834
|
+
#! subplots, support automatic extend new axis
|
3835
|
+
def subplot(rows:int=2,
|
3836
|
+
cols:int=2,
|
3837
|
+
figsize:Union[tuple,list]=[8, 8],
|
3838
|
+
sharex=False,
|
3839
|
+
sharey=False,
|
3840
|
+
**kwargs):
|
3841
|
+
"""
|
3842
|
+
nexttile = subplot(
|
3843
|
+
8,
|
3844
|
+
2,
|
3845
|
+
figsize=(8, 9),
|
3846
|
+
sharey=True,
|
3847
|
+
sharex=True,
|
3848
|
+
)
|
3849
|
+
|
3850
|
+
for i in range(8):
|
3851
|
+
ax = nexttile()
|
3852
|
+
x = np.linspace(0, 10, 100) + i
|
3853
|
+
ax.plot(x, np.sin(x + i) + i, label=f"Plot {i + 1}")
|
3854
|
+
ax.legend()
|
3855
|
+
ax.set_title(f"Tile {i + 1}")
|
3856
|
+
ax.set_ylabel(f"Tile {i + 1}")
|
3857
|
+
ax.set_xlabel(f"Tile {i + 1}")
|
3858
|
+
"""
|
3859
|
+
from matplotlib.gridspec import GridSpec
|
3860
|
+
if run_once_within():
|
3861
|
+
print(f"usage:\n\tnexttile = subplot(2, 2, figsize=(5, 5), sharex=True, sharey=True)\n\tax = nexttile()")
|
3862
|
+
fig = plt.figure(figsize=figsize)
|
3863
|
+
grid_spec = GridSpec(rows, cols, figure=fig)
|
3864
|
+
occupied = set()
|
3865
|
+
row_first_axes = [None] * rows # Track the first axis in each row (for sharey)
|
3866
|
+
col_first_axes = [None] * cols # Track the first axis in each column (for sharex)
|
3867
|
+
|
3868
|
+
def expand_ax():
|
3869
|
+
nonlocal rows, grid_spec
|
3870
|
+
rows += 1 # Expands by adding a row
|
3871
|
+
grid_spec = GridSpec(rows, cols, figure=fig)
|
3872
|
+
def nexttile(rowspan=1, colspan=1, **kwargs):
|
3873
|
+
nonlocal rows, cols, occupied, grid_spec
|
3874
|
+
for row in range(rows):
|
3875
|
+
for col in range(cols):
|
3876
|
+
if all(
|
3877
|
+
(row + r, col + c) not in occupied
|
3878
|
+
for r in range(rowspan)
|
3879
|
+
for c in range(colspan)
|
3880
|
+
):
|
3881
|
+
break
|
3882
|
+
else:
|
3883
|
+
continue
|
3884
|
+
break
|
3885
|
+
else:
|
3886
|
+
expand_ax()
|
3887
|
+
return nexttile(rowspan=rowspan, colspan=colspan, **kwargs)
|
3888
|
+
|
3889
|
+
sharex_ax,sharey_ax = None, None
|
3890
|
+
|
3891
|
+
if sharex:
|
3892
|
+
sharex_ax = col_first_axes[col]
|
3893
|
+
|
3894
|
+
if sharey:
|
3895
|
+
sharey_ax = row_first_axes[row]
|
3896
|
+
ax = fig.add_subplot(
|
3897
|
+
grid_spec[row : row + rowspan, col : col + colspan],
|
3898
|
+
sharex=sharex_ax,
|
3899
|
+
sharey=sharey_ax,
|
3900
|
+
**kwargs
|
3901
|
+
)
|
3902
|
+
if row_first_axes[row] is None:
|
3903
|
+
row_first_axes[row] = ax
|
3904
|
+
if col_first_axes[col] is None:
|
3905
|
+
col_first_axes[col] = ax
|
3906
|
+
for r in range(row, row + rowspan):
|
3907
|
+
for c in range(col, col + colspan):
|
3908
|
+
occupied.add((r, c))
|
3909
|
+
|
3910
|
+
return ax
|
3911
|
+
|
3912
|
+
return nexttile
|
3913
|
+
|
3914
|
+
|
3915
|
+
#! radar chart
|
3916
|
+
def radar(
|
3917
|
+
data: pd.DataFrame,
|
3918
|
+
ylim=(0,100),
|
3919
|
+
color=get_color(5),
|
3920
|
+
fontsize=10,
|
3921
|
+
fontcolor='k',
|
3922
|
+
size=6,
|
3923
|
+
linewidth=1,
|
3924
|
+
linestyle="-",
|
3925
|
+
alpha=0.5,
|
3926
|
+
marker="o",
|
3927
|
+
edgecolor='none',
|
3928
|
+
edge_linewidth=0,
|
3929
|
+
bg_color="0.8",
|
3930
|
+
bg_alpha=None,
|
3931
|
+
grid_interval_ratio=0.2,
|
3932
|
+
title="Radar Chart",
|
3933
|
+
cmap=None,
|
3934
|
+
legend_loc="upper right",
|
3935
|
+
legend_fontsize=10,
|
3936
|
+
grid_color="gray",
|
3937
|
+
grid_alpha=0.5,
|
3938
|
+
grid_linestyle="--",grid_linewidth=0.5,
|
3939
|
+
circular: bool = False,
|
3940
|
+
tick_fontsize=None,
|
3941
|
+
tick_fontcolor="0.65",
|
3942
|
+
tick_loc = None,# label position
|
3943
|
+
turning = None,
|
3944
|
+
ax=None,
|
3945
|
+
sp=2,
|
3946
|
+
**kwargs
|
3947
|
+
):
|
3948
|
+
"""
|
3949
|
+
Example DATA:
|
3950
|
+
df = pd.DataFrame(
|
3951
|
+
data=[
|
3952
|
+
[80, 80, 80, 80, 80, 80, 80],
|
3953
|
+
[90, 20, 95, 95, 30, 30, 80],
|
3954
|
+
[60, 90, 20, 20, 100, 90, 50],
|
3955
|
+
],
|
3956
|
+
index=["Hero", "Warrior", "Wizard"],
|
3957
|
+
columns=["HP", "MP", "ATK", "DEF", "SP.ATK", "SP.DEF", "SPD"])
|
3958
|
+
|
3959
|
+
Parameters:
|
3960
|
+
- data (pd.DataFrame): The data to plot. Each column corresponds to a variable, and each row represents a data point.
|
3961
|
+
- ylim (tuple): The limits of the radial axis (y-axis). Default is (0, 100).
|
3962
|
+
- color: The color(s) for the plot. Can be a single color or a list of colors.
|
3963
|
+
- fontsize (int): Font size for the angular labels (x-axis).
|
3964
|
+
- fontcolor (str): Color for the angular labels.
|
3965
|
+
- size (int): The size of the markers for each data point.
|
3966
|
+
- linewidth (int): Line width for the plot lines.
|
3967
|
+
- linestyle (str): Line style for the plot lines.
|
3968
|
+
- alpha (float): The transparency level for the filled area.
|
3969
|
+
- marker (str): The marker style for the data points.
|
3970
|
+
- edgecolor (str): The color for the marker edges.
|
3971
|
+
- edge_linewidth (int): Line width for the marker edges.
|
3972
|
+
- bg_color (str): Background color for the radar chart.
|
3973
|
+
- grid_interval_ratio (float): Determines the intervals for the grid lines as a fraction of the y-limit.
|
3974
|
+
- title (str): The title of the radar chart.
|
3975
|
+
- cmap (str): The colormap to use if `color` is a list.
|
3976
|
+
- legend_loc (str): The location of the legend.
|
3977
|
+
- legend_fontsize (int): Font size for the legend.
|
3978
|
+
- grid_color (str): Color for the grid lines.
|
3979
|
+
- grid_alpha (float): Transparency of the grid lines.
|
3980
|
+
- grid_linestyle (str): Style of the grid lines.
|
3981
|
+
- grid_linewidth (int): Line width of the grid lines.
|
3982
|
+
- circular (bool): If True, use circular grid lines. If False, use spider-style grid lines (straight lines).
|
3983
|
+
- tick_fontsize (int): Font size for the radial (y-axis) labels.
|
3984
|
+
- tick_fontcolor (str): Font color for the radial (y-axis) labels.
|
3985
|
+
- tick_loc (float or None): The location of the radial tick labels (between 0 and 1). If None, it is automatically calculated.
|
3986
|
+
- turning (float or None): Rotation of the radar chart. If None, it is not applied.
|
3987
|
+
- ax (matplotlib.axes.Axes or None): The axis on which to plot the radar chart. If None, a new axis will be created.
|
3988
|
+
- sp (int): Padding for the ticks from the plot area.
|
3989
|
+
- **kwargs: Additional arguments for customization.
|
3990
|
+
"""
|
3991
|
+
if circular:
|
3992
|
+
from matplotlib.colors import to_rgba
|
3993
|
+
kws_figsets = {}
|
3994
|
+
for k_arg, v_arg in kwargs.items():
|
3995
|
+
if "figset" in k_arg:
|
3996
|
+
kws_figsets = v_arg
|
3997
|
+
kwargs.pop(k_arg, None)
|
3998
|
+
break
|
3999
|
+
categories = list(data.columns)
|
4000
|
+
num_vars = len(categories)
|
4001
|
+
|
4002
|
+
# Set up angle for each category on radar chart
|
4003
|
+
angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist()
|
4004
|
+
angles += angles[:1] # Complete the loop to ensure straight-line connections
|
4005
|
+
|
4006
|
+
# If no axis is provided, create a new one
|
4007
|
+
if ax is None:
|
4008
|
+
fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(polar=True))
|
4009
|
+
|
4010
|
+
# bg_color
|
4011
|
+
if bg_alpha is None:
|
4012
|
+
bg_alpha=alpha
|
4013
|
+
ax.set_facecolor(to_rgba(bg_color,alpha=bg_alpha)) if circular else ax.set_facecolor('none')
|
4014
|
+
# Set up the radar chart with straight-line connections
|
4015
|
+
ax.set_theta_offset(np.pi / 2)
|
4016
|
+
ax.set_theta_direction(-1)
|
4017
|
+
|
4018
|
+
# Draw one axis per variable and add labels
|
4019
|
+
ax.set_xticks(angles[:-1])
|
4020
|
+
ax.set_xticklabels(categories)
|
4021
|
+
|
4022
|
+
# Set y-axis limits and grid intervals
|
4023
|
+
vmin, vmax = ylim
|
4024
|
+
if circular:
|
4025
|
+
#* cicular style
|
4026
|
+
ax.yaxis.set_ticks(np.arange(vmin, vmax+1, vmax * grid_interval_ratio))
|
4027
|
+
ax.grid(axis='both',
|
4028
|
+
color=grid_color,
|
4029
|
+
linestyle=grid_linestyle,
|
4030
|
+
alpha=grid_alpha,
|
4031
|
+
linewidth=grid_linewidth,
|
4032
|
+
dash_capstyle='round',
|
4033
|
+
dash_joinstyle='round',
|
4034
|
+
)
|
4035
|
+
ax.spines["polar"].set_color(grid_color)
|
4036
|
+
ax.spines["polar"].set_linewidth(grid_linewidth)
|
4037
|
+
ax.spines["polar"].set_linestyle('-')
|
4038
|
+
ax.spines["polar"].set_alpha(grid_alpha)
|
4039
|
+
ax.spines["polar"].set_capstyle('round')
|
4040
|
+
ax.spines["polar"].set_joinstyle('round')
|
4041
|
+
|
4042
|
+
else:
|
4043
|
+
#* spider style: spider-style grid (straight lines, not circles)
|
4044
|
+
# Create the spider-style grid (straight lines, not circles)
|
4045
|
+
for i in range(1, int(vmax * grid_interval_ratio) + 1):
|
4046
|
+
ax.plot(
|
4047
|
+
angles + [angles[0]], # Closing the loop
|
4048
|
+
[i * vmax * grid_interval_ratio] * (num_vars+1) + [i * vmax * grid_interval_ratio],
|
4049
|
+
color=grid_color, linestyle=grid_linestyle, alpha=grid_alpha,linewidth=grid_linewidth
|
4050
|
+
)
|
4051
|
+
# set bg_color
|
4052
|
+
ax.fill(angles, [vmax]*(data.shape[1]+1), color=bg_color, alpha=bg_alpha)
|
4053
|
+
ax.yaxis.grid(False)
|
4054
|
+
# Move radial labels away from plotted line
|
4055
|
+
if tick_loc is None:
|
4056
|
+
tick_loc = np.mean([angles[0],angles[1]])/(2*np.pi)*360 if circular else 0
|
4057
|
+
|
4058
|
+
ax.set_rlabel_position(tick_loc)
|
4059
|
+
ax.set_theta_offset(turning) if turning is not None else None
|
4060
|
+
ax.tick_params(axis='x', labelsize=fontsize, colors=fontcolor) # Optional: for angular labels
|
4061
|
+
tick_fontsize = fontsize-2 if fontsize is None else tick_fontsize
|
4062
|
+
ax.tick_params(axis='y', labelsize=tick_fontsize, colors=tick_fontcolor) # For radial labels
|
4063
|
+
if not circular:
|
4064
|
+
ax.spines['polar'].set_visible(False)
|
4065
|
+
ax.tick_params(axis='x', pad=sp) # move spines outward
|
4066
|
+
ax.tick_params(axis='y', pad=sp) # move spines outward
|
4067
|
+
# colors
|
4068
|
+
colors = get_color(data.shape[0]) if cmap is None else plt.get_cmap(cmap)(np.linspace(0, 1, data.shape[0]))
|
4069
|
+
# Plot each row with straight lines
|
4070
|
+
for i, (index, row) in enumerate(data.iterrows()):
|
4071
|
+
values = row.tolist()
|
4072
|
+
values += values[:1] # Close the loop
|
4073
|
+
ax.plot(
|
4074
|
+
angles,
|
4075
|
+
values,
|
4076
|
+
color=colors[i],
|
4077
|
+
linewidth=linewidth,
|
4078
|
+
linestyle=linestyle,
|
4079
|
+
label=index,
|
4080
|
+
clip_on=False
|
4081
|
+
)
|
4082
|
+
ax.fill(angles, values, color=colors[i], alpha=alpha)
|
4083
|
+
|
4084
|
+
ax.set_ylim(ylim)
|
4085
|
+
# Add markers for each data point
|
4086
|
+
for i, row in enumerate(data.values):
|
4087
|
+
ax.plot(
|
4088
|
+
angles,
|
4089
|
+
list(row) + [row[0]], # Close the loop for markers
|
4090
|
+
color=colors[i],
|
4091
|
+
marker=marker,
|
4092
|
+
markersize=size,
|
4093
|
+
markeredgecolor=edgecolor,
|
4094
|
+
markeredgewidth = edge_linewidth, zorder=10,clip_on=False
|
4095
|
+
)
|
4096
|
+
# ax.tick_params(axis='y', labelleft=False, left=False)
|
4097
|
+
if 'legend' in kws_figsets:
|
4098
|
+
figsets(ax=ax, **kws_figsets)
|
4099
|
+
else:
|
4100
|
+
|
4101
|
+
figsets(ax=ax,legend=dict(loc=legend_loc,fontsize=legend_fontsize,
|
4102
|
+
bbox_to_anchor=[1.1,1.4],ncols=2),**kws_figsets)
|
3818
4103
|
return ax
|