rgwfuncs 0.0.51__py3-none-any.whl → 0.0.52__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.
rgwfuncs/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # This file is automatically generated
2
2
  # Dynamically importing functions from modules
3
3
 
4
- from .algebra_lib import cancel_polynomial_expression, compute_constant_expression, compute_constant_expression_involving_matrices, compute_constant_expression_involving_ordered_series, compute_prime_factors, expand_polynomial_expression, factor_polynomial_expression, python_polynomial_expression_to_latex, simplify_polynomial_expression, solve_homogeneous_polynomial_expression
4
+ from .algebra_lib import cancel_polynomial_expression, compute_constant_expression, compute_constant_expression_involving_matrices, compute_constant_expression_involving_ordered_series, compute_prime_factors, expand_polynomial_expression, factor_polynomial_expression, plot_polynomial_functions, python_polynomial_expression_to_latex, simplify_polynomial_expression, solve_homogeneous_polynomial_expression
5
5
  from .df_lib import append_columns, append_percentile_classification_column, append_ranged_classification_column, append_ranged_date_classification_column, append_rows, append_xgb_labels, append_xgb_logistic_regression_predictions, append_xgb_regression_predictions, bag_union_join, bottom_n_unique_values, cascade_sort, delete_rows, drop_duplicates, drop_duplicates_retain_first, drop_duplicates_retain_last, filter_dataframe, filter_indian_mobiles, first_n_rows, from_raw_data, insert_dataframe_in_sqlite_database, last_n_rows, left_join, limit_dataframe, load_data_from_path, load_data_from_query, load_data_from_sqlite_path, mask_against_dataframe, mask_against_dataframe_converse, numeric_clean, order_columns, print_correlation, print_dataframe, print_memory_usage, print_n_frequency_cascading, print_n_frequency_linear, rename_columns, retain_columns, right_join, send_data_to_email, send_data_to_slack, send_dataframe_via_telegram, sync_dataframe_to_sqlite_database, top_n_unique_values, union_join, update_rows
6
6
  from .docs_lib import docs
7
7
  from .interactive_shell_lib import interactive_shell
rgwfuncs/algebra_lib.py CHANGED
@@ -8,7 +8,12 @@ from sympy.parsing.sympy_parser import parse_expr
8
8
  from sympy import __all__ as sympy_functions
9
9
  from sympy.parsing.sympy_parser import (standard_transformations, implicit_multiplication_application)
10
10
 
11
- from typing import Tuple, List, Dict, Optional
11
+ from typing import Tuple, List, Dict, Optional, Any
12
+
13
+
14
+ import numpy as np
15
+ import matplotlib.pyplot as plt
16
+ from io import BytesIO
12
17
 
13
18
 
14
19
  def compute_prime_factors(n: int) -> str:
@@ -285,7 +290,6 @@ def python_polynomial_expression_to_latex(
285
290
  Raises:
286
291
  ValueError: If the expression cannot be parsed due to syntax errors.
287
292
  """
288
-
289
293
  transformations = standard_transformations + (implicit_multiplication_application,)
290
294
 
291
295
  def parse_and_convert_expression(expr_str: str, sym_vars: Dict[str, Expr]) -> Expr:
@@ -701,3 +705,145 @@ def solve_homogeneous_polynomial_expression(
701
705
 
702
706
  except Exception as e:
703
707
  raise ValueError(f"Error solving the expression: {e}")
708
+
709
+
710
+ def plot_polynomial_functions(
711
+ functions: List[Dict[str, Dict[str, Any]]],
712
+ zoom: float = 10.0,
713
+ show_legend: bool = True
714
+ ) -> str:
715
+ """
716
+ Plots expressions described by a list of dictionaries of the form:
717
+ [
718
+ { "expression_string": { "x": "*", "a":..., "b":... } },
719
+ { "expression_string": { "x": np.linspace(...), "a":..., ... } },
720
+ ...
721
+ ]
722
+
723
+ In each top-level dictionary, there is exactly one key (a string
724
+ representing a Python/NumPy expression) and one value (a dictionary of
725
+ substitutions). This substitutions dictionary must have an "x" key:
726
+ • "x": "*" -> Use a default domain from -zoom..+zoom.
727
+ • "x": np.array(...) -> Use that array as the domain.
728
+ Other variables (like "a", "b", etc.) may also appear in the same dict.
729
+
730
+ Additionally, we use latexify_expression(...) to transform the expression
731
+ into a nice LaTeX form for the legend, including a special Δ notation for np.diff(...).
732
+
733
+ Parameters
734
+ ----------
735
+ functions : List[Dict[str, Dict[str, Any]]]
736
+ A list of items. Each item is a dictionary:
737
+ key = expression string (e.g., "x**2", "np.diff(x,2)", etc.)
738
+ value = a dictionary of substitutions. Must contain "x",
739
+ either as "*" or a NumPy array. May contain additional
740
+ parameters like "a", "b", etc.
741
+ zoom : float
742
+ Sets the numeric axis range from -zoom..+zoom in both x and y.
743
+ show_legend : bool
744
+ Whether to add a legend to the plot (defaults to True).
745
+
746
+ Returns
747
+ -------
748
+ str
749
+ The raw SVG markup of the resulting plot.
750
+ """
751
+
752
+ def latexify_expression(expr_str: str) -> str:
753
+ # Regex to locate np.diff(...) with an optional second argument
754
+ DIFF_PATTERN = r"np\.diff\s*\(\s*([^,\)]+)(?:,\s*(\d+))?\)"
755
+
756
+ def diff_replacer(match: re.Match) -> str:
757
+ inside = match.group(1).strip()
758
+ exponent = match.group(2)
759
+ inside_no_np = inside.replace("np.", "")
760
+ if exponent:
761
+ return rf"\Delta^{exponent}\left({inside_no_np}\right)"
762
+ else:
763
+ return rf"\Delta\left({inside_no_np}\right)"
764
+
765
+ expr_tmp = re.sub(DIFF_PATTERN, diff_replacer, expr_str)
766
+ expr_tmp = expr_tmp.replace("np.", "")
767
+ try:
768
+ latex_expr = python_polynomial_expression_to_latex(expr_tmp)
769
+ return latex_expr
770
+ except Exception:
771
+ # Fallback: just do naive **
772
+ return expr_tmp.replace("**", "^")
773
+
774
+ buffer = BytesIO()
775
+ fig, ax = plt.subplots()
776
+
777
+ for entry in functions:
778
+ if len(entry) != 1:
779
+ print("Skipping invalid item. Must have exactly 1 expression->substitutions pair.")
780
+ continue
781
+
782
+ expression, sub_dict = list(entry.items())[0]
783
+ if "x" not in sub_dict:
784
+ print(f"Skipping '{expression}' because sub-dict lacks 'x' key.")
785
+ continue
786
+
787
+ # If "x" is "*", create a default domain
788
+ x_val = sub_dict["x"]
789
+ if isinstance(x_val, str) and x_val == "*":
790
+ x_values = np.linspace(-zoom, zoom, 1201)
791
+ sub_dict["x"] = x_values
792
+ elif isinstance(x_val, np.ndarray):
793
+ x_values = x_val
794
+ else:
795
+ print(f"Skipping '{expression}' because 'x' is neither '*' nor a NumPy array.")
796
+ continue
797
+
798
+ # Evaluate the expression
799
+ try:
800
+ eval_context = {"np": np}
801
+ eval_context.update(sub_dict)
802
+ y_values = eval(expression, {"np": np}, eval_context)
803
+ except Exception as e:
804
+ print(f"Error evaluating expression '{expression}': {e}")
805
+ continue
806
+
807
+ if not isinstance(y_values, np.ndarray):
808
+ print(f"Skipping '{expression}' because it did not produce a NumPy array.")
809
+ continue
810
+
811
+ # If y_values is shorter than x_values (like np.diff), truncate x
812
+ if len(y_values) < len(x_values):
813
+ x_values = x_values[:len(y_values)]
814
+
815
+ # Convert expression to a nice LaTeX string
816
+ label_expr = latexify_expression(expression)
817
+ ax.plot(x_values, y_values, label=rf"${label_expr}$")
818
+
819
+ # Configure axes
820
+ ax.set_xlim(-zoom, zoom)
821
+ ax.set_ylim(-zoom, zoom)
822
+ ax.spines['left'].set_position('zero')
823
+ ax.spines['bottom'].set_position('zero')
824
+ ax.spines['right'].set_color('none')
825
+ ax.spines['top'].set_color('none')
826
+ ax.set_aspect('equal', 'box')
827
+ ax.xaxis.set_ticks_position('bottom')
828
+ ax.yaxis.set_ticks_position('left')
829
+ ax.grid(True)
830
+
831
+ # Show legend
832
+ if show_legend:
833
+ leg = ax.legend(
834
+ loc='upper center',
835
+ bbox_to_anchor=(0.5, -0.03),
836
+ fancybox=True,
837
+ shadow=True,
838
+ ncol=1
839
+ )
840
+ plt.savefig(
841
+ buffer,
842
+ format='svg',
843
+ bbox_inches='tight',
844
+ bbox_extra_artists=[leg] # ensures the legend is fully captured
845
+ )
846
+ else:
847
+ plt.savefig(buffer, format='svg', bbox_inches='tight')
848
+ plt.close(fig)
849
+ return buffer.getvalue().decode('utf-8')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rgwfuncs
3
- Version: 0.0.51
3
+ Version: 0.0.52
4
4
  Summary: A functional programming paradigm for mathematical modelling and data science
5
5
  Home-page: https://github.com/ryangerardwilson/rgwfunc
6
6
  Author: Ryan Gerard Wilson
@@ -514,6 +514,45 @@ Solves a homogeneous polynomial expression for a specified variable and returns
514
514
 
515
515
  --------------------------------------------------------------------------------
516
516
 
517
+ ### 11. `plot_polynomial_functions`
518
+
519
+ This function plots polynomial functions described by a list of expressions and their corresponding substitution dictionaries. It generates SVG markup of the plots, with options for specifying the domain, axis zoom, and legend display.
520
+
521
+ • Parameters:
522
+ - `functions` (`List[Dict[str, Dict[str, Any]]]`): A list of dictionaries, each containing:
523
+ - A key which is a string representing a Python/NumPy expression (e.g., `"x**2"`, `"np.diff(x,2)"`).
524
+ - A value which is a dictionary containing substitutions for the expression. Must include an `"x"` key, either as `"*"` for default domain or a NumPy array.
525
+ - `zoom` (`float`): Determines the numeric axis range from `-zoom` to `+zoom` for both x and y axes (default is `10.0`).
526
+ - `show_legend` (`bool`): Specifies whether to include a legend in the plot (default is `True`).
527
+
528
+ • Returns:
529
+ - `str`: The raw SVG markup of the resulting plot.
530
+
531
+ • Example:
532
+
533
+ import subprocess
534
+ from rgwfuncs import plot_polynomial_functions
535
+
536
+ # Generate the SVG
537
+ plot_svg_string = plot_polynomial_functions(
538
+ functions=[
539
+ {"x**2": {"x": "*"}}, # Single expression, "*" means plot all discernable points
540
+ {"x**2/(2 + a) + a": {"x": np.linspace(-3, 4, 101), "a": 1.23}},
541
+ {"np.diff(x**3, 2)": {"x": np.linspace(-2, 2, 10)}}
542
+ ],
543
+ zoom=2
544
+ )
545
+
546
+ # Write the SVG to an actual file
547
+ with open("plot.svg", "w", encoding="utf-8") as file:
548
+ file.write(plot_svg_string)
549
+
550
+ • Displaying the SVG:
551
+
552
+ ![Plot](./media/plot_polynomial_functions_example_1.svg)
553
+
554
+ --------------------------------------------------------------------------------
555
+
517
556
  ## String Based Functions
518
557
 
519
558
  ### 1. send_telegram_message
@@ -0,0 +1,12 @@
1
+ rgwfuncs/__init__.py,sha256=JjkuVeRV_Bkw8vnqSbJsRcYQRm4iCI3futR86cf3tRI,1637
2
+ rgwfuncs/algebra_lib.py,sha256=-Q2W63EtRLhwOvGGFuf8KUKVuoLA72ONt-wPhcX6R94,33408
3
+ rgwfuncs/df_lib.py,sha256=qqRQdakheLy8wMZRBfHwKyIp8DmdZIWfAiLKWgq03QU,68977
4
+ rgwfuncs/docs_lib.py,sha256=y3wSAOPO3qsA4HZ7xAtW8HimM8w-c8hjcEzMRLJ96ao,1960
5
+ rgwfuncs/interactive_shell_lib.py,sha256=A7EWsYxAfDev_N0-2GjRvAtp0bAwBPHIczXb8Gu9fzI,1107
6
+ rgwfuncs/str_lib.py,sha256=rtAdRlnSJIu3JhI-tA_A0wCiPK2m-zn5RoGpBxv_g-4,2228
7
+ rgwfuncs-0.0.52.dist-info/LICENSE,sha256=7EI8xVBu6h_7_JlVw-yPhhOZlpY9hP8wal7kHtqKT_E,1074
8
+ rgwfuncs-0.0.52.dist-info/METADATA,sha256=ByUIjumG8zZCcuKbS0d9Ipq5VH0rBfAAumeRHQ5SR90,56826
9
+ rgwfuncs-0.0.52.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
10
+ rgwfuncs-0.0.52.dist-info/entry_points.txt,sha256=j-c5IOPIQ0252EaOV6j6STio56sbXl2C4ym_fQ0lXx0,43
11
+ rgwfuncs-0.0.52.dist-info/top_level.txt,sha256=aGuVIzWsKiV1f2gCb6mynx0zx5ma0B1EwPGFKVEMTi4,9
12
+ rgwfuncs-0.0.52.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- rgwfuncs/__init__.py,sha256=vs8xv3IVx7KGpPxEXrIePD3gb_QI1XTXpD_n9817foA,1610
2
- rgwfuncs/algebra_lib.py,sha256=sLQUxXG4mNNO55XclTgIrwVrg5LbwELOFsiSAm_9G20,28212
3
- rgwfuncs/df_lib.py,sha256=qqRQdakheLy8wMZRBfHwKyIp8DmdZIWfAiLKWgq03QU,68977
4
- rgwfuncs/docs_lib.py,sha256=y3wSAOPO3qsA4HZ7xAtW8HimM8w-c8hjcEzMRLJ96ao,1960
5
- rgwfuncs/interactive_shell_lib.py,sha256=A7EWsYxAfDev_N0-2GjRvAtp0bAwBPHIczXb8Gu9fzI,1107
6
- rgwfuncs/str_lib.py,sha256=rtAdRlnSJIu3JhI-tA_A0wCiPK2m-zn5RoGpBxv_g-4,2228
7
- rgwfuncs-0.0.51.dist-info/LICENSE,sha256=7EI8xVBu6h_7_JlVw-yPhhOZlpY9hP8wal7kHtqKT_E,1074
8
- rgwfuncs-0.0.51.dist-info/METADATA,sha256=Q-t10jPxJYG_orABThvIy6q1-WQvwOYwe_3TNLuLYRw,55152
9
- rgwfuncs-0.0.51.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
10
- rgwfuncs-0.0.51.dist-info/entry_points.txt,sha256=j-c5IOPIQ0252EaOV6j6STio56sbXl2C4ym_fQ0lXx0,43
11
- rgwfuncs-0.0.51.dist-info/top_level.txt,sha256=aGuVIzWsKiV1f2gCb6mynx0zx5ma0B1EwPGFKVEMTi4,9
12
- rgwfuncs-0.0.51.dist-info/RECORD,,