py2ls 0.2.4.15__py3-none-any.whl → 0.2.4.16__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/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
- plt.tight_layout()
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
- kind: Union[str, list] = "scatter", # Specify the kind of plot
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 kind is not None:
3159
- if isinstance(kind, str):
3160
- kind = [kind]
3161
- kind = [strcmp(i, valid_kinds)[0] for i in kind]
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 kind is not None:
3167
- for k in kind:
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
- kind=["scatter","rug"],
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 kind:
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
- g = sns.lmplot(data=data, x=x, y=y, **kws_lm)
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
- ax = sns.regplot(data=data, x=x, y=y, ax=ax, zorder=zorder, **kws_reg)
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(60):
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 run_once_within():
4428
+ if verbose:
4129
4429
  print(
4130
- f"usage:\n\tnexttile = subplot(2, 2, figsize=(5, 5), sharex=True, sharey=True)\n\tax = nexttile()"
4430
+ f"usage:\n\tnexttile = subplot(2, 2, figsize=(5, 5), sharex=False, sharey=False)\n\tax = nexttile()"
4131
4431
  )
4132
- fig = plt.figure(figsize=figsize)
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
- title="Radar Chart",
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: py2ls
3
- Version: 0.2.4.15
3
+ Version: 0.2.4.16
4
4
  Summary: py(thon)2(too)ls
5
5
  Author: Jianfeng
6
6
  Author-email: Jianfeng.Liu0413@gmail.com
@@ -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=CwYqVYvTvnn8cGWn-ctzQIfhmbgRfxtYXrAkmCA1AuU,4232
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=O2QdLo6-vPbHvWtlVdtMA49LAn2y0CNVM27cxLbqqYA,271496
238
- py2ls/ml2ls.py,sha256=LutEbrIF2KcBdz8jnbR3EZ4WTjRTuVGPvskUsuX2ZoA,128551
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=X0R1KK_UTdeJazjnqTqYvP-uWu6wY8szQHyJMsDDz2s,171515
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.15.dist-info/METADATA,sha256=MbwWj3zOohusA3UxDrIgR6S3Zms5tdWbcWjw9-dA57U,20046
249
- py2ls-0.2.4.15.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
250
- py2ls-0.2.4.15.dist-info/RECORD,,
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,,