From c65a2cb0b35982fac320744fb662456025ad42d0 Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 19 Apr 2026 14:04:27 +0200 Subject: discontinue plots; too complex. Signed-off-by: salmonik --- cogs/plot.py | 195 ----------------------------------------------------------- 1 file changed, 195 deletions(-) delete mode 100644 cogs/plot.py (limited to 'cogs/plot.py') diff --git a/cogs/plot.py b/cogs/plot.py deleted file mode 100644 index ee19de9..0000000 --- a/cogs/plot.py +++ /dev/null @@ -1,195 +0,0 @@ -# This file is part of Senator Sperma -# Licensed under the GPL-3.0 License -# Copyright (C) 2026 Salmonik @ salmonik@tuta.io -# https://codeberg.org/salmonik/senator-sperma - -import asyncio -import logging -import math -import os -import re - -import discord -from discord.ext import commands - -logger = logging.getLogger(__name__) - -_plt_module = None -_plot_available = False - - -def _ensure_plot(): - global _plt_module, _plot_available - - if _plt_module is not None: - return _plot_available - - try: - import matplotlib - matplotlib.use("Agg") - import matplotlib.pyplot as _plt_module - _plot_available = True - except ImportError: - _plot_available = False - logger.warning("matplotlib not available, plot command will be disabled") - return _plot_available - - -def parse_expression(expr: str) -> str: - expr = expr.replace("^", "**") - expr = re.sub(r"(\d)([x])", r"\1*\2", expr) - expr = re.sub(r"([x])(\d)", r"\1*\2", expr) - expr = re.sub(r"(\d)([y])", r"\1*\2", expr) - expr = re.sub(r"([y])(\d)", r"\1*\2", expr) - return expr - - -def is_implicit(expr: str) -> bool: - return "=" in expr and "y" in expr and "x" in expr - - -def parse_implicit(expr: str) -> tuple[str, str]: - lhs, rhs = expr.split("=", 1) - lhs = parse_expression(lhs.strip()) - rhs = parse_expression(rhs.strip()) - return lhs, rhs - - -class Plot(commands.Cog): - def __init__(self, bot): - self.bot = bot - - def _generate_plot(self, func_expr: str, output_path: str): - global _plt_module - - if not _ensure_plot(): - raise RuntimeError("matplotlib not available") - - plt = _plt_module - - if is_implicit(func_expr): - self._generate_implicit_plot(func_expr, output_path) - return - - parsed_expr = parse_expression(func_expr) - - x = [i * 0.1 for i in range(-100, 101)] - y = [] - - for xi in x: - try: - result = eval( - parsed_expr, - { - "x": xi, - "math": math, - "sin": math.sin, - "cos": math.cos, - "tan": math.tan, - "sqrt": math.sqrt, - "log": math.log, - "exp": math.exp, - "pi": math.pi, - "e": math.e, - }, - ) - if math.isfinite(result): - y.append(result) - else: - y.append(float("nan")) - except Exception: - y.append(float("nan")) - - valid_y = [yi for yi in y if not math.isnan(yi)] - if not valid_y: - raise ValueError("Brak danych do wykreślenia dla podanej funkcji") - - fig, ax = plt.subplots(figsize=(10, 6)) - ax.plot(x, y, linewidth=2, color="#00ff00") - ax.set_title(f"y = {func_expr}", fontsize=14) - ax.set_xlabel("x", fontsize=12) - ax.set_ylabel("y", fontsize=12) - ax.grid(True, alpha=0.3) - ax.axhline(y=0, color="white", linewidth=0.5) - ax.axvline(x=0, color="white", linewidth=0.5) - ax.set_facecolor("#1a1a1a") - fig.patch.set_facecolor("#1a1a1a") - - plt.savefig(output_path, dpi=100, bbox_inches="tight") - plt.close() - - def _generate_implicit_plot(self, func_expr: str, output_path: str): - global _plt_module - plt = _plt_module - - lhs, rhs = parse_implicit(func_expr) - - x_range = 20 - y_range = 20 - - x_vals = [] - y_vals = [] - - for xi in range(-x_range * 10, x_range * 10 + 1): - x = xi / 10.0 - for yi in range(-y_range * 10, y_range * 10 + 1): - y = yi / 10.0 - try: - left_val = eval(lhs, {"x": x, "y": y, "math": math, "sqrt": math.sqrt, "pi": math.pi, "e": math.e}) - right_val = eval(rhs, {"x": x, "y": y, "math": math, "sqrt": math.sqrt, "pi": math.pi, "e": math.e}) - diff = abs(left_val - right_val) - if math.isfinite(diff) and diff < 0.3: - x_vals.append(x) - y_vals.append(y) - except Exception: - pass - - if not x_vals or not y_vals: - raise ValueError("Brak danych do wykreślenia dla podanej funkcji") - - fig, ax = plt.subplots(figsize=(10, 10)) - ax.scatter(x_vals, y_vals, s=1, color="#00ff00", alpha=0.5) - ax.set_title(f"{func_expr}", fontsize=14) - ax.set_xlabel("x", fontsize=12) - ax.set_ylabel("y", fontsize=12) - ax.grid(True, alpha=0.3) - ax.axhline(y=0, color="white", linewidth=0.5) - ax.axvline(x=0, color="white", linewidth=0.5) - ax.set_xlim(-x_range, x_range) - ax.set_ylim(-y_range, y_range) - ax.set_aspect("equal") - ax.set_facecolor("#1a1a1a") - fig.patch.set_facecolor("#1a1a1a") - - plt.savefig(output_path, dpi=100, bbox_inches="tight") - plt.close() - - @commands.slash_command(name="funkcja", description="Generuje wykres funkcji matematycznej") - async def plot(self, ctx, funkcja: str = discord.Option(str, "Funkcja np. x^3, sin(x), x^2 + 2*x - 1", required=True)): - if not _ensure_plot(): - await ctx.respond("Generowanie wykresów nie jest dostępne (brak matplotlib)", ephemeral=True) - return - - await ctx.defer() - - from cogs.utils.temp import get_temp_dir - temp_path = os.path.join(get_temp_dir(), f"plot_{os.getpid()}_{asyncio.get_event_loop().time()}.png") - - try: - loop = asyncio.get_event_loop() - await loop.run_in_executor(None, self._generate_plot, funkcja, temp_path) - await ctx.respond(file=discord.File(temp_path, filename="plot.png")) - logger.info(f"Generated plot for function: {funkcja}") - except Exception as e: - logger.error(f"Plot generation error: {e}") - await ctx.respond(f"Błąd generowania wykresu: {str(e)}", ephemeral=True) - finally: - try: - if os.path.exists(temp_path): - os.unlink(temp_path) - except Exception as e: - logger.error(f"Error cleaning up temp file: {e}") - - -def setup(bot): - bot.add_cog(Plot(bot)) -- cgit v1.2.3