diff options
| author | salmonik <raisersoft@proton.me> | 2026-04-18 00:29:07 +0200 |
|---|---|---|
| committer | salmonik <raisersoft@proton.me> | 2026-04-18 00:29:07 +0200 |
| commit | 27724fc7756e61ed04a859698f10dee0248bd95e (patch) | |
| tree | a1cf5c3b47eb391b35af60093d1128f9b2bc60a2 | |
| parent | refactor + preparing bot for public use (diff) | |
| download | senator-sperma-27724fc7756e61ed04a859698f10dee0248bd95e.tar.gz senator-sperma-27724fc7756e61ed04a859698f10dee0248bd95e.zip | |
add support for x^2+y^2=0,4 and alike
Signed-off-by: salmonik <raisersoft@proton.me>
| -rw-r--r-- | cogs/plot.py | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/cogs/plot.py b/cogs/plot.py index 65dcae4..4fcde44 100644 --- a/cogs/plot.py +++ b/cogs/plot.py | |||
| @@ -39,9 +39,22 @@ def parse_expression(expr: str) -> str: | |||
| 39 | expr = expr.replace("^", "**") | 39 | expr = expr.replace("^", "**") |
| 40 | expr = re.sub(r"(\d)([x])", r"\1*\2", expr) | 40 | expr = re.sub(r"(\d)([x])", r"\1*\2", expr) |
| 41 | expr = re.sub(r"([x])(\d)", r"\1*\2", expr) | 41 | expr = re.sub(r"([x])(\d)", r"\1*\2", expr) |
| 42 | expr = re.sub(r"(\d)([y])", r"\1*\2", expr) | ||
| 43 | expr = re.sub(r"([y])(\d)", r"\1*\2", expr) | ||
| 42 | return expr | 44 | return expr |
| 43 | 45 | ||
| 44 | 46 | ||
| 47 | def is_implicit(expr: str) -> bool: | ||
| 48 | return "=" in expr and "y" in expr and "x" in expr | ||
| 49 | |||
| 50 | |||
| 51 | def parse_implicit(expr: str) -> tuple[str, str]: | ||
| 52 | lhs, rhs = expr.split("=", 1) | ||
| 53 | lhs = parse_expression(lhs.strip()) | ||
| 54 | rhs = parse_expression(rhs.strip()) | ||
| 55 | return lhs, rhs | ||
| 56 | |||
| 57 | |||
| 45 | class Plot(commands.Cog): | 58 | class Plot(commands.Cog): |
| 46 | def __init__(self, bot): | 59 | def __init__(self, bot): |
| 47 | self.bot = bot | 60 | self.bot = bot |
| @@ -53,6 +66,11 @@ class Plot(commands.Cog): | |||
| 53 | raise RuntimeError("matplotlib not available") | 66 | raise RuntimeError("matplotlib not available") |
| 54 | 67 | ||
| 55 | plt = _plt_module | 68 | plt = _plt_module |
| 69 | |||
| 70 | if is_implicit(func_expr): | ||
| 71 | self._generate_implicit_plot(func_expr, output_path) | ||
| 72 | return | ||
| 73 | |||
| 56 | parsed_expr = parse_expression(func_expr) | 74 | parsed_expr = parse_expression(func_expr) |
| 57 | 75 | ||
| 58 | x = [i * 0.1 for i in range(-100, 101)] | 76 | x = [i * 0.1 for i in range(-100, 101)] |
| @@ -96,6 +114,49 @@ class Plot(commands.Cog): | |||
| 96 | plt.savefig(output_path, dpi=100, bbox_inches="tight") | 114 | plt.savefig(output_path, dpi=100, bbox_inches="tight") |
| 97 | plt.close() | 115 | plt.close() |
| 98 | 116 | ||
| 117 | def _generate_implicit_plot(self, func_expr: str, output_path: str): | ||
| 118 | global _plt_module | ||
| 119 | plt = _plt_module | ||
| 120 | |||
| 121 | lhs, rhs = parse_implicit(func_expr) | ||
| 122 | |||
| 123 | x_range = 20 | ||
| 124 | y_range = 20 | ||
| 125 | |||
| 126 | x_vals = [] | ||
| 127 | y_vals = [] | ||
| 128 | |||
| 129 | for xi in range(-x_range * 10, x_range * 10 + 1): | ||
| 130 | x = xi / 10.0 | ||
| 131 | for yi in range(-y_range * 10, y_range * 10 + 1): | ||
| 132 | y = yi / 10.0 | ||
| 133 | try: | ||
| 134 | left_val = eval(lhs, {"x": x, "y": y, "math": math, "sqrt": math.sqrt, "pi": math.pi, "e": math.e}) | ||
| 135 | right_val = eval(rhs, {"x": x, "y": y, "math": math, "sqrt": math.sqrt, "pi": math.pi, "e": math.e}) | ||
| 136 | diff = abs(left_val - right_val) | ||
| 137 | if math.isfinite(diff) and diff < 0.3: | ||
| 138 | x_vals.append(x) | ||
| 139 | y_vals.append(y) | ||
| 140 | except Exception: | ||
| 141 | pass | ||
| 142 | |||
| 143 | fig, ax = plt.subplots(figsize=(10, 10)) | ||
| 144 | ax.scatter(x_vals, y_vals, s=1, color="#00ff00", alpha=0.5) | ||
| 145 | ax.set_title(f"{func_expr}", fontsize=14) | ||
| 146 | ax.set_xlabel("x", fontsize=12) | ||
| 147 | ax.set_ylabel("y", fontsize=12) | ||
| 148 | ax.grid(True, alpha=0.3) | ||
| 149 | ax.axhline(y=0, color="white", linewidth=0.5) | ||
| 150 | ax.axvline(x=0, color="white", linewidth=0.5) | ||
| 151 | ax.set_xlim(-x_range, x_range) | ||
| 152 | ax.set_ylim(-y_range, y_range) | ||
| 153 | ax.set_aspect("equal") | ||
| 154 | ax.set_facecolor("#1a1a1a") | ||
| 155 | fig.patch.set_facecolor("#1a1a1a") | ||
| 156 | |||
| 157 | plt.savefig(output_path, dpi=100, bbox_inches="tight") | ||
| 158 | plt.close() | ||
| 159 | |||
| 99 | @commands.slash_command(name="funkcja", description="Generuje wykres funkcji matematycznej") | 160 | @commands.slash_command(name="funkcja", description="Generuje wykres funkcji matematycznej") |
| 100 | async def plot(self, ctx, funkcja: str = discord.Option(str, "Funkcja np. x^3, sin(x), x^2 + 2*x - 1", required=True)): | 161 | async def plot(self, ctx, funkcja: str = discord.Option(str, "Funkcja np. x^3, sin(x), x^2 + 2*x - 1", required=True)): |
| 101 | if not _ensure_plot(): | 162 | if not _ensure_plot(): |
