py2ls 0.2.4.14__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/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
py2ls/translator.py CHANGED
@@ -586,6 +586,8 @@ def replace_text(text, dict_replace=None, robust=True):
586
586
  Returns:
587
587
  str: The text after replacements have been made.
588
588
  """
589
+ if not all(text):
590
+ return ''
589
591
  # Default replacements for newline and tab characters
590
592
  default_replacements = {
591
593
  "\a": "",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: py2ls
3
- Version: 0.2.4.14
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=LovnWDV9ptdWuWwJF5EEdf3sGY4EniGBBNxRJJbzStw,112784
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
- py2ls/translator.py,sha256=zBeq4pYZeroqw3DT-5g7uHfVqKd-EQptT6LJ-Adi8JY,34244
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.14.dist-info/METADATA,sha256=SSjNh_FXmxwIF_Xx2fZvSGKZaX997x4sfJxUQckMuGY,20046
249
- py2ls-0.2.4.14.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
250
- py2ls-0.2.4.14.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,,