py2ls 0.2.4.6__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 +25 -22
- py2ls/data/usages_sns.json +2 -1
- py2ls/ips.py +1258 -724
- py2ls/ml2ls.py +1841 -390
- py2ls/plot.py +500 -235
- {py2ls-0.2.4.6.dist-info → py2ls-0.2.4.8.dist-info}/METADATA +2 -2
- {py2ls-0.2.4.6.dist-info → py2ls-0.2.4.8.dist-info}/RECORD +10 -10
- {py2ls-0.2.4.6.dist-info → py2ls-0.2.4.8.dist-info}/WHEEL +0 -0
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,81 +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
|
-
|
2361
|
-
|
2362
|
-
|
2363
|
-
|
2364
|
-
|
2365
|
-
|
2366
|
-
|
2367
|
-
|
2368
|
-
|
2369
|
-
|
2370
|
-
|
2371
|
-
|
2372
|
-
|
2373
|
-
|
2374
|
-
|
2375
|
-
|
2376
|
-
|
2377
|
-
|
2378
|
-
|
2379
|
-
|
2380
|
-
|
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
|
2381
2422
|
)
|
2382
|
-
|
2383
|
-
elif any(["hls" in cmap.lower(), "hsl" in cmap.lower()]):
|
2384
|
-
if kwargs:
|
2385
|
-
colorlist = sns.hls_palette(n, **kwargs)
|
2423
|
+
colorlist = [matplotlib.colors.rgb2hex(color) for color in colorlist]
|
2386
2424
|
else:
|
2387
|
-
|
2388
|
-
|
2389
|
-
|
2390
|
-
|
2391
|
-
|
2392
|
-
for k, v in kwargs.items():
|
2393
|
-
if "p" in k:
|
2394
|
-
palette = v
|
2395
|
-
elif "d" in k:
|
2396
|
-
desat = v
|
2397
|
-
elif "a" in k:
|
2398
|
-
as_cmap = v
|
2399
|
-
colorlist = sns.color_palette(
|
2400
|
-
palette=palette, n_colors=n, desat=desat, as_cmap=as_cmap
|
2401
|
-
)
|
2402
|
-
colorlist = [matplotlib.colors.rgb2hex(color) for color in colorlist]
|
2403
|
-
else:
|
2404
|
-
if by == "start":
|
2405
|
-
by = "linspace"
|
2406
|
-
colorlist = cmap2hex(cmap)
|
2425
|
+
if by == "start":
|
2426
|
+
by = "linspace"
|
2427
|
+
colorlist = cmap2hex(cmap)
|
2428
|
+
elif isinstance(cmap, list):
|
2429
|
+
colorlist=cmap
|
2407
2430
|
|
2408
2431
|
# Determine method for generating color list
|
2409
2432
|
if "st" in by.lower() or "be" in by.lower():
|
@@ -2423,35 +2446,15 @@ def get_color(
|
|
2423
2446
|
return hue_list
|
2424
2447
|
else:
|
2425
2448
|
raise ValueError("Invalid output type. Choose 'rgb' or 'hue'.")
|
2426
|
-
|
2427
|
-
# # Example usage
|
2428
|
-
# colors = get_color(n=5, cmap="viridis", by="linear", alpha=0.5,output='rgb')
|
2429
|
-
# print(colors)
|
2430
|
-
|
2431
|
-
|
2432
|
-
"""
|
2433
|
-
# n = 7
|
2434
|
-
# clist = get_color(n, cmap="auto", by="linspace") # get_color(100)
|
2435
|
-
# plt.figure(figsize=[8, 5], dpi=100)
|
2436
|
-
# x = np.linspace(0, 2 * np.pi, 50) * 100
|
2437
|
-
# y = np.sin(x)
|
2438
|
-
# for i in range(1, n + 1):
|
2439
|
-
# plt.plot(x, y + i, c=clist[i - 1], lw=5, label=str(i))
|
2440
|
-
# plt.legend()
|
2441
|
-
# plt.ylim(-2, 20)
|
2442
|
-
# figsets(plt.gca(), {"style": "whitegrid"}) """
|
2443
|
-
|
2444
|
-
|
2445
|
-
from scipy.signal import savgol_filter
|
2446
|
-
import numpy as np
|
2447
|
-
import matplotlib.pyplot as plt
|
2448
|
-
|
2449
|
+
|
2449
2450
|
|
2450
2451
|
def stdshade(ax=None, *args, **kwargs):
|
2451
2452
|
"""
|
2452
2453
|
usage:
|
2453
2454
|
plot.stdshade(data_array, c=clist[1], lw=2, ls="-.", alpha=0.2)
|
2454
2455
|
"""
|
2456
|
+
from scipy.signal import savgol_filter
|
2457
|
+
|
2455
2458
|
# Separate kws_line and kws_fill if necessary
|
2456
2459
|
kws_line = kwargs.pop("kws_line", {})
|
2457
2460
|
kws_fill = kwargs.pop("kws_fill", {})
|
@@ -2957,6 +2960,7 @@ def thumbnail(dir_img_list: list, figsize=(10, 10), dpi=100, show=False, verbose
|
|
2957
2960
|
|
2958
2961
|
|
2959
2962
|
def get_params_from_func_usage(function_signature):
|
2963
|
+
import re
|
2960
2964
|
# Regular expression to match parameter names, ignoring '*' and '**kwargs'
|
2961
2965
|
keys_pattern = r"(?<!\*\*)\b(\w+)="
|
2962
2966
|
# Find all matches
|
@@ -2983,7 +2987,7 @@ def plotxy(
|
|
2983
2987
|
x=None,
|
2984
2988
|
y=None,
|
2985
2989
|
ax=None,
|
2986
|
-
kind: Union[str, list] =
|
2990
|
+
kind: Union[str, list] = 'scatter', # Specify the kind of plot
|
2987
2991
|
verbose=False,
|
2988
2992
|
**kwargs,
|
2989
2993
|
):
|
@@ -3006,14 +3010,15 @@ def plotxy(
|
|
3006
3010
|
"""
|
3007
3011
|
# Check for valid plot kind
|
3008
3012
|
# Default arguments for various plot types
|
3009
|
-
|
3010
|
-
|
3011
|
-
)
|
3012
|
-
|
3013
|
-
|
3014
|
-
|
3015
|
-
|
3016
|
-
|
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
|
+
|
3017
3022
|
valid_kinds = list(default_settings.keys())
|
3018
3023
|
print(valid_kinds)
|
3019
3024
|
if kind is not None:
|
@@ -3022,6 +3027,7 @@ def plotxy(
|
|
3022
3027
|
kind = [strcmp(i, valid_kinds)[0] for i in kind]
|
3023
3028
|
else:
|
3024
3029
|
verbose = True
|
3030
|
+
|
3025
3031
|
if verbose:
|
3026
3032
|
if kind is not None:
|
3027
3033
|
for k in kind:
|
@@ -3033,7 +3039,7 @@ def plotxy(
|
|
3033
3039
|
.tolist()[0]
|
3034
3040
|
)
|
3035
3041
|
print()
|
3036
|
-
usage_str = """
|
3042
|
+
usage_str = """plotxy(data=ranked_genes,
|
3037
3043
|
x="log2(fold_change)",
|
3038
3044
|
y="-log10(p-value)",
|
3039
3045
|
palette=get_color(3, cmap="coolwarm"),
|
@@ -3057,24 +3063,15 @@ def plotxy(
|
|
3057
3063
|
kws_add_text = v_arg
|
3058
3064
|
kwargs.pop(k_arg, None)
|
3059
3065
|
break
|
3060
|
-
|
3066
|
+
zorder=0
|
3061
3067
|
for k in kind:
|
3068
|
+
zorder+=1
|
3062
3069
|
# indicate 'col' features
|
3063
3070
|
col = kwargs.get("col", None)
|
3064
|
-
sns_with_col = [
|
3065
|
-
"catplot",
|
3066
|
-
"histplot",
|
3067
|
-
"relplot",
|
3068
|
-
"lmplot",
|
3069
|
-
"pairplot",
|
3070
|
-
"displot",
|
3071
|
-
"kdeplot",
|
3072
|
-
]
|
3071
|
+
sns_with_col = ["catplot","histplot","relplot","lmplot","pairplot","displot","kdeplot"]
|
3073
3072
|
if col is not None:
|
3074
3073
|
if not k in sns_with_col:
|
3075
|
-
print(
|
3076
|
-
f"tips:\n'{k}' has no 'col' param, you could try with {sns_with_col}"
|
3077
|
-
)
|
3074
|
+
print(f"tips:\n'{k}' has no 'col' param, you could try with {sns_with_col}")
|
3078
3075
|
# (1) return FcetGrid
|
3079
3076
|
if k == "jointplot":
|
3080
3077
|
kws_joint = kwargs.pop("kws_joint", kwargs)
|
@@ -3093,7 +3090,6 @@ def plotxy(
|
|
3093
3090
|
# (2) return axis
|
3094
3091
|
if ax is None:
|
3095
3092
|
ax = plt.gca()
|
3096
|
-
|
3097
3093
|
if k == "catplot":
|
3098
3094
|
kws_cat = kwargs.pop("kws_cat", kwargs)
|
3099
3095
|
g = catplot(data=data, x=x, y=y, ax=ax, **kws_cat)
|
@@ -3102,88 +3098,86 @@ def plotxy(
|
|
3102
3098
|
ax = stdshade(ax=ax, **kwargs)
|
3103
3099
|
elif k == "scatterplot":
|
3104
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_")}
|
3105
3102
|
hue = kwargs.pop("hue", None)
|
3106
|
-
|
3107
|
-
"
|
3108
|
-
|
3109
|
-
|
3110
|
-
if hue is not None
|
3111
|
-
else sns.color_palette("tab10")
|
3112
|
-
),
|
3113
|
-
)
|
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)
|
3114
3107
|
s = kws_scatter.pop("s", 10)
|
3115
3108
|
alpha = kws_scatter.pop("alpha", 0.7)
|
3116
|
-
ax = sns.scatterplot(
|
3117
|
-
ax=ax,
|
3118
|
-
data=data,
|
3119
|
-
x=x,
|
3120
|
-
y=y,
|
3121
|
-
hue=hue,
|
3122
|
-
palette=palette,
|
3123
|
-
s=s,
|
3124
|
-
alpha=alpha,
|
3125
|
-
**kws_scatter,
|
3126
|
-
)
|
3109
|
+
ax = sns.scatterplot(ax=ax,data=data,x=x,y=y,hue=hue,palette=palette,s=s,alpha=alpha,zorder=zorder,**kws_scatter)
|
3127
3110
|
elif k == "histplot":
|
3128
3111
|
kws_hist = kwargs.pop("kws_hist", kwargs)
|
3129
|
-
|
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)
|
3130
3114
|
elif k == "kdeplot":
|
3131
3115
|
kws_kde = kwargs.pop("kws_kde", kwargs)
|
3132
|
-
|
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)
|
3133
3118
|
elif k == "ecdfplot":
|
3134
3119
|
kws_ecdf = kwargs.pop("kws_ecdf", kwargs)
|
3135
|
-
|
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)
|
3136
3122
|
elif k == "rugplot":
|
3137
3123
|
kws_rug = kwargs.pop("kws_rug", kwargs)
|
3138
|
-
|
3139
|
-
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)
|
3140
3126
|
elif k == "stripplot":
|
3141
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_")}
|
3142
3129
|
dodge = kws_strip.pop("dodge", True)
|
3143
|
-
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)
|
3144
3131
|
elif k == "swarmplot":
|
3145
3132
|
kws_swarm = kwargs.pop("kws_swarm", kwargs)
|
3146
|
-
|
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)
|
3147
3135
|
elif k == "boxplot":
|
3148
3136
|
kws_box = kwargs.pop("kws_box", kwargs)
|
3149
|
-
|
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)
|
3150
3139
|
elif k == "violinplot":
|
3151
3140
|
kws_violin = kwargs.pop("kws_violin", kwargs)
|
3152
|
-
|
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)
|
3153
3143
|
elif k == "boxenplot":
|
3154
3144
|
kws_boxen = kwargs.pop("kws_boxen", kwargs)
|
3155
|
-
|
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)
|
3156
3147
|
elif k == "pointplot":
|
3157
3148
|
kws_point = kwargs.pop("kws_point", kwargs)
|
3158
|
-
|
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)
|
3159
3151
|
elif k == "barplot":
|
3160
3152
|
kws_bar = kwargs.pop("kws_bar", kwargs)
|
3161
|
-
|
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)
|
3162
3155
|
elif k == "countplot":
|
3163
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_")}
|
3164
3158
|
if not kws_count.get("hue",None):
|
3165
3159
|
kws_count.pop("palette",None)
|
3166
|
-
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)
|
3167
3161
|
elif k == "regplot":
|
3168
3162
|
kws_reg = kwargs.pop("kws_reg", kwargs)
|
3169
|
-
|
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)
|
3170
3165
|
elif k == "residplot":
|
3171
3166
|
kws_resid = kwargs.pop("kws_resid", kwargs)
|
3172
|
-
|
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)
|
3173
3169
|
elif k == "lineplot":
|
3174
3170
|
kws_line = kwargs.pop("kws_line", kwargs)
|
3175
|
-
|
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)
|
3176
3173
|
|
3177
3174
|
figsets(ax=ax, **kws_figsets)
|
3178
|
-
|
3179
|
-
|
3180
|
-
|
3181
|
-
|
3182
|
-
|
3183
|
-
"=>\t",
|
3184
|
-
sns_info[sns_info["Functions"].str.contains(k)].iloc[:, -1].tolist()[0],
|
3185
|
-
)
|
3186
|
-
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")
|
3187
3181
|
if "g" in locals():
|
3188
3182
|
if ax is not None:
|
3189
3183
|
return g, ax
|
@@ -3202,7 +3196,7 @@ def volcano(
|
|
3202
3196
|
top_genes=[5, 5], # [down-regulated, up-regulated]
|
3203
3197
|
thr_x=np.log2(1.5), # default: 0.585
|
3204
3198
|
thr_y=-np.log10(0.05),
|
3205
|
-
sort_xy="x", #'y'
|
3199
|
+
sort_xy="x", #'y', 'xy'
|
3206
3200
|
colors=("#00BFFF", "#9d9a9a", "#FF3030"),
|
3207
3201
|
s=20,
|
3208
3202
|
fill=True, # plot filled scatter
|
@@ -3835,4 +3829,275 @@ def venn(
|
|
3835
3829
|
patch.set_alpha(alpha)
|
3836
3830
|
if 'none' in edgecolor or 0 in linewidth:
|
3837
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)
|
3838
4103
|
return ax
|