| import os
|
| from flask import Blueprint, render_template, request, jsonify
|
| import numpy as np
|
| import matplotlib
|
| matplotlib.use('Agg')
|
| import matplotlib.pyplot as plt
|
| import base64
|
| from io import BytesIO
|
| import re
|
|
|
| graph_bp = Blueprint('graph_bp', __name__)
|
|
|
| UPLOAD_FOLDER = 'static/uploads'
|
| GRAPHS_FOLDER = 'static/graphs'
|
| os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
| os.makedirs(GRAPHS_FOLDER, exist_ok=True)
|
|
|
|
|
| def parse_plot_command(command):
|
| """Parse plot command and extract function and range"""
|
|
|
| command = command.strip()
|
|
|
|
|
| pattern = r"plot\s+(.+?)\s+from\s+(-?[\d\*\.pi]+)\s+to\s+(-?[\d\*\.pi]+)"
|
| match = re.match(pattern, command, re.IGNORECASE)
|
|
|
| if match:
|
| function = match.group(1)
|
| x_min = match.group(2)
|
| x_max = match.group(3)
|
|
|
|
|
| x_min = x_min.replace('pi', 'np.pi')
|
| x_max = x_max.replace('pi', 'np.pi')
|
|
|
| try:
|
| x_min_val = eval(x_min)
|
| x_max_val = eval(x_max)
|
| return function, x_min_val, x_max_val
|
| except:
|
| raise ValueError("Invalid range values")
|
|
|
|
|
| simple_pattern = r"plot\s+(.+)"
|
| simple_match = re.match(simple_pattern, command, re.IGNORECASE)
|
|
|
| if simple_match:
|
| function = simple_match.group(1)
|
| return function, -10, 10
|
|
|
| raise ValueError("Invalid plot command format")
|
|
|
|
|
| def evaluate_function(func_str, x):
|
| """Safely evaluate mathematical function"""
|
|
|
| func_str = func_str.replace('^', '**')
|
| func_str = func_str.replace('sin', 'np.sin')
|
| func_str = func_str.replace('cos', 'np.cos')
|
| func_str = func_str.replace('tan', 'np.tan')
|
| func_str = func_str.replace('log', 'np.log')
|
| func_str = func_str.replace('exp', 'np.exp')
|
| func_str = func_str.replace('sqrt', 'np.sqrt')
|
| func_str = func_str.replace('abs', 'np.abs')
|
|
|
|
|
| func_str = func_str.replace('x', f'({x})')
|
|
|
| try:
|
| return eval(func_str)
|
| except:
|
| raise ValueError(f"Error evaluating function: {func_str}")
|
|
|
|
|
| def generate_tikz_latex(function, x_min, x_max):
|
| """Generate TikZ/pgfplots LaTeX code for the function"""
|
|
|
| pgf_function = function.replace('^', '^')
|
| pgf_function = pgf_function.replace('sqrt', 'sqrt')
|
|
|
|
|
| latex_code = r'''\documentclass{article}
|
| \usepackage{pgfplots}
|
| \usepackage{amsmath}
|
| \pgfplotsset{compat=1.18}
|
|
|
| \begin{document}
|
|
|
| \begin{figure}[h]
|
| \centering
|
| \begin{tikzpicture}
|
| \begin{axis}[
|
| xlabel={$x$},
|
| ylabel={$y$},
|
| grid=major,
|
| width=12cm,
|
| height=8cm,
|
| samples=200,
|
| domain=''' + f"{x_min}:{x_max}" + r''',
|
| legend pos=north west,
|
| axis lines=middle,
|
| ]
|
| \addplot[blue, thick] {''' + pgf_function + r'''};
|
| \legend{$f(x)=''' + function + r'''$}
|
| \end{axis}
|
| \end{tikzpicture}
|
| \caption{Graph of $f(x) = ''' + function + r'''$}
|
| \label{fig:graph}
|
| \end{figure}
|
|
|
| \end{document}'''
|
|
|
| return latex_code
|
|
|
|
|
| def generate_plot(function, x_min, x_max):
|
| """Generate plot and return base64 image"""
|
| try:
|
|
|
| x = np.linspace(x_min, x_max, 1000)
|
|
|
|
|
| y = []
|
| for xi in x:
|
| try:
|
| yi = evaluate_function(function, xi)
|
| y.append(yi)
|
| except:
|
| y.append(np.nan)
|
|
|
| y = np.array(y)
|
|
|
|
|
| plt.figure(figsize=(10, 6))
|
| plt.plot(x, y, linewidth=2, color='#667eea')
|
| plt.grid(True, alpha=0.3)
|
| plt.xlabel('x')
|
| plt.ylabel('y')
|
| plt.title(f'Graph of f(x) = {function}')
|
|
|
|
|
| buffer = BytesIO()
|
| plt.savefig(buffer, format='png', dpi=150, bbox_inches='tight')
|
| buffer.seek(0)
|
| image_base64 = base64.b64encode(buffer.getvalue()).decode()
|
| plt.close()
|
|
|
| return image_base64
|
| except Exception as e:
|
| raise ValueError(f"Error generating plot: {str(e)}")
|
|
|
|
|
| @graph_bp.route("/graph")
|
| def graph_page():
|
| return render_template("graph.html")
|
|
|
|
|
| @graph_bp.route("/graph/generate", methods=["POST"])
|
| def generate_graph():
|
| """Generate graph from user input"""
|
| try:
|
| data = request.get_json()
|
| if not data:
|
| return jsonify({'error': 'No data provided'}), 400
|
|
|
| command = data.get('command', '')
|
| if not command:
|
| return jsonify({'error': 'No command provided'}), 400
|
|
|
|
|
| function, x_min, x_max = parse_plot_command(command)
|
|
|
|
|
| image_base64 = generate_plot(function, x_min, x_max)
|
|
|
|
|
| latex_code = generate_tikz_latex(function, x_min, x_max)
|
|
|
| return jsonify({
|
| 'success': True,
|
| 'image': image_base64,
|
| 'function': function,
|
| 'range': f'[{x_min}, {x_max}]',
|
| 'latex': latex_code
|
| })
|
|
|
| except Exception as e:
|
| return jsonify({'error': str(e)}), 500 |