rgwfuncs 0.0.51__py3-none-any.whl → 0.0.53__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,14 +1,18 @@
1
1
  import re
2
2
  import math
3
3
  import ast
4
+ import subprocess
5
+ import tempfile
4
6
  from sympy import symbols, latex, simplify, solve, diff, Expr, factor, cancel, Eq
5
7
  from sympy.core.sympify import SympifyError
6
8
  from sympy.core import S
7
9
  from sympy.parsing.sympy_parser import parse_expr
8
10
  from sympy import __all__ as sympy_functions
9
11
  from sympy.parsing.sympy_parser import (standard_transformations, implicit_multiplication_application)
10
-
11
- from typing import Tuple, List, Dict, Optional
12
+ from typing import Tuple, List, Dict, Optional, Any
13
+ import numpy as np
14
+ import matplotlib.pyplot as plt
15
+ from io import BytesIO
12
16
 
13
17
 
14
18
  def compute_prime_factors(n: int) -> str:
@@ -285,7 +289,6 @@ def python_polynomial_expression_to_latex(
285
289
  Raises:
286
290
  ValueError: If the expression cannot be parsed due to syntax errors.
287
291
  """
288
-
289
292
  transformations = standard_transformations + (implicit_multiplication_application,)
290
293
 
291
294
  def parse_and_convert_expression(expr_str: str, sym_vars: Dict[str, Expr]) -> Expr:
@@ -701,3 +704,184 @@ def solve_homogeneous_polynomial_expression(
701
704
 
702
705
  except Exception as e:
703
706
  raise ValueError(f"Error solving the expression: {e}")
707
+
708
+
709
+ def plot_polynomial_functions(
710
+ functions: List[Dict[str, Dict[str, Any]]],
711
+ zoom: float = 10.0,
712
+ show_legend: bool = True,
713
+ open_file: bool = False,
714
+ save_path: Optional[str] = None,
715
+ ) -> str:
716
+ """
717
+ Plots expressions described by a list of dictionaries of the form:
718
+ [
719
+ { "expression_string": { "x": "*", "a":..., "b":... } },
720
+ { "expression_string": { "x": np.linspace(...), "a":..., ... } },
721
+ ...
722
+ ]
723
+
724
+ In each top-level dictionary, there is exactly one key (a string
725
+ representing a Python/NumPy expression) and one value (a dictionary of
726
+ substitutions). This substitutions dictionary must have an "x" key:
727
+ • "x": "*" -> Use a default domain from -zoom..+zoom.
728
+ • "x": np.array(...) -> Use that array as the domain.
729
+ Other variables (like "a", "b", etc.) may also appear in the same dict.
730
+
731
+ Additionally, we use latexify_expression(...) to transform the expression
732
+ into a nice LaTeX form for the legend, including a special Δ notation for np.diff(...).
733
+
734
+ Parameters
735
+ ----------
736
+ functions : List[Dict[str, Dict[str, Any]]]
737
+ A list of items. Each item is a dictionary:
738
+ key = expression string (e.g., "x**2", "np.diff(x,2)", etc.)
739
+ value = a dictionary of substitutions. Must contain "x",
740
+ either as "*" or a NumPy array. May contain additional
741
+ parameters like "a", "b", etc.
742
+ zoom : float
743
+ Sets the numeric axis range from -zoom..+zoom in both x and y.
744
+ show_legend : bool
745
+ Whether to add a legend to the plot (defaults to True).
746
+ open_file : bool
747
+ If saving to path is not desireable, opens the svg as a temp file, else opens
748
+ the file from the actual location using the system's default viewer (defaults to
749
+ False).
750
+ save_path : Optional[str]
751
+ If specified, saves the output string as a .svg at the indicated path (defaults to
752
+ None).
753
+
754
+ Returns
755
+ -------
756
+ str
757
+ The raw SVG markup of the resulting plot.
758
+ """
759
+
760
+ def latexify_expression(expr_str: str) -> str:
761
+ # Regex to locate np.diff(...) with an optional second argument
762
+ DIFF_PATTERN = r"np\.diff\s*\(\s*([^,\)]+)(?:,\s*(\d+))?\)"
763
+
764
+ def diff_replacer(match: re.Match) -> str:
765
+ inside = match.group(1).strip()
766
+ exponent = match.group(2)
767
+ inside_no_np = inside.replace("np.", "")
768
+ if exponent:
769
+ return rf"\Delta^{exponent}\left({inside_no_np}\right)"
770
+ else:
771
+ return rf"\Delta\left({inside_no_np}\right)"
772
+
773
+ expr_tmp = re.sub(DIFF_PATTERN, diff_replacer, expr_str)
774
+ expr_tmp = expr_tmp.replace("np.", "")
775
+ try:
776
+ latex_expr = python_polynomial_expression_to_latex(expr_tmp)
777
+ return latex_expr
778
+ except Exception:
779
+ # Fallback: just do naive **
780
+ return expr_tmp.replace("**", "^")
781
+
782
+ def handle_open_and_save(
783
+ svg_string: str,
784
+ open_file: bool,
785
+ save_path: Optional[str]
786
+ ) -> None:
787
+ # Save the SVG to a file if a save path is provided
788
+ if save_path:
789
+ try:
790
+ with open(save_path, 'w', encoding='utf-8') as file:
791
+ file.write(svg_string)
792
+ print(f"[INFO] SVG saved to: {save_path}")
793
+ except IOError as e:
794
+ print(f"[ERROR] Failed to save SVG to {save_path}. IOError: {e}")
795
+
796
+ # Handle opening the file if requested
797
+ if open_file and save_path:
798
+ result = subprocess.run(["xdg-open", save_path], stderr=subprocess.DEVNULL)
799
+ if result.returncode != 0:
800
+ print("[ERROR] Failed to open the SVG file with the default viewer.")
801
+ elif open_file:
802
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".svg") as tmpfile:
803
+ temp_svg_path = tmpfile.name
804
+ tmpfile.write(svg_string.encode('utf-8'))
805
+ result = subprocess.run(["xdg-open", temp_svg_path], stderr=subprocess.DEVNULL)
806
+ if result.returncode != 0:
807
+ print("[ERROR] Failed to open the SVG file with the default viewer.")
808
+
809
+ buffer = BytesIO()
810
+ fig, ax = plt.subplots()
811
+
812
+ for entry in functions:
813
+ if len(entry) != 1:
814
+ print("Skipping invalid item. Must have exactly 1 expression->substitutions pair.")
815
+ continue
816
+
817
+ expression, sub_dict = list(entry.items())[0]
818
+ if "x" not in sub_dict:
819
+ print(f"Skipping '{expression}' because sub-dict lacks 'x' key.")
820
+ continue
821
+
822
+ # If "x" is "*", create a default domain
823
+ x_val = sub_dict["x"]
824
+ if isinstance(x_val, str) and x_val == "*":
825
+ x_values = np.linspace(-zoom, zoom, 1201)
826
+ sub_dict["x"] = x_values
827
+ elif isinstance(x_val, np.ndarray):
828
+ x_values = x_val
829
+ else:
830
+ print(f"Skipping '{expression}' because 'x' is neither '*' nor a NumPy array.")
831
+ continue
832
+
833
+ # Evaluate the expression
834
+ try:
835
+ eval_context = {"np": np}
836
+ eval_context.update(sub_dict)
837
+ y_values = eval(expression, {"np": np}, eval_context)
838
+ except Exception as e:
839
+ print(f"Error evaluating expression '{expression}': {e}")
840
+ continue
841
+
842
+ if not isinstance(y_values, np.ndarray):
843
+ print(f"Skipping '{expression}' because it did not produce a NumPy array.")
844
+ continue
845
+
846
+ # If y_values is shorter than x_values (like np.diff), truncate x
847
+ if len(y_values) < len(x_values):
848
+ x_values = x_values[:len(y_values)]
849
+
850
+ # Convert expression to a nice LaTeX string
851
+ label_expr = latexify_expression(expression)
852
+ ax.plot(x_values, y_values, label=rf"${label_expr}$")
853
+
854
+ # Configure axes
855
+ ax.set_xlim(-zoom, zoom)
856
+ ax.set_ylim(-zoom, zoom)
857
+ ax.spines['left'].set_position('zero')
858
+ ax.spines['bottom'].set_position('zero')
859
+ ax.spines['right'].set_color('none')
860
+ ax.spines['top'].set_color('none')
861
+ ax.set_aspect('equal', 'box')
862
+ ax.xaxis.set_ticks_position('bottom')
863
+ ax.yaxis.set_ticks_position('left')
864
+ ax.grid(True)
865
+
866
+ # Show legend
867
+ if show_legend:
868
+ leg = ax.legend(
869
+ loc='upper center',
870
+ bbox_to_anchor=(0.5, -0.03),
871
+ fancybox=True,
872
+ shadow=True,
873
+ ncol=1
874
+ )
875
+ plt.savefig(
876
+ buffer,
877
+ format='svg',
878
+ bbox_inches='tight',
879
+ bbox_extra_artists=[leg] # ensures the legend is fully captured
880
+ )
881
+ else:
882
+ plt.savefig(buffer, format='svg', bbox_inches='tight')
883
+
884
+ plt.close(fig)
885
+ svg_string = buffer.getvalue().decode('utf-8')
886
+ handle_open_and_save(svg_string, open_file, save_path)
887
+ return svg_string
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: rgwfuncs
3
- Version: 0.0.51
3
+ Version: 0.0.53
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
@@ -370,17 +370,17 @@ Converts a polynomial expression written in Python syntax to a LaTeX formatted s
370
370
 
371
371
  Expands a polynomial expression written in Python syntax and converts it into a LaTeX formatted string. This function takes algebraic expressions provided as strings using Python's syntax, applies polynomial expansion through SymPy, and translates them into LaTeX representations, suitable for academic or professional documentation. It supports expressions with named variables and provides an option to substitute specific values into the expression before expansion.
372
372
 
373
- - Parameters:
373
+ Parameters:
374
374
  - `expression` (str): The algebraic expression to expand and convert to LaTeX. This string should be formatted using Python syntax acceptable by SymPy.
375
375
  - `subs` (Optional[Dict[str, float]]): An optional dictionary of substitutions where the keys are variable names in the expression, and the values are the numbers with which to substitute those variables before expanding.
376
376
 
377
- - Returns:
377
+ Returns:
378
378
  - `str`: The LaTeX formatted string of the expanded expression.
379
379
 
380
- - Raises:
380
+ Raises:
381
381
  - `ValueError`: If the expression cannot be parsed due to syntax errors.
382
382
 
383
- - Example:
383
+ Example:
384
384
 
385
385
  from rgwfuncs import expand_polynomial_expression
386
386
 
@@ -406,17 +406,17 @@ Expands a polynomial expression written in Python syntax and converts it into a
406
406
 
407
407
  Factors a polynomial expression written in Python syntax and converts it into a LaTeX formatted string. This function parses an algebraic expression, performs polynomial factoring using SymPy, and converts the factored expression into a LaTeX representation, ideal for academic or professional use. Optional substitutions can be made before factoring.
408
408
 
409
- - Parameters:
409
+ Parameters:
410
410
  - `expression` (str): The polynomial expression to factor and convert to LaTeX. This should be a valid expression formatted using Python syntax.
411
411
  - `subs` (Optional[Dict[str, float]]): An optional dictionary of substitutions. The keys are variable names in the expression, and the values are numbers that replace these variables.
412
412
 
413
- - Returns:
413
+ Returns:
414
414
  - `str`: The LaTeX formatted string representing the factored expression.
415
415
 
416
- - Raises:
416
+ Raises:
417
417
  - `ValueError`: If the expression cannot be parsed due to syntax errors.
418
418
 
419
- - Example:
419
+ Example:
420
420
 
421
421
  from rgwfuncs import factor_polynomial_expression
422
422
 
@@ -441,7 +441,7 @@ Simplifies an algebraic expression in polynomial form and returns it in LaTeX fo
441
441
  • Returns:
442
442
  - `str`: The simplified expression formatted as a LaTeX string.
443
443
 
444
- • Example Usage:
444
+ • Example:
445
445
 
446
446
  from rgwfuncs import simplify_polynomial_expression
447
447
 
@@ -467,17 +467,17 @@ Simplifies an algebraic expression in polynomial form and returns it in LaTeX fo
467
467
 
468
468
  Cancels common factors within a polynomial expression written in Python syntax and converts it to a LaTeX formatted string. This function parses an algebraic expression, cancels common factors using SymPy, and translates the reduced expression into a LaTeX representation. It can also accommodate optional substitutions to be made prior to simplification.
469
469
 
470
- - Parameters:
470
+ Parameters:
471
471
  - `expression` (str): The algebraic expression to simplify and convert to LaTeX. This string should be formatted using Python syntax.
472
472
  - `subs` (Optional[Dict[str, float]]): An optional dictionary of substitutions where the keys are variable names in the expression, and the values are the numbers to substitute.
473
473
 
474
- - Returns:
474
+ Returns:
475
475
  - `str`: The LaTeX formatted string of the simplified expression. If the expression involves indeterminate forms due to operations like division by zero, a descriptive error message is returned instead.
476
476
 
477
- - Raises:
477
+ Raises:
478
478
  - `ValueError`: If the expression cannot be parsed due to syntax errors or involves undefined operations, such as division by zero.
479
479
 
480
- - Example:
480
+ Example:
481
481
 
482
482
  from rgwfuncs import cancel_polynomial_expression
483
483
 
@@ -514,6 +514,46 @@ 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
+ - `open_file` (`bool`): If saving to path is not desireable, opens the svg as a temp file, else opens the file from the actual location using the system's default viewer (defaults to False).
528
+ - `save_path` (`Optional[str]`): If specified, saves the output string as a .svg at the indicated path (defaults to None).
529
+
530
+ • Returns:
531
+ - `str`: The raw SVG markup of the resulting plot.
532
+
533
+ • Example:
534
+
535
+ from rgwfuncs import plot_polynomial_functions
536
+
537
+ # Generate the SVG
538
+ plot_svg_string = plot_polynomial_functions(
539
+ functions=[
540
+ {"x**2": {"x": "*"}}, # Single expression, "*" means plot all discernable points
541
+ {"x**2/(2 + a) + a": {"x": np.linspace(-3, 4, 101), "a": 1.23}},
542
+ {"np.diff(x**3, 2)": {"x": np.linspace(-2, 2, 10)}}
543
+ ],
544
+ zoom=2
545
+ )
546
+
547
+ # Write the SVG to an actual file
548
+ with open("plot.svg", "w", encoding="utf-8") as file:
549
+ file.write(plot_svg_string)
550
+
551
+ • Displaying the SVG:
552
+
553
+ ![Plot](./media/plot_polynomial_functions_example_1.svg)
554
+
555
+ --------------------------------------------------------------------------------
556
+
517
557
  ## String Based Functions
518
558
 
519
559
  ### 1. send_telegram_message
@@ -0,0 +1,12 @@
1
+ rgwfuncs/__init__.py,sha256=JjkuVeRV_Bkw8vnqSbJsRcYQRm4iCI3futR86cf3tRI,1637
2
+ rgwfuncs/algebra_lib.py,sha256=AcGurkWyq3sd-HXPqUDnioEyiYwC_H70PBkJHOcXO7I,35183
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.53.dist-info/LICENSE,sha256=7EI8xVBu6h_7_JlVw-yPhhOZlpY9hP8wal7kHtqKT_E,1074
8
+ rgwfuncs-0.0.53.dist-info/METADATA,sha256=dkIVCAMIVUoI1teXGoalzHFYQT1usUebDMG5Mr6bafE,57140
9
+ rgwfuncs-0.0.53.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
10
+ rgwfuncs-0.0.53.dist-info/entry_points.txt,sha256=j-c5IOPIQ0252EaOV6j6STio56sbXl2C4ym_fQ0lXx0,43
11
+ rgwfuncs-0.0.53.dist-info/top_level.txt,sha256=aGuVIzWsKiV1f2gCb6mynx0zx5ma0B1EwPGFKVEMTi4,9
12
+ rgwfuncs-0.0.53.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,,