Initial commit: Quadratic Equation Plotter application
Features: - Plot quadratic equations: y = ax² + bx + c - Adjustable X-axis range - Visualize vertex and roots - Save plots in multiple formats - Interactive matplotlib navigation toolbar - Clean GUI interface with Tkinter
This commit is contained in:
commit
831b650111
155
.gitignore
vendored
Normal file
155
.gitignore
vendored
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
Pipfile.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# VS Code
|
||||||
|
.vscode/
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# OS generated files
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Matplotlib
|
||||||
|
*.png
|
||||||
|
*.jpg
|
||||||
|
*.pdf
|
||||||
|
*.svg
|
||||||
|
|
||||||
|
# Project specific (optional)
|
||||||
|
screenshots/
|
||||||
|
output/
|
||||||
|
test_output/
|
||||||
121
README.md
Normal file
121
README.md
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
# Quadratic Equation Plotter
|
||||||
|
|
||||||
|
A Python GUI application for plotting quadratic equations using Tkinter and Matplotlib.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Plot any quadratic equation in the form: **y = ax² + bx + c**
|
||||||
|
- Adjustable X-axis range
|
||||||
|
- Visualize vertex and roots (when they exist)
|
||||||
|
- Save plots in multiple formats (PNG, JPEG, PDF, SVG)
|
||||||
|
- Interactive matplotlib navigation toolbar (zoom, pan, save)
|
||||||
|
- Clean, user-friendly interface
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Python 3.6 or higher
|
||||||
|
- NumPy
|
||||||
|
- Matplotlib
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Install Python dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Or install manually:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install numpy matplotlib
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Run the application:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python quadratic_plotter.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Interface Components:
|
||||||
|
|
||||||
|
1. **Coefficients Input**:
|
||||||
|
- Enter values for `a`, `b`, and `c`
|
||||||
|
- Default: a=1, b=0, c=0 (plots y = x²)
|
||||||
|
|
||||||
|
2. **X-axis Range**:
|
||||||
|
- Set the range of x-values to plot
|
||||||
|
- Default: -10 to 10
|
||||||
|
|
||||||
|
3. **Buttons**:
|
||||||
|
- **Plot Quadratic**: Generate the plot with current parameters
|
||||||
|
- **Save Plot**: Save the current plot to a file
|
||||||
|
- **Clear Plot**: Clear the current plot
|
||||||
|
|
||||||
|
4. **Plot Area**:
|
||||||
|
- Interactive matplotlib plot with zoom and pan capabilities
|
||||||
|
- Vertex shown as red dot (for a ≠ 0)
|
||||||
|
- Roots shown as green dots (when real roots exist)
|
||||||
|
- Legend showing equation and key points
|
||||||
|
|
||||||
|
## Example Plots
|
||||||
|
|
||||||
|
1. **Standard Parabola**: a=1, b=0, c=0
|
||||||
|
2. **Shifted Parabola**: a=1, b=-2, c=1
|
||||||
|
3. **Downward Parabola**: a=-1, b=0, c=4
|
||||||
|
4. **Linear Function**: a=0, b=2, c=1 (plots a straight line)
|
||||||
|
|
||||||
|
## Features in Detail
|
||||||
|
|
||||||
|
### Vertex Calculation
|
||||||
|
The vertex of the parabola is calculated using:
|
||||||
|
```
|
||||||
|
x_vertex = -b / (2a)
|
||||||
|
y_vertex = a(x_vertex)² + b(x_vertex) + c
|
||||||
|
```
|
||||||
|
|
||||||
|
### Roots Calculation
|
||||||
|
Real roots are calculated using the quadratic formula:
|
||||||
|
```
|
||||||
|
x = [-b ± √(b² - 4ac)] / (2a)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Plot Customization
|
||||||
|
- Blue line: Quadratic curve
|
||||||
|
- Red dot: Vertex of parabola
|
||||||
|
- Green dots: Real roots (x-intercepts)
|
||||||
|
- Grid lines for easy reference
|
||||||
|
- Axes lines through origin
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
The application includes error handling for:
|
||||||
|
- Invalid numeric input
|
||||||
|
- X-min greater than X-max
|
||||||
|
- File save errors
|
||||||
|
- Missing dependencies
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is open source and available for educational and personal use.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
If you encounter issues:
|
||||||
|
|
||||||
|
1. **Missing dependencies**: Ensure all packages are installed
|
||||||
|
2. **GUI not showing**: Check if Tkinter is installed (usually bundled with Python)
|
||||||
|
3. **Plot not updating**: Verify all input fields contain valid numbers
|
||||||
|
4. **ImportError: "NavigationToolbar2Tk" is not exported**: This application includes compatibility code for different matplotlib versions. If you see this error, update matplotlib to version 3.4 or later:
|
||||||
|
```bash
|
||||||
|
pip install --upgrade matplotlib
|
||||||
|
```
|
||||||
|
The code will automatically try multiple import locations for backward compatibility.
|
||||||
|
|
||||||
|
## Screenshot
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
*Note: Add your own screenshot after running the application*
|
||||||
273
quadratic_plotter.py
Normal file
273
quadratic_plotter.py
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
from tkinter import ttk, messagebox
|
||||||
|
import numpy as np
|
||||||
|
from matplotlib.figure import Figure
|
||||||
|
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
|
||||||
|
|
||||||
|
# Import NavigationToolbar2Tk with version compatibility
|
||||||
|
try:
|
||||||
|
# For matplotlib >= 3.4
|
||||||
|
from matplotlib.backends.backend_tkagg import NavigationToolbar2Tk # type: ignore
|
||||||
|
except ImportError:
|
||||||
|
try:
|
||||||
|
# For older matplotlib versions or alternative location
|
||||||
|
from matplotlib.backends._backend_tk import NavigationToolbar2Tk # type: ignore
|
||||||
|
except ImportError:
|
||||||
|
# Try another possible location
|
||||||
|
from matplotlib.backends.backend_tk import NavigationToolbar2Tk # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
class QuadraticPlotter:
|
||||||
|
def __init__(self):
|
||||||
|
self.root = tk.Tk()
|
||||||
|
self.root.title("Quadratic Equation Plotter")
|
||||||
|
self.root.geometry("900x700")
|
||||||
|
|
||||||
|
# Variables for coefficients
|
||||||
|
self.a_var = tk.StringVar(value="1")
|
||||||
|
self.b_var = tk.StringVar(value="0")
|
||||||
|
self.c_var = tk.StringVar(value="0")
|
||||||
|
|
||||||
|
# Variables for x-range
|
||||||
|
self.x_min_var = tk.StringVar(value="-10")
|
||||||
|
self.x_max_var = tk.StringVar(value="10")
|
||||||
|
|
||||||
|
# Create the main window content
|
||||||
|
self.create_widgets()
|
||||||
|
|
||||||
|
# Start the application loop
|
||||||
|
self.root.mainloop()
|
||||||
|
|
||||||
|
def create_widgets(self):
|
||||||
|
# Create main frames
|
||||||
|
control_frame = tk.Frame(self.root, padx=10, pady=10)
|
||||||
|
control_frame.pack(side=tk.TOP, fill=tk.X)
|
||||||
|
|
||||||
|
plot_frame = tk.Frame(self.root)
|
||||||
|
plot_frame.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True, padx=10, pady=10)
|
||||||
|
|
||||||
|
# Title
|
||||||
|
title_label = tk.Label(control_frame, text="Quadratic Equation Plotter: y = ax² + bx + c",
|
||||||
|
font=("Arial", 14, "bold"))
|
||||||
|
title_label.grid(row=0, column=0, columnspan=6, pady=(0, 15))
|
||||||
|
|
||||||
|
# Coefficients input
|
||||||
|
coeff_frame = tk.LabelFrame(control_frame, text="Coefficients", padx=10, pady=10)
|
||||||
|
coeff_frame.grid(row=1, column=0, columnspan=6, sticky="ew", pady=(0, 10))
|
||||||
|
|
||||||
|
# a coefficient
|
||||||
|
tk.Label(coeff_frame, text="a =").grid(row=0, column=0, padx=(0, 5))
|
||||||
|
a_entry = tk.Entry(coeff_frame, textvariable=self.a_var, width=10)
|
||||||
|
a_entry.grid(row=0, column=1, padx=(0, 15))
|
||||||
|
|
||||||
|
# b coefficient
|
||||||
|
tk.Label(coeff_frame, text="b =").grid(row=0, column=2, padx=(0, 5))
|
||||||
|
b_entry = tk.Entry(coeff_frame, textvariable=self.b_var, width=10)
|
||||||
|
b_entry.grid(row=0, column=3, padx=(0, 15))
|
||||||
|
|
||||||
|
# c coefficient
|
||||||
|
tk.Label(coeff_frame, text="c =").grid(row=0, column=4, padx=(0, 5))
|
||||||
|
c_entry = tk.Entry(coeff_frame, textvariable=self.c_var, width=10)
|
||||||
|
c_entry.grid(row=0, column=5, padx=(0, 15))
|
||||||
|
|
||||||
|
# X-range input
|
||||||
|
range_frame = tk.LabelFrame(control_frame, text="X-axis Range", padx=10, pady=10)
|
||||||
|
range_frame.grid(row=2, column=0, columnspan=6, sticky="ew", pady=(0, 10))
|
||||||
|
|
||||||
|
tk.Label(range_frame, text="From:").grid(row=0, column=0, padx=(0, 5))
|
||||||
|
xmin_entry = tk.Entry(range_frame, textvariable=self.x_min_var, width=10)
|
||||||
|
xmin_entry.grid(row=0, column=1, padx=(0, 15))
|
||||||
|
|
||||||
|
tk.Label(range_frame, text="To:").grid(row=0, column=2, padx=(0, 5))
|
||||||
|
xmax_entry = tk.Entry(range_frame, textvariable=self.x_max_var, width=10)
|
||||||
|
xmax_entry.grid(row=0, column=3, padx=(0, 15))
|
||||||
|
|
||||||
|
# Buttons
|
||||||
|
button_frame = tk.Frame(control_frame)
|
||||||
|
button_frame.grid(row=3, column=0, columnspan=6, pady=(10, 0))
|
||||||
|
|
||||||
|
plot_button = tk.Button(button_frame, text="Plot Quadratic", command=self.plot_quadratic,
|
||||||
|
bg="lightblue", font=("Arial", 10, "bold"), padx=20, pady=5)
|
||||||
|
plot_button.pack(side=tk.LEFT, padx=(0, 10))
|
||||||
|
|
||||||
|
save_button = tk.Button(button_frame, text="Save Plot", command=self.save_plot,
|
||||||
|
bg="lightgreen", font=("Arial", 10, "bold"), padx=20, pady=5)
|
||||||
|
save_button.pack(side=tk.LEFT, padx=(0, 10))
|
||||||
|
|
||||||
|
clear_button = tk.Button(button_frame, text="Clear Plot", command=self.clear_plot,
|
||||||
|
bg="lightcoral", font=("Arial", 10, "bold"), padx=20, pady=5)
|
||||||
|
clear_button.pack(side=tk.LEFT)
|
||||||
|
|
||||||
|
# Matplotlib figure and canvas
|
||||||
|
self.fig = Figure(figsize=(8, 6), dpi=100)
|
||||||
|
self.ax = self.fig.add_subplot(111)
|
||||||
|
self.setup_plot()
|
||||||
|
|
||||||
|
self.canvas = FigureCanvasTkAgg(self.fig, master=plot_frame)
|
||||||
|
self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
# Add matplotlib navigation toolbar
|
||||||
|
self.toolbar = NavigationToolbar2Tk(self.canvas, plot_frame)
|
||||||
|
self.toolbar.update()
|
||||||
|
self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
def setup_plot(self):
|
||||||
|
"""Initialize plot with labels and grid"""
|
||||||
|
self.ax.set_xlabel('x')
|
||||||
|
self.ax.set_ylabel('y')
|
||||||
|
self.ax.set_title('Quadratic Function: y = ax² + bx + c')
|
||||||
|
self.ax.grid(True, linestyle='--', alpha=0.7)
|
||||||
|
self.ax.axhline(y=0, color='k', linestyle='-', linewidth=0.5)
|
||||||
|
self.ax.axvline(x=0, color='k', linestyle='-', linewidth=0.5)
|
||||||
|
|
||||||
|
def plot_quadratic(self):
|
||||||
|
"""Plot the quadratic equation based on user input"""
|
||||||
|
try:
|
||||||
|
# Get coefficients
|
||||||
|
a = float(self.a_var.get())
|
||||||
|
b = float(self.b_var.get())
|
||||||
|
c = float(self.c_var.get())
|
||||||
|
|
||||||
|
# Get x-range
|
||||||
|
x_min = float(self.x_min_var.get())
|
||||||
|
x_max = float(self.x_max_var.get())
|
||||||
|
|
||||||
|
if x_min >= x_max:
|
||||||
|
messagebox.showerror("Input Error", "X-min must be less than X-max")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Generate x values
|
||||||
|
x = np.linspace(x_min, x_max, 500)
|
||||||
|
y = a * x**2 + b * x + c
|
||||||
|
|
||||||
|
# Clear previous plot
|
||||||
|
self.ax.clear()
|
||||||
|
self.setup_plot()
|
||||||
|
|
||||||
|
# Determine equation type for title
|
||||||
|
if a != 0:
|
||||||
|
eq_type = "Quadratic Function"
|
||||||
|
elif b != 0:
|
||||||
|
eq_type = "Linear Function"
|
||||||
|
else:
|
||||||
|
eq_type = "Constant Function"
|
||||||
|
|
||||||
|
# Build equation string with only non-zero terms, formatted nicely
|
||||||
|
parts = []
|
||||||
|
if a != 0:
|
||||||
|
if a == 1:
|
||||||
|
parts.append("x²")
|
||||||
|
elif a == -1:
|
||||||
|
parts.append("-x²")
|
||||||
|
else:
|
||||||
|
parts.append(f"{a}x²")
|
||||||
|
if b != 0:
|
||||||
|
if b == 1:
|
||||||
|
parts.append("+ x" if parts else "x")
|
||||||
|
elif b == -1:
|
||||||
|
parts.append("- x" if parts else "-x")
|
||||||
|
else:
|
||||||
|
sign = "+" if b > 0 else "-"
|
||||||
|
parts.append(f"{sign} {abs(b)}x")
|
||||||
|
if c != 0:
|
||||||
|
sign = "+" if c > 0 else "-"
|
||||||
|
parts.append(f"{sign} {abs(c)}")
|
||||||
|
|
||||||
|
if not parts:
|
||||||
|
eq_str = "y = 0"
|
||||||
|
else:
|
||||||
|
# First term without leading plus
|
||||||
|
first = parts[0]
|
||||||
|
if first.startswith("+ "):
|
||||||
|
first = first[2:]
|
||||||
|
elif first.startswith("- "):
|
||||||
|
first = f"-{first[2:]}"
|
||||||
|
eq_str = "y = " + first + " " + " ".join(parts[1:])
|
||||||
|
|
||||||
|
self.ax.set_title(f"{eq_type}: {eq_str}")
|
||||||
|
|
||||||
|
# Plot the quadratic
|
||||||
|
self.ax.plot(x, y, 'b-', linewidth=2, label=eq_str)
|
||||||
|
|
||||||
|
# Calculate and plot vertex
|
||||||
|
if a != 0:
|
||||||
|
vertex_x = -b / (2 * a)
|
||||||
|
vertex_y = a * vertex_x**2 + b * vertex_x + c
|
||||||
|
self.ax.plot(vertex_x, vertex_y, 'ro', markersize=8, label=f'Vertex ({vertex_x:.2f}, {vertex_y:.2f})')
|
||||||
|
|
||||||
|
# Calculate and plot roots if they exist (real roots)
|
||||||
|
discriminant = b**2 - 4*a*c
|
||||||
|
|
||||||
|
# Handle quadratic case (a ≠ 0)
|
||||||
|
if a != 0:
|
||||||
|
if discriminant >= 0:
|
||||||
|
root1 = (-b + np.sqrt(discriminant)) / (2 * a)
|
||||||
|
root2 = (-b - np.sqrt(discriminant)) / (2 * a)
|
||||||
|
# For discriminant == 0, both roots are the same
|
||||||
|
if abs(root1 - root2) < 1e-10: # Essentially equal
|
||||||
|
self.ax.plot(root1, 0, 'go', markersize=8, label=f'Double Root ({root1:.2f}, 0)')
|
||||||
|
else:
|
||||||
|
self.ax.plot(root1, 0, 'go', markersize=8, label=f'Root1 ({root1:.2f}, 0)')
|
||||||
|
self.ax.plot(root2, 0, 'go', markersize=8, label=f'Root2 ({root2:.2f}, 0)')
|
||||||
|
else:
|
||||||
|
# Complex roots - show message in legend
|
||||||
|
self.ax.text(0.02, 0.02, 'Complex Roots', transform=self.ax.transAxes,
|
||||||
|
fontsize=10, color='red', bbox=dict(boxstyle='round', facecolor='yellow', alpha=0.5))
|
||||||
|
# Handle linear case (a = 0, b ≠ 0)
|
||||||
|
elif b != 0:
|
||||||
|
root = -c / b
|
||||||
|
self.ax.plot(root, 0, 'go', markersize=8, label=f'Root ({root:.2f}, 0)')
|
||||||
|
# Handle constant case (a = 0, b = 0)
|
||||||
|
else:
|
||||||
|
if c == 0:
|
||||||
|
self.ax.text(0.02, 0.02, 'Infinite Roots (y = 0)', transform=self.ax.transAxes,
|
||||||
|
fontsize=10, color='blue', bbox=dict(boxstyle='round', facecolor='lightblue', alpha=0.5))
|
||||||
|
else:
|
||||||
|
self.ax.text(0.02, 0.02, 'No Roots (horizontal line)', transform=self.ax.transAxes,
|
||||||
|
fontsize=10, color='red', bbox=dict(boxstyle='round', facecolor='lightcoral', alpha=0.5))
|
||||||
|
|
||||||
|
# Add legend
|
||||||
|
self.ax.legend(loc='best')
|
||||||
|
|
||||||
|
# Refresh canvas
|
||||||
|
self.canvas.draw()
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
messagebox.showerror("Input Error", "Please enter valid numbers for all coefficients and range")
|
||||||
|
|
||||||
|
def clear_plot(self):
|
||||||
|
"""Clear the plot"""
|
||||||
|
self.ax.clear()
|
||||||
|
self.setup_plot()
|
||||||
|
self.canvas.draw()
|
||||||
|
|
||||||
|
def save_plot(self):
|
||||||
|
"""Save the current plot to a file"""
|
||||||
|
try:
|
||||||
|
from tkinter import filedialog
|
||||||
|
import os
|
||||||
|
|
||||||
|
filetypes = [
|
||||||
|
('PNG files', '*.png'),
|
||||||
|
('JPEG files', '*.jpg'),
|
||||||
|
('PDF files', '*.pdf'),
|
||||||
|
('SVG files', '*.svg'),
|
||||||
|
('All files', '*.*')
|
||||||
|
]
|
||||||
|
|
||||||
|
filename = filedialog.asksaveasfilename(
|
||||||
|
defaultextension=".png",
|
||||||
|
filetypes=filetypes,
|
||||||
|
title="Save Plot As"
|
||||||
|
)
|
||||||
|
|
||||||
|
if filename:
|
||||||
|
self.fig.savefig(filename, dpi=300, bbox_inches='tight')
|
||||||
|
messagebox.showinfo("Success", f"Plot saved successfully as:\n{os.path.basename(filename)}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
messagebox.showerror("Save Error", f"Could not save plot: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = QuadraticPlotter()
|
||||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
numpy>=1.21.0
|
||||||
|
matplotlib>=3.5.0
|
||||||
Loading…
Reference in New Issue
Block a user