py2ls 0.1.9.1__py3-none-any.whl → 0.1.9.2__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
@@ -10,6 +10,7 @@ from cycler import cycler
10
10
  import logging
11
11
  import os
12
12
  from .ips import fsave, fload, mkdir
13
+ from .stats import *
13
14
 
14
15
  # Suppress INFO messages from fontTools
15
16
  logging.getLogger("fontTools").setLevel(logging.WARNING)
@@ -220,8 +221,11 @@ def catplot(data, *args, **kwargs):
220
221
  # MeanLine or MedianLine only keep only one
221
222
  if bx_opt["MeanLine"]: # MeanLine has priority
222
223
  bx_opt["MedianLine"] = False
224
+ # rm NaNs
225
+ cleaned_data = [data[~np.isnan(data[:, i]), i] for i in range(data.shape[1])]
226
+
223
227
  bxp = ax.boxplot(
224
- data,
228
+ cleaned_data,
225
229
  positions=X_bx,
226
230
  notch=bx_opt["Notch"],
227
231
  patch_artist=True,
@@ -488,7 +492,33 @@ def catplot(data, *args, **kwargs):
488
492
  default_x_width = 0.85
489
493
  legend_hue = df[hue].unique().tolist()
490
494
  default_colors = get_color(hue_len)
495
+
496
+ # ! stats info
497
+ stats_param = kwargs.get("stats", False)
498
+ res = pd.DataFrame() # Initialize an empty DataFrame to store results
499
+ for i in df[x].unique().tolist():
500
+ print(i)
501
+ if hue and stats_param:
502
+ if isinstance(stats_param, dict):
503
+ if "factor" in stats_param.keys():
504
+ res_tmp = FuncMultiCmpt(data=df, dv=y, **stats_param)
505
+ else:
506
+ res_tmp = FuncMultiCmpt(
507
+ data=df[df[x] == i], dv=y, factor=hue, **stats_param
508
+ )
509
+ elif bool(stats_param):
510
+ res_tmp = FuncMultiCmpt(data=df, dv=y, factor=hue)
511
+ else:
512
+ res_tmp = "did not work properly"
513
+ display_output(res_tmp)
514
+ res_tmp = [{"x": i, **res_tmp}]
515
+ res = pd.concat(
516
+ [res, pd.DataFrame([res_tmp])], ignore_index=True
517
+ )
518
+ display_output(res)
491
519
  else:
520
+ # ! stats info
521
+ stats_param = kwargs.get("stats", False)
492
522
  for i in df[x].unique().tolist():
493
523
  xticklabels.append(i)
494
524
  xticks = np.arange(1, len(xticklabels) + 1).tolist()
@@ -496,9 +526,17 @@ def catplot(data, *args, **kwargs):
496
526
  legend_hue = xticklabels
497
527
  default_colors = get_color(len(xticklabels))
498
528
  default_x_width = 0.5
529
+ res = None
530
+ if x and stats_param:
531
+ if isinstance(stats_param, dict):
532
+ res = FuncMultiCmpt(data=df, dv=y, factor=x, **stats_param)
533
+ elif bool(stats_param):
534
+ res = FuncMultiCmpt(data=df, dv=y, factor=x)
535
+ else:
536
+ res = "did not work properly"
537
+ display_output(res)
499
538
 
500
539
  # when the xticklabels are too long, rotate the labels a bit
501
-
502
540
  xangle = 30 if max([len(i) for i in xticklabels]) > 50 else 0
503
541
  if kw_figsets is not None:
504
542
  kw_figsets = {
@@ -526,6 +564,22 @@ def catplot(data, *args, **kwargs):
526
564
 
527
565
  # full_order
528
566
  opt = kwargs.get("opt", {})
567
+
568
+ # load style:
569
+ style_use = None
570
+ for k, v in kwargs.items():
571
+ if "style" in k and "exp" not in k:
572
+ style_use = v
573
+ break
574
+ if style_use:
575
+ try:
576
+ dir_curr_script = os.path.dirname(os.path.abspath(__file__))
577
+ dir_style = dir_curr_script + "/data/styles/"
578
+ style_load = fload(dir_style + style_use + ".json")
579
+ style_load = remove_colors_in_dict(style_load)
580
+ opt.update(style_load)
581
+ except:
582
+ print(f"cannot find the style'{style_name}'")
529
583
  ax = kwargs.get("ax", None)
530
584
  if "ax" not in locals() or ax is None:
531
585
  ax = plt.gca()
@@ -654,16 +708,6 @@ def catplot(data, *args, **kwargs):
654
708
  opt["v"].setdefault("NumPoints", 500)
655
709
  opt["v"].setdefault("BoundaryCorrection", "reflection")
656
710
 
657
- # load style:
658
- style_use = kwargs.get("style_use", None)
659
- if style_use:
660
- try:
661
- dir_curr_script = os.path.dirname(os.path.abspath(__file__))
662
- dir_style = dir_curr_script + "/data/styles/"
663
- style_load = fload(dir_style + style_use + ".json")
664
- opt.update(style_load)
665
- except:
666
- print(f"cannot find the style'{style_name}'")
667
711
  data_m = np.nanmean(data, axis=0)
668
712
  nr, nc = data.shape
669
713
 
@@ -692,7 +736,6 @@ def catplot(data, *args, **kwargs):
692
736
  legend_which = "v"
693
737
  else:
694
738
  legend_which = None
695
-
696
739
  for layer in layers:
697
740
  if layer == "b" and opt["b"]["go"]:
698
741
  if legend_which == "b":
@@ -721,8 +764,7 @@ def catplot(data, *args, **kwargs):
721
764
  plot_violin(data, opt["v"], xloc, ax, label=None)
722
765
  elif all([layer == "l", opt["l"]["go"], opt["s"]["go"]]):
723
766
  plot_lines(data, opt["l"], opt["s"], ax)
724
- else:
725
- print("layers run some problems")
767
+
726
768
  if kw_figsets is not None:
727
769
  figsets(ax=ax, **kw_figsets)
728
770
  show_legend = kwargs.get("show_legend", True)
@@ -734,6 +776,7 @@ def catplot(data, *args, **kwargs):
734
776
  dir_curr_script = os.path.dirname(os.path.abspath(__file__))
735
777
  dir_style = dir_curr_script + "/data/styles/"
736
778
  fsave(dir_style + style_export + ".json", opt)
779
+
737
780
  return ax, opt
738
781
  else:
739
782
  col_names = data[col].unique().tolist()
@@ -750,7 +793,10 @@ def catplot(data, *args, **kwargs):
750
793
  if i < len(col_names):
751
794
  df_sub = data.loc[data[col] == col_names[i]]
752
795
  _, opt = catplot(ax=ax, data=df_sub, **kwargs)
753
- ax.set_title(col_names[i])
796
+ ax.set_title(f"{col}={col_names[i]}")
797
+ x_label = kwargs.get("x", None)
798
+ if x_label:
799
+ ax.set_xlabel(x_label)
754
800
  print(f"Axis layout shape: {axs.shape}")
755
801
  return axs, opt
756
802
 
@@ -1530,175 +1576,6 @@ def add_colorbar(im, width=None, pad=None, **kwargs):
1530
1576
  return fig.colorbar(im, cax=cax, **kwargs) # draw cbar
1531
1577
 
1532
1578
 
1533
- # def padcat(*args, fill_value=np.nan, axis=1):
1534
- # """
1535
- # Concatenate vectors with padding.
1536
-
1537
- # Parameters:
1538
- # *args : variable number of list or 1D arrays
1539
- # Input arrays to concatenate.
1540
- # fill_value : scalar, optional
1541
- # The value to use for padding the shorter lists (default is np.nan).
1542
- # axis : int, optional
1543
- # The axis along which to concatenate (0 for rows, 1 for columns, default is 0).
1544
-
1545
- # Returns:
1546
- # np.ndarray
1547
- # A 2D array with the input arrays concatenated along the specified axis, padded with fill_value where necessary.
1548
- # """
1549
- # if axis == 0:
1550
- # # Concatenate along rows
1551
- # max_len = max(len(lst) for lst in args)
1552
- # result = np.full((len(args), max_len), fill_value)
1553
- # for i, lst in enumerate(args):
1554
- # result[i, : len(lst)] = lst
1555
- # elif axis == 1:
1556
- # # Concatenate along columns
1557
- # max_len = max(len(lst) for lst in args)
1558
- # result = np.full((max_len, len(args)), fill_value)
1559
- # for i, lst in enumerate(args):
1560
- # result[: len(lst), i] = lst
1561
- # else:
1562
- # raise ValueError("axis must be 0 or 1")
1563
-
1564
- # return result
1565
- import numpy as np
1566
-
1567
-
1568
- def padcat(*args, fill_value=np.nan, axis=1, order="row"):
1569
- """
1570
- Concatenate vectors with padding.
1571
-
1572
- Parameters:
1573
- *args : variable number of list or 1D arrays
1574
- Input arrays to concatenate.
1575
- fill_value : scalar, optional
1576
- The value to use for padding the shorter lists (default is np.nan).
1577
- axis : int, optional
1578
- The axis along which to concatenate (0 for rows, 1 for columns, default is 1).
1579
- order : str, optional
1580
- The order for flattening when required: "row" or "column" (default is "row").
1581
-
1582
- Returns:
1583
- np.ndarray
1584
- A 2D array with the input arrays concatenated along the specified axis,
1585
- padded with fill_value where necessary.
1586
- """
1587
- # Set the order for processing
1588
- if "ro" in order.lower():
1589
- order = "C" # row-major order
1590
- else:
1591
- order = "F" # column-major order
1592
-
1593
- # Process input arrays based on their dimensions
1594
- processed_arrays = []
1595
- for arg in args:
1596
- arr = np.asarray(arg)
1597
- if arr.ndim == 1:
1598
- processed_arrays.append(arr) # Keep 1D arrays as is
1599
- elif arr.ndim == 2:
1600
- if axis == 0:
1601
- # If concatenating along rows, split 2D arrays into 1D arrays row-wise
1602
- processed_arrays.extend(arr)
1603
- elif axis == 1:
1604
- # If concatenating along columns, split 2D arrays into 1D arrays column-wise
1605
- processed_arrays.extend(arr.T)
1606
- else:
1607
- raise ValueError("axis must be 0 or 1")
1608
- else:
1609
- raise ValueError("Input arrays must be 1D or 2D")
1610
-
1611
- if axis == 0:
1612
- # Concatenate along rows
1613
- max_len = max(arr.size for arr in processed_arrays)
1614
- result = np.full((len(processed_arrays), max_len), fill_value)
1615
- for i, arr in enumerate(processed_arrays):
1616
- result[i, : arr.size] = arr
1617
- elif axis == 1:
1618
- # Concatenate along columns
1619
- max_len = max(arr.size for arr in processed_arrays)
1620
- result = np.full((max_len, len(processed_arrays)), fill_value)
1621
- for i, arr in enumerate(processed_arrays):
1622
- result[: arr.size, i] = arr
1623
- else:
1624
- raise ValueError("axis must be 0 or 1")
1625
-
1626
- return result
1627
-
1628
-
1629
- # # Example usage:
1630
- # a = [1, np.nan]
1631
- # b = [1, 3, 4, np.nan, 2, np.nan]
1632
- # c = [1, 2, 3, 4, 5, 6, 7, 8, 10]
1633
- # d = padcat(a, b)
1634
- # result1 = padcat(d, c)
1635
- # result2 = padcat(a, b, c)
1636
- # print("Result of padcat(d, c):\n", result1)
1637
- # print("Result of padcat(a, b, c):\n", result2)
1638
-
1639
-
1640
- def sort_rows_move_nan(arr, sort=False):
1641
- # Handle edge cases where all values are NaN
1642
- if np.all(np.isnan(arr)):
1643
- return arr # Return unchanged if the entire array is NaN
1644
-
1645
- if sort:
1646
- # Replace NaNs with a temporary large value for sorting
1647
- temp_value = (
1648
- np.nanmax(arr[np.isfinite(arr)]) + 1 if np.any(np.isfinite(arr)) else np.inf
1649
- )
1650
- arr_no_nan = np.where(np.isnan(arr), temp_value, arr)
1651
-
1652
- # Sort each row
1653
- sorted_arr = np.sort(arr_no_nan, axis=1)
1654
-
1655
- # Move NaNs to the end
1656
- result_arr = np.where(sorted_arr == temp_value, np.nan, sorted_arr)
1657
- else:
1658
- result_rows = []
1659
- for row in arr:
1660
- # Separate non-NaN and NaN values
1661
- non_nan_values = row[~np.isnan(row)]
1662
- nan_count = np.isnan(row).sum()
1663
- # Create a new row with non-NaN values followed by NaNs
1664
- new_row = np.concatenate([non_nan_values, [np.nan] * nan_count])
1665
- result_rows.append(new_row)
1666
- # Convert the list of rows back into a 2D NumPy array
1667
- result_arr = np.array(result_rows)
1668
-
1669
- # Remove rows/columns that contain only NaNs
1670
- clean_arr = result_arr[~np.isnan(result_arr).all(axis=1)]
1671
- clean_arr_ = clean_arr[:, ~np.isnan(clean_arr).all(axis=0)]
1672
-
1673
- return clean_arr_
1674
-
1675
-
1676
- def df2array(data: pd.DataFrame, x, y, hue=None, sort=False):
1677
- if hue is None:
1678
- a = []
1679
- if sort:
1680
- np.sort(data[x].unique().tolist()).tolist()
1681
- else:
1682
- cat_x = data[x].unique().tolist()
1683
- for i, x_ in enumerate(cat_x):
1684
- new_ = data.loc[data[x] == x_, y].to_list()
1685
- a = padcat(a, new_, axis=0)
1686
- return sort_rows_move_nan(a).T
1687
- else:
1688
- a = []
1689
- if sort:
1690
- cat_x = np.sort(data[x].unique().tolist()).tolist()
1691
- cat_hue = np.sort(data[hue].unique().tolist()).tolist()
1692
- else:
1693
- cat_x = data[x].unique().tolist()
1694
- cat_hue = data[hue].unique().tolist()
1695
- for i, x_ in enumerate(cat_x):
1696
- for j, hue_ in enumerate(cat_hue):
1697
- new_ = data.loc[(data[x] == x_) & (data[hue] == hue_), y].to_list()
1698
- a = padcat(a, new_, axis=0)
1699
- return sort_rows_move_nan(a).T
1700
-
1701
-
1702
1579
  def generate_xticks_with_gap(x_len, hue_len):
1703
1580
  """
1704
1581
  Generate a concatenated array based on x_len and hue_len,
@@ -1728,3 +1605,18 @@ def generate_xticks_x_labels(x_len, hue_len):
1728
1605
  for i in range(max(x_len, hue_len), 0, -1) # i iterates from 3 to 1
1729
1606
  ]
1730
1607
  return [np.mean(i) for i in arrays if np.mean(i) > 0]
1608
+
1609
+
1610
+ def remove_colors_in_dict(
1611
+ data: dict, sections_to_remove_facecolor=["b", "e", "s", "bx", "v"]
1612
+ ):
1613
+ # Remove "FaceColor" from specified sections
1614
+ for section in sections_to_remove_facecolor:
1615
+ if section in data and ("FaceColor" in data[section]):
1616
+ del data[section]["FaceColor"]
1617
+
1618
+ if "c" in data:
1619
+ del data["c"]
1620
+ if "loc" in data:
1621
+ del data["loc"]
1622
+ return data