py2ls 0.2.4.15__py3-none-any.whl → 0.2.4.16__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- py2ls/.git/index +0 -0
- py2ls/ips.py +722 -12
- py2ls/ml2ls copy.py +2906 -0
- py2ls/ml2ls.py +345 -12
- py2ls/plot.py +409 -24
- {py2ls-0.2.4.15.dist-info → py2ls-0.2.4.16.dist-info}/METADATA +1 -1
- {py2ls-0.2.4.15.dist-info → py2ls-0.2.4.16.dist-info}/RECORD +8 -7
- {py2ls-0.2.4.15.dist-info → py2ls-0.2.4.16.dist-info}/WHEEL +0 -0
py2ls/plot.py
CHANGED
@@ -20,7 +20,9 @@ from .ips import (
|
|
20
20
|
flatten,
|
21
21
|
plt_font,
|
22
22
|
run_once_within,
|
23
|
+
df_format
|
23
24
|
)
|
25
|
+
import scipy.stats as scipy_stats
|
24
26
|
from .stats import *
|
25
27
|
import os
|
26
28
|
|
@@ -2255,7 +2257,10 @@ def figsets(*args, **kwargs):
|
|
2255
2257
|
colors = get_color(8)
|
2256
2258
|
matplotlib.rcParams["axes.prop_cycle"] = cycler(color=colors)
|
2257
2259
|
if len(fig.get_axes()) > 1:
|
2258
|
-
|
2260
|
+
try:
|
2261
|
+
plt.tight_layout()
|
2262
|
+
except Exception as e:
|
2263
|
+
print(e)
|
2259
2264
|
|
2260
2265
|
|
2261
2266
|
def split_legend(ax, n=2, loc=None, title=None, bbox=None, ncol=1, **kwargs):
|
@@ -3120,7 +3125,7 @@ def plotxy(
|
|
3120
3125
|
x=None,
|
3121
3126
|
y=None,
|
3122
3127
|
ax=None,
|
3123
|
-
|
3128
|
+
kind_: Union[str, list] = "scatter", # Specify the kind of plot
|
3124
3129
|
verbose=False,
|
3125
3130
|
**kwargs,
|
3126
3131
|
):
|
@@ -3155,23 +3160,23 @@ def plotxy(
|
|
3155
3160
|
|
3156
3161
|
valid_kinds = list(default_settings.keys())
|
3157
3162
|
# print(valid_kinds)
|
3158
|
-
if
|
3159
|
-
if isinstance(
|
3160
|
-
|
3161
|
-
|
3163
|
+
if kind_ is not None:
|
3164
|
+
if isinstance(kind_, str):
|
3165
|
+
kind_ = [kind_]
|
3166
|
+
kind_ = [strcmp(i, valid_kinds)[0] for i in kind_]
|
3162
3167
|
else:
|
3163
3168
|
verbose = True
|
3164
3169
|
|
3165
3170
|
if verbose:
|
3166
|
-
if
|
3167
|
-
for k in
|
3171
|
+
if kind_ is not None:
|
3172
|
+
for k in kind_:
|
3168
3173
|
if k in valid_kinds:
|
3169
3174
|
print(f"{k}:\n\t{default_settings[k]}")
|
3170
3175
|
usage_str = """plotxy(data=ranked_genes,
|
3171
3176
|
x="log2(fold_change)",
|
3172
3177
|
y="-log10(p-value)",
|
3173
3178
|
palette=get_color(3, cmap="coolwarm"),
|
3174
|
-
|
3179
|
+
kind_=["scatter","rug"],
|
3175
3180
|
kws_rug=dict(height=0.2),
|
3176
3181
|
kws_scatter=dict(s=20, color=get_color(3)[2]),
|
3177
3182
|
verbose=0)
|
@@ -3192,7 +3197,11 @@ def plotxy(
|
|
3192
3197
|
kwargs.pop(k_arg, None)
|
3193
3198
|
break
|
3194
3199
|
zorder = 0
|
3195
|
-
for k in
|
3200
|
+
for k in kind_:
|
3201
|
+
# preprocess data
|
3202
|
+
data=df_preprocessing_(data, kind=k)
|
3203
|
+
if 'variable' in data.columns and 'value' in data.columns:
|
3204
|
+
x,y='variable','value'
|
3196
3205
|
zorder += 1
|
3197
3206
|
# indicate 'col' features
|
3198
3207
|
col = kwargs.get("col", None)
|
@@ -3213,10 +3222,166 @@ def plotxy(
|
|
3213
3222
|
# (1) return FcetGrid
|
3214
3223
|
if k == "jointplot":
|
3215
3224
|
kws_joint = kwargs.pop("kws_joint", kwargs)
|
3225
|
+
stats=kwargs.pop("stats",True)
|
3226
|
+
if stats:
|
3227
|
+
r, p_value = scipy_stats.pearsonr(data[x], data[y])
|
3216
3228
|
g = sns.jointplot(data=data, x=x, y=y, **kws_joint)
|
3229
|
+
g.ax_joint.annotate(
|
3230
|
+
f"pearsonr = {r:.2f} p = {p_value:.3f}",
|
3231
|
+
xy=(0.6, 0.98),
|
3232
|
+
xycoords="axes fraction",
|
3233
|
+
fontsize=12,
|
3234
|
+
color="black",
|
3235
|
+
ha="center",
|
3236
|
+
)
|
3217
3237
|
elif k == "lmplot":
|
3218
3238
|
kws_lm = kwargs.pop("kws_lm", kwargs)
|
3219
|
-
|
3239
|
+
stats = kwargs.pop("stats", True) # Flag to calculate stats
|
3240
|
+
hue = kwargs.pop("hue", None) # Get the hue argument (if any)
|
3241
|
+
col = kwargs.pop("col", None) # Get the col argument (if any)
|
3242
|
+
row = kwargs.pop("row", None) # Get the row argument (if any)
|
3243
|
+
|
3244
|
+
# Create the linear model plot (lmplot)
|
3245
|
+
g = sns.lmplot(data=data, x=x, y=y, hue=hue, col=col, row=row, **kws_lm)
|
3246
|
+
|
3247
|
+
# Compute Pearson correlation and p-value statistics
|
3248
|
+
if stats:
|
3249
|
+
stats_per_facet = {}
|
3250
|
+
stats_per_hue = {}
|
3251
|
+
|
3252
|
+
# If no hue, col, or row, calculate stats for the entire dataset
|
3253
|
+
if all([hue is None, col is None, row is None]):
|
3254
|
+
r, p_value = scipy_stats.pearsonr(data[x], data[y])
|
3255
|
+
stats_per_facet[(None, None)] = (r, p_value) # Store stats for the entire dataset
|
3256
|
+
|
3257
|
+
else:
|
3258
|
+
if hue is None and (col is not None or row is not None):
|
3259
|
+
for ax in g.axes.flat:
|
3260
|
+
facet_name = ax.get_title()
|
3261
|
+
if '=' in facet_name:
|
3262
|
+
# Assume facet_name is like 'Column = Value'
|
3263
|
+
facet_column_name = facet_name.split('=')[0].strip() # Column name before '='
|
3264
|
+
facet_value_str = facet_name.split('=')[1].strip() # Facet value after '='
|
3265
|
+
|
3266
|
+
# Try converting facet_value to match the data type of the DataFrame column
|
3267
|
+
facet_column_dtype = data[facet_column_name].dtype
|
3268
|
+
if facet_column_dtype == 'int' or facet_column_dtype == 'float':
|
3269
|
+
facet_value = pd.to_numeric(facet_value_str, errors='coerce') # Convert to numeric
|
3270
|
+
else:
|
3271
|
+
facet_value = facet_value_str # Treat as a string if not numeric
|
3272
|
+
else:
|
3273
|
+
facet_column_name = facet_name.split('=')[0].strip() # Column name before '='
|
3274
|
+
facet_value=facet_name.split('=')[1].strip()
|
3275
|
+
facet_data = data[data[facet_column_name] == facet_value]
|
3276
|
+
if not facet_data.empty:
|
3277
|
+
r, p_value = scipy_stats.pearsonr(facet_data[x], facet_data[y])
|
3278
|
+
stats_per_facet[facet_name] = (r, p_value)
|
3279
|
+
else:
|
3280
|
+
stats_per_facet[facet_name] = (None, None) # Handle empty facets
|
3281
|
+
|
3282
|
+
# Annotate the stats on the plot
|
3283
|
+
for ax in g.axes.flat:
|
3284
|
+
if stats:
|
3285
|
+
# Adjust the position for each facet to avoid overlap
|
3286
|
+
idx=1
|
3287
|
+
shift_factor = 0.02 * idx # Adjust this factor as needed to prevent overlap
|
3288
|
+
y_position = 0.98 - shift_factor # Dynamic vertical shift for each facet
|
3289
|
+
|
3290
|
+
if all([hue is None, col is None, row is None]):
|
3291
|
+
# Use stats for the entire dataset if no hue, col, or row
|
3292
|
+
r, p_value = stats_per_facet.get((None, None), (None, None))
|
3293
|
+
if r is not None and p_value is not None:
|
3294
|
+
ax.annotate(
|
3295
|
+
f"pearsonr = {r:.2f} p = {p_value:.3f}",
|
3296
|
+
xy=(0.6, y_position),
|
3297
|
+
xycoords="axes fraction",
|
3298
|
+
fontsize=12,
|
3299
|
+
color="black",
|
3300
|
+
ha="center",
|
3301
|
+
)
|
3302
|
+
else:
|
3303
|
+
ax.annotate(
|
3304
|
+
"No stats available",
|
3305
|
+
xy=(0.6, y_position),
|
3306
|
+
xycoords="axes fraction",
|
3307
|
+
fontsize=12,
|
3308
|
+
color="black",
|
3309
|
+
ha="center",
|
3310
|
+
)
|
3311
|
+
elif hue is not None:
|
3312
|
+
if (col is None and row is None):
|
3313
|
+
hue_categories = sorted(flatten(data[hue],verbose=0))
|
3314
|
+
idx=1
|
3315
|
+
for category in hue_categories:
|
3316
|
+
subset_data = data[data[hue] == category]
|
3317
|
+
r, p_value = scipy_stats.pearsonr(subset_data[x], subset_data[y])
|
3318
|
+
stats_per_hue[category] = (r, p_value)
|
3319
|
+
shift_factor = 0.05 * idx # Adjust this factor as needed to prevent overlap
|
3320
|
+
y_position = 0.98 - shift_factor # Dynamic vertical shift for each facet
|
3321
|
+
ax.annotate(
|
3322
|
+
f"{category}: pearsonr = {r:.2f} p = {p_value:.3f}",
|
3323
|
+
xy=(0.6, y_position),
|
3324
|
+
xycoords="axes fraction",
|
3325
|
+
fontsize=12,
|
3326
|
+
color="black",
|
3327
|
+
ha="center",
|
3328
|
+
)
|
3329
|
+
idx+=1
|
3330
|
+
else:
|
3331
|
+
for ax in g.axes.flat:
|
3332
|
+
facet_name = ax.get_title()
|
3333
|
+
if '=' in facet_name:
|
3334
|
+
# Assume facet_name is like 'Column = Value'
|
3335
|
+
facet_column_name = facet_name.split('=')[0].strip() # Column name before '='
|
3336
|
+
facet_value_str = facet_name.split('=')[1].strip() # Facet value after '='
|
3337
|
+
|
3338
|
+
# Try converting facet_value to match the data type of the DataFrame column
|
3339
|
+
facet_column_dtype = data[facet_column_name].dtype
|
3340
|
+
if facet_column_dtype == 'int' or facet_column_dtype == 'float':
|
3341
|
+
facet_value = pd.to_numeric(facet_value_str, errors='coerce') # Convert to numeric
|
3342
|
+
else:
|
3343
|
+
facet_value = facet_value_str # Treat as a string if not numeric
|
3344
|
+
else:
|
3345
|
+
facet_column_name = facet_name.split('=')[0].strip() # Column name before '='
|
3346
|
+
facet_value=facet_name.split('=')[1].strip()
|
3347
|
+
facet_data = data[data[facet_column_name] == facet_value]
|
3348
|
+
if not facet_data.empty:
|
3349
|
+
r, p_value = scipy_stats.pearsonr(facet_data[x], facet_data[y])
|
3350
|
+
stats_per_facet[facet_name] = (r, p_value)
|
3351
|
+
else:
|
3352
|
+
stats_per_facet[facet_name] = (None, None) # Handle empty facets
|
3353
|
+
|
3354
|
+
ax.annotate(
|
3355
|
+
f"pearsonr = {r:.2f} p = {p_value:.3f}",
|
3356
|
+
xy=(0.6, y_position),
|
3357
|
+
xycoords="axes fraction",
|
3358
|
+
fontsize=12,
|
3359
|
+
color="black",
|
3360
|
+
ha="center",
|
3361
|
+
)
|
3362
|
+
elif hue is None and (col is not None or row is not None):
|
3363
|
+
# Annotate stats for each facet
|
3364
|
+
facet_name = ax.get_title()
|
3365
|
+
r, p_value = stats_per_facet.get(facet_name, (None, None))
|
3366
|
+
if r is not None and p_value is not None:
|
3367
|
+
ax.annotate(
|
3368
|
+
f"pearsonr = {r:.2f} p = {p_value:.3f}",
|
3369
|
+
xy=(0.6, y_position),
|
3370
|
+
xycoords="axes fraction",
|
3371
|
+
fontsize=12,
|
3372
|
+
color="black",
|
3373
|
+
ha="center",
|
3374
|
+
)
|
3375
|
+
else:
|
3376
|
+
ax.annotate(
|
3377
|
+
"No stats available",
|
3378
|
+
xy=(0.6, y_position),
|
3379
|
+
xycoords="axes fraction",
|
3380
|
+
fontsize=12,
|
3381
|
+
color="black",
|
3382
|
+
ha="center",
|
3383
|
+
)
|
3384
|
+
|
3220
3385
|
elif k == "catplot_sns":
|
3221
3386
|
kws_cat = kwargs.pop("kws_cat", kwargs)
|
3222
3387
|
g = sns.catplot(data=data, x=x, y=y, **kws_cat)
|
@@ -3317,7 +3482,22 @@ def plotxy(
|
|
3317
3482
|
elif k == "regplot":
|
3318
3483
|
kws_reg = kwargs.pop("kws_reg", kwargs)
|
3319
3484
|
kws_reg = {k: v for k, v in kws_reg.items() if not k.startswith("kws_")}
|
3320
|
-
|
3485
|
+
stats = kwargs.pop("stats", True) # Flag to calculate stats
|
3486
|
+
|
3487
|
+
# Compute Pearson correlation if stats is True
|
3488
|
+
if stats:
|
3489
|
+
r, p_value = scipy_stats.pearsonr(data[x], data[y])
|
3490
|
+
ax = sns.regplot(data=data, x=x, y=y, ax=ax, **kws_reg)
|
3491
|
+
|
3492
|
+
# Annotate the Pearson correlation and p-value
|
3493
|
+
ax.annotate(
|
3494
|
+
f"pearsonr = {r:.2f} p = {p_value:.3f}",
|
3495
|
+
xy=(0.6, 0.98),
|
3496
|
+
xycoords="axes fraction",
|
3497
|
+
fontsize=12,
|
3498
|
+
color="black",
|
3499
|
+
ha="center",
|
3500
|
+
)
|
3321
3501
|
elif k == "residplot":
|
3322
3502
|
kws_resid = kwargs.pop("kws_resid", kwargs)
|
3323
3503
|
kws_resid = {k: v for k, v in kws_resid.items() if not k.startswith("kws_")}
|
@@ -3332,7 +3512,7 @@ def plotxy(
|
|
3332
3512
|
figsets(ax=ax, **kws_figsets)
|
3333
3513
|
if kws_add_text:
|
3334
3514
|
add_text(ax=ax, **kws_add_text) if kws_add_text else None
|
3335
|
-
if run_once_within(
|
3515
|
+
if run_once_within(10):
|
3336
3516
|
print(f"\n{k}⤵ ")
|
3337
3517
|
print(default_settings[k])
|
3338
3518
|
# print("=>\t",sns_info[sns_info["Functions"].str.contains(k)].iloc[:, -1].tolist()[0],"\n")
|
@@ -3341,6 +3521,125 @@ def plotxy(
|
|
3341
3521
|
return g, ax
|
3342
3522
|
return ax
|
3343
3523
|
|
3524
|
+
import pandas as pd
|
3525
|
+
|
3526
|
+
|
3527
|
+
def df_preprocessing_(data, kind, verbose=False):
|
3528
|
+
"""
|
3529
|
+
Automatically formats data for various seaborn plot types.
|
3530
|
+
|
3531
|
+
Parameters:
|
3532
|
+
- data (pd.DataFrame): Original DataFrame.
|
3533
|
+
- kind (str): Type of seaborn plot, e.g., "heatmap", "boxplot", "violinplot", "lineplot", "scatterplot", "histplot", "kdeplot", "catplot", "barplot".
|
3534
|
+
- verbose (bool): If True, print detailed information about the data format conversion.
|
3535
|
+
|
3536
|
+
Returns:
|
3537
|
+
- pd.DataFrame: Formatted DataFrame ready for the specified seaborn plot type.
|
3538
|
+
"""
|
3539
|
+
# Determine data format: 'long', 'wide', or 'uncertain'
|
3540
|
+
df_format_ = df_format(data)
|
3541
|
+
|
3542
|
+
# Correct plot type name
|
3543
|
+
kind = strcmp(
|
3544
|
+
kind,
|
3545
|
+
[
|
3546
|
+
"heatmap",
|
3547
|
+
"pairplot",
|
3548
|
+
"jointplot", # Typically requires wide format for axis variables
|
3549
|
+
"facetgrid", # Used for creating small multiples (can work with wide format)
|
3550
|
+
"barplot", # Can be used with wide format
|
3551
|
+
"pointplot", # Works well with wide format
|
3552
|
+
"pivot_table", # Works with wide format (aggregated data)
|
3553
|
+
"boxplot",
|
3554
|
+
"violinplot",
|
3555
|
+
"stripplot",
|
3556
|
+
"swarmplot",
|
3557
|
+
"catplot",
|
3558
|
+
"lineplot",
|
3559
|
+
"scatterplot",
|
3560
|
+
"relplot",
|
3561
|
+
"barplot", # Can also work with long format (aggregated data in long form)
|
3562
|
+
"boxenplot", # Similar to boxplot, works with long format
|
3563
|
+
"countplot", # Works best with long format (categorical data)
|
3564
|
+
"heatmap", # Can work with long format after reshaping
|
3565
|
+
"lineplot", # Can work with long format (time series, continuous)
|
3566
|
+
"histplot", # Can be used with both wide and long formats
|
3567
|
+
"kdeplot", # Works with both wide and long formats
|
3568
|
+
"ecdfplot", # Works with both formats
|
3569
|
+
"scatterplot", # Can work with both formats depending on data structure
|
3570
|
+
"lineplot", # Can work with both wide and long formats
|
3571
|
+
"area plot", # Can work with both formats, useful for stacked areas
|
3572
|
+
"violinplot", # Can work with both formats depending on categorical vs continuous data
|
3573
|
+
],
|
3574
|
+
)[0]
|
3575
|
+
|
3576
|
+
wide_kinds = [
|
3577
|
+
"pairplot",
|
3578
|
+
]
|
3579
|
+
|
3580
|
+
# Define plot types that require 'long' format
|
3581
|
+
long_kinds = [
|
3582
|
+
"catplot",
|
3583
|
+
]
|
3584
|
+
|
3585
|
+
# Flexible kinds: distribution plots can use either format
|
3586
|
+
flexible_kinds = [
|
3587
|
+
"jointplot", # Typically requires wide format for axis variables
|
3588
|
+
"lineplot", # Can work with long format (time series, continuous)
|
3589
|
+
"lineplot",
|
3590
|
+
"scatterplot",
|
3591
|
+
"barplot", # Can also work with long format (aggregated data in long form)
|
3592
|
+
"boxenplot", # Similar to boxplot, works with long format
|
3593
|
+
"countplot", # Works best with long format (categorical data)
|
3594
|
+
"regplot",
|
3595
|
+
"violinplot",
|
3596
|
+
"stripplot",
|
3597
|
+
"swarmplot",
|
3598
|
+
"boxplot",
|
3599
|
+
"histplot", # Can be used with both wide and long formats
|
3600
|
+
"kdeplot", # Works with both wide and long formats
|
3601
|
+
"ecdfplot", # Works with both formats
|
3602
|
+
"scatterplot", # Can work with both formats depending on data structure
|
3603
|
+
"lineplot", # Can work with both wide and long formats
|
3604
|
+
"area plot", # Can work with both formats, useful for stacked areas
|
3605
|
+
"violinplot", # Can work with both formats depending on categorical vs continuous data
|
3606
|
+
"relplot",
|
3607
|
+
"pointplot", # Works well with wide format
|
3608
|
+
]
|
3609
|
+
|
3610
|
+
# Wide format (e.g., for heatmap and pairplot)
|
3611
|
+
if kind in wide_kinds:
|
3612
|
+
if df_format_ != "wide":
|
3613
|
+
if verbose:
|
3614
|
+
print("Converting to wide format for", kind)
|
3615
|
+
return data.corr() if kind == "heatmap" else data
|
3616
|
+
return data
|
3617
|
+
|
3618
|
+
# Long format for categorical plots or time series
|
3619
|
+
elif kind in long_kinds:
|
3620
|
+
if df_format_ == "wide":
|
3621
|
+
if verbose:
|
3622
|
+
print("Converting wide data to long format for", kind)
|
3623
|
+
return pd.melt(data, var_name="variable", value_name="value")
|
3624
|
+
elif df_format_ == "uncertain":
|
3625
|
+
if verbose:
|
3626
|
+
print("Data format is uncertain, attempting to melt for", kind)
|
3627
|
+
return pd.melt(data, var_name="variable", value_name="value")
|
3628
|
+
return data
|
3629
|
+
|
3630
|
+
# Flexible format: distribution plots can use either long or wide
|
3631
|
+
elif kind in flexible_kinds:
|
3632
|
+
if df_format_ == "wide" or df_format_ == "long":
|
3633
|
+
return data
|
3634
|
+
if verbose:
|
3635
|
+
print("Converting uncertain format to long format for distribution plots")
|
3636
|
+
return pd.melt(data, var_name="variable", value_name="value")
|
3637
|
+
|
3638
|
+
else:
|
3639
|
+
if verbose:
|
3640
|
+
print("Unrecognized plot type; returning original data without conversion.")
|
3641
|
+
return data
|
3642
|
+
|
3344
3643
|
|
3345
3644
|
def norm_cmap(data, cmap="coolwarm", min_max=[0, 1]):
|
3346
3645
|
norm_ = plt.Normalize(min_max[0], min_max[1])
|
@@ -4103,6 +4402,7 @@ def subplot(
|
|
4103
4402
|
figsize: Union[tuple, list] = [8, 8],
|
4104
4403
|
sharex=False,
|
4105
4404
|
sharey=False,
|
4405
|
+
verbose=False,
|
4106
4406
|
**kwargs,
|
4107
4407
|
):
|
4108
4408
|
"""
|
@@ -4125,23 +4425,32 @@ def subplot(
|
|
4125
4425
|
"""
|
4126
4426
|
from matplotlib.gridspec import GridSpec
|
4127
4427
|
|
4128
|
-
if
|
4428
|
+
if verbose:
|
4129
4429
|
print(
|
4130
|
-
f"usage:\n\tnexttile = subplot(2, 2, figsize=(5, 5), sharex=
|
4430
|
+
f"usage:\n\tnexttile = subplot(2, 2, figsize=(5, 5), sharex=False, sharey=False)\n\tax = nexttile()"
|
4131
4431
|
)
|
4132
|
-
|
4432
|
+
|
4433
|
+
figsize_recommend = f"subplot({rows}, {cols}, figsize={figsize})"
|
4434
|
+
|
4435
|
+
fig = plt.figure(figsize=figsize, constrained_layout=True)
|
4133
4436
|
grid_spec = GridSpec(rows, cols, figure=fig)
|
4134
4437
|
occupied = set()
|
4135
4438
|
row_first_axes = [None] * rows # Track the first axis in each row (for sharey)
|
4136
4439
|
col_first_axes = [None] * cols # Track the first axis in each column (for sharex)
|
4137
4440
|
|
4138
4441
|
def expand_ax():
|
4139
|
-
nonlocal rows, grid_spec
|
4442
|
+
nonlocal rows, grid_spec,cols,row_first_axes,fig,figsize,figsize_recommend
|
4443
|
+
# fig_height = fig.get_figheight()
|
4444
|
+
# subplot_height = fig_height / rows
|
4140
4445
|
rows += 1 # Expands by adding a row
|
4446
|
+
# figsize = (figsize[0], fig_height+subplot_height)
|
4447
|
+
fig.set_size_inches(figsize)
|
4141
4448
|
grid_spec = GridSpec(rows, cols, figure=fig)
|
4142
|
-
|
4449
|
+
row_first_axes.append(None)
|
4450
|
+
figsize_recommend=f"Warning: 建议设置 subplot({rows}, {cols})"
|
4451
|
+
print(figsize_recommend)
|
4143
4452
|
def nexttile(rowspan=1, colspan=1, **kwargs):
|
4144
|
-
nonlocal rows, cols, occupied, grid_spec
|
4453
|
+
nonlocal rows, cols, occupied, grid_spec,fig,figsize_recommend
|
4145
4454
|
for row in range(rows):
|
4146
4455
|
for col in range(cols):
|
4147
4456
|
if all(
|
@@ -4153,6 +4462,7 @@ def subplot(
|
|
4153
4462
|
else:
|
4154
4463
|
continue
|
4155
4464
|
break
|
4465
|
+
|
4156
4466
|
else:
|
4157
4467
|
expand_ax()
|
4158
4468
|
return nexttile(rowspan=rowspan, colspan=colspan, **kwargs)
|
@@ -4161,7 +4471,6 @@ def subplot(
|
|
4161
4471
|
|
4162
4472
|
if sharex:
|
4163
4473
|
sharex_ax = col_first_axes[col]
|
4164
|
-
|
4165
4474
|
if sharey:
|
4166
4475
|
sharey_ax = row_first_axes[row]
|
4167
4476
|
ax = fig.add_subplot(
|
@@ -4170,22 +4479,24 @@ def subplot(
|
|
4170
4479
|
sharey=sharey_ax,
|
4171
4480
|
**kwargs,
|
4172
4481
|
)
|
4482
|
+
|
4173
4483
|
if row_first_axes[row] is None:
|
4174
4484
|
row_first_axes[row] = ax
|
4175
4485
|
if col_first_axes[col] is None:
|
4176
4486
|
col_first_axes[col] = ax
|
4487
|
+
|
4177
4488
|
for r in range(row, row + rowspan):
|
4178
4489
|
for c in range(col, col + colspan):
|
4179
4490
|
occupied.add((r, c))
|
4180
|
-
|
4491
|
+
|
4181
4492
|
return ax
|
4182
|
-
|
4183
4493
|
return nexttile
|
4184
4494
|
|
4185
4495
|
|
4186
4496
|
#! radar chart
|
4187
4497
|
def radar(
|
4188
4498
|
data: pd.DataFrame,
|
4499
|
+
title="Radar Chart",
|
4189
4500
|
ylim=(0, 100),
|
4190
4501
|
color=get_color(5),
|
4191
4502
|
fontsize=10,
|
@@ -4196,11 +4507,11 @@ def radar(
|
|
4196
4507
|
alpha=0.5,
|
4197
4508
|
marker="o",
|
4198
4509
|
edgecolor="none",
|
4199
|
-
edge_linewidth=0,
|
4510
|
+
edge_linewidth=0.5,
|
4200
4511
|
bg_color="0.8",
|
4201
4512
|
bg_alpha=None,
|
4202
4513
|
grid_interval_ratio=0.2,
|
4203
|
-
|
4514
|
+
show_value=False,# show text for each value
|
4204
4515
|
cmap=None,
|
4205
4516
|
legend_loc="upper right",
|
4206
4517
|
legend_fontsize=10,
|
@@ -4215,6 +4526,7 @@ def radar(
|
|
4215
4526
|
turning=None,
|
4216
4527
|
ax=None,
|
4217
4528
|
sp=2,
|
4529
|
+
verbose=True,
|
4218
4530
|
**kwargs,
|
4219
4531
|
):
|
4220
4532
|
"""
|
@@ -4239,6 +4551,7 @@ def radar(
|
|
4239
4551
|
- linestyle (str): Line style for the plot lines.
|
4240
4552
|
- alpha (float): The transparency level for the filled area.
|
4241
4553
|
- marker (str): The marker style for the data points.
|
4554
|
+
- value_offset=0.93,# offset of the text of each value
|
4242
4555
|
- edgecolor (str): The color for the marker edges.
|
4243
4556
|
- edge_linewidth (int): Line width for the marker edges.
|
4244
4557
|
- bg_color (str): Background color for the radar chart.
|
@@ -4260,6 +4573,43 @@ def radar(
|
|
4260
4573
|
- sp (int): Padding for the ticks from the plot area.
|
4261
4574
|
- **kwargs: Additional arguments for customization.
|
4262
4575
|
"""
|
4576
|
+
if run_once_within() and verbose:
|
4577
|
+
usage_="""usage:
|
4578
|
+
radar(
|
4579
|
+
data: pd.DataFrame, #The data to plot. Each column corresponds to a variable, and each row represents a data point.
|
4580
|
+
title="Radar Chart",
|
4581
|
+
ylim=(0, 100),# ylim (tuple): The limits of the radial axis (y-axis). Default is (0, 100).
|
4582
|
+
color=get_color(5),#The color(s) for the plot. Can be a single color or a list of colors.
|
4583
|
+
fontsize=10,# Font size for the angular labels (x-axis).
|
4584
|
+
fontcolor="k",# Color for the angular labels.
|
4585
|
+
size=6,#The size of the markers for each data point.
|
4586
|
+
linewidth=1,
|
4587
|
+
linestyle="-",
|
4588
|
+
alpha=0.5,#for the filled area.
|
4589
|
+
marker="o",# for the data points.
|
4590
|
+
edgecolor="none",#for the marker edges.
|
4591
|
+
edge_linewidth=0.5,#for the marker edges.
|
4592
|
+
bg_color="0.8",
|
4593
|
+
bg_alpha=None,
|
4594
|
+
grid_interval_ratio=0.2,#Determines the intervals for the grid lines as a fraction of the y-limit.
|
4595
|
+
show_value=False,# show text for each value
|
4596
|
+
cmap=None,
|
4597
|
+
legend_loc="upper right",
|
4598
|
+
legend_fontsize=10,
|
4599
|
+
grid_color="gray",
|
4600
|
+
grid_alpha=0.5,
|
4601
|
+
grid_linestyle="--",
|
4602
|
+
grid_linewidth=0.5,
|
4603
|
+
circular: bool = False,#If True, use circular grid lines. If False, use spider-style grid lines (straight lines)
|
4604
|
+
tick_fontsize=None,#for the radial (y-axis) labels.
|
4605
|
+
tick_fontcolor="0.65",#for the radial (y-axis) labels.
|
4606
|
+
tick_loc=None, # label position
|
4607
|
+
turning=None,#Rotation of the radar chart
|
4608
|
+
ax=None,
|
4609
|
+
sp=2,#Padding for the ticks from the plot area.
|
4610
|
+
**kwargs,
|
4611
|
+
)"""
|
4612
|
+
print(usage_)
|
4263
4613
|
if circular:
|
4264
4614
|
from matplotlib.colors import to_rgba
|
4265
4615
|
kws_figsets = {}
|
@@ -4371,6 +4721,41 @@ def radar(
|
|
4371
4721
|
clip_on=False,
|
4372
4722
|
)
|
4373
4723
|
ax.fill(angles, values, color=colors[i], alpha=alpha)
|
4724
|
+
# Add text labels for each value at each angle
|
4725
|
+
labeled_points = set() #这样同一个点就不会标多次了
|
4726
|
+
if show_value:
|
4727
|
+
for angle, value in zip(angles, values):
|
4728
|
+
if (angle, value) not in labeled_points:
|
4729
|
+
# offset_radius = value * value_offset
|
4730
|
+
lim_ = np.max(values)
|
4731
|
+
sep_in = lim_/5
|
4732
|
+
sep_low=sep_in*2
|
4733
|
+
sep_med=sep_in*3
|
4734
|
+
sep_hig=sep_in*4
|
4735
|
+
sep_out=lim_*5
|
4736
|
+
if value<sep_in:
|
4737
|
+
offset_radius = value * 0.7
|
4738
|
+
elif value<sep_low:
|
4739
|
+
offset_radius = value * 0.8
|
4740
|
+
elif sep_low<=value<sep_med:
|
4741
|
+
offset_radius = value * 0.85
|
4742
|
+
elif sep_med<=value<sep_hig:
|
4743
|
+
offset_radius = value * 0.9
|
4744
|
+
elif sep_hig<=value<sep_out:
|
4745
|
+
offset_radius = value * 0.93
|
4746
|
+
else:
|
4747
|
+
offset_radius = value * 0.98
|
4748
|
+
ax.text(
|
4749
|
+
angle,
|
4750
|
+
offset_radius,
|
4751
|
+
str(value),
|
4752
|
+
ha="center",
|
4753
|
+
va="center",
|
4754
|
+
fontsize=fontsize,
|
4755
|
+
color=fontcolor,
|
4756
|
+
zorder=11
|
4757
|
+
)
|
4758
|
+
labeled_points.add((angle, value))
|
4374
4759
|
|
4375
4760
|
ax.set_ylim(ylim)
|
4376
4761
|
# Add markers for each data point
|
@@ -17,7 +17,7 @@ py2ls/.git/hooks/pre-receive.sample,sha256=pMPSuce7P9jRRBwxvU7nGlldZrRPz0ndsxAlI
|
|
17
17
|
py2ls/.git/hooks/prepare-commit-msg.sample,sha256=6d3KpBif3dJe2X_Ix4nsp7bKFjkLI5KuMnbwyOGqRhk,1492
|
18
18
|
py2ls/.git/hooks/push-to-checkout.sample,sha256=pT0HQXmLKHxt16-mSu5HPzBeZdP0lGO7nXQI7DsSv18,2783
|
19
19
|
py2ls/.git/hooks/update.sample,sha256=jV8vqD4QPPCLV-qmdSHfkZT0XL28s32lKtWGCXoU0QY,3650
|
20
|
-
py2ls/.git/index,sha256=
|
20
|
+
py2ls/.git/index,sha256=2psUA1HSf13h_hMIjiDXo3a-eKs7JT7vYt6myqyT568,4232
|
21
21
|
py2ls/.git/info/exclude,sha256=ZnH-g7egfIky7okWTR8nk7IxgFjri5jcXAbuClo7DsE,240
|
22
22
|
py2ls/.git/logs/HEAD,sha256=8ID7WuAe_TlO9g-ARxhIJYdgdL3u3m7-1qrOanaIUlA,3535
|
23
23
|
py2ls/.git/logs/refs/heads/main,sha256=8ID7WuAe_TlO9g-ARxhIJYdgdL3u3m7-1qrOanaIUlA,3535
|
@@ -234,17 +234,18 @@ py2ls/export_requirements.py,sha256=x2WgUF0jYKz9GfA1MVKN-MdsM-oQ8yUeC6Ua8oCymio,
|
|
234
234
|
py2ls/fetch_update.py,sha256=9LXj661GpCEFII2wx_99aINYctDiHni6DOruDs_fdt8,4752
|
235
235
|
py2ls/freqanalysis.py,sha256=F4218VSPbgL5tnngh6xNCYuNnfR-F_QjECUUxrPYZss,32594
|
236
236
|
py2ls/ich2ls.py,sha256=3E9R8oVpyYZXH5PiIQgT3CN5NxLe4Dwtm2LwaeacE6I,21381
|
237
|
-
py2ls/ips.py,sha256=
|
238
|
-
py2ls/ml2ls.py,sha256=
|
237
|
+
py2ls/ips.py,sha256=YlBLv69l2ILYO9jGqHZss7AydNHCoq51qqu3b443cv0,297616
|
238
|
+
py2ls/ml2ls copy.py,sha256=iZJrFLIrdfTieAY2BDsxQFTm29smwnJh0aC4hRB9VGM,113314
|
239
|
+
py2ls/ml2ls.py,sha256=ldNxpo7JKekDai5Izn0pk1wQ1fcNFHZx0huoK_ypfvw,142109
|
239
240
|
py2ls/mol.py,sha256=AZnHzarIk_MjueKdChqn1V6e4tUle3X1NnHSFA6n3Nw,10645
|
240
241
|
py2ls/netfinder.py,sha256=R70NkrnO8LlXjT1y7bf2TN-yE4yOeAYhb0jDBiNp8XA,57536
|
241
242
|
py2ls/ocr.py,sha256=5lhUbJufIKRSOL6wAWVLEo8TqMYSjoI_Q-IO-_4u3DE,31419
|
242
|
-
py2ls/plot.py,sha256=
|
243
|
+
py2ls/plot.py,sha256=jFBglmV-czTxGlmhZ4VhGzN5shnYw3hFV2JoosoSW9U,190457
|
243
244
|
py2ls/setuptools-70.1.0-py3-none-any.whl,sha256=2bi3cUVal8ip86s0SOvgspteEF8SKLukECi-EWmFomc,882588
|
244
245
|
py2ls/sleep_events_detectors.py,sha256=bQA3HJqv5qnYKJJEIhCyhlDtkXQfIzqksnD0YRXso68,52145
|
245
246
|
py2ls/stats.py,sha256=qBn2rJmNa_QLLUqjwYqXUlGzqmW94sgA1bxJU2FC3r0,39175
|
246
247
|
py2ls/translator.py,sha256=77Tp_GjmiiwFbEIJD_q3VYpQ43XL9ZeJo6Mhl44mvh8,34284
|
247
248
|
py2ls/wb_detector.py,sha256=7y6TmBUj9exCZeIgBAJ_9hwuhkDh1x_-yg4dvNY1_GQ,6284
|
248
|
-
py2ls-0.2.4.
|
249
|
-
py2ls-0.2.4.
|
250
|
-
py2ls-0.2.4.
|
249
|
+
py2ls-0.2.4.16.dist-info/METADATA,sha256=z431Uha36h4d6syqBxzeNEsOwrXAp2yCya_q19-hoYo,20046
|
250
|
+
py2ls-0.2.4.16.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
251
|
+
py2ls-0.2.4.16.dist-info/RECORD,,
|
File without changes
|