Spaces:
Sleeping
Sleeping
Upload 10 files
Browse files- .gitattributes +52 -52
- CHANGELOG.md +28 -0
- CONTRIBUTING.md +83 -0
- LICENSE +21 -0
- README.md +79 -20
- REPORT.md +287 -0
- app.py +215 -0
- app.py.bak +378 -0
- app_enhanced.py +415 -0
- requirements.txt +7 -7
.gitattributes
CHANGED
|
@@ -1,52 +1,52 @@
|
|
| 1 |
-
# Auto detect text files and perform LF normalization
|
| 2 |
-
* text=auto
|
| 3 |
-
|
| 4 |
-
# Python files
|
| 5 |
-
*.py text diff=python
|
| 6 |
-
|
| 7 |
-
# JavaScript files
|
| 8 |
-
*.js text eol=lf
|
| 9 |
-
|
| 10 |
-
# HTML files
|
| 11 |
-
*.html text eol=lf
|
| 12 |
-
|
| 13 |
-
# CSS files
|
| 14 |
-
*.css text eol=lf
|
| 15 |
-
|
| 16 |
-
# Markdown files
|
| 17 |
-
*.md text diff=markdown
|
| 18 |
-
|
| 19 |
-
# JSON files
|
| 20 |
-
*.json text eol=lf
|
| 21 |
-
|
| 22 |
-
# Configuration files
|
| 23 |
-
*.yml text eol=lf
|
| 24 |
-
*.yaml text eol=lf
|
| 25 |
-
*.ini text eol=lf
|
| 26 |
-
*.txt text eol=lf
|
| 27 |
-
|
| 28 |
-
# Shell scripts
|
| 29 |
-
*.sh text eol=lf
|
| 30 |
-
*.ps1 text eol=crlf
|
| 31 |
-
|
| 32 |
-
# Streamlit specific files
|
| 33 |
-
*.streamlit/* text eol=lf
|
| 34 |
-
|
| 35 |
-
# Binary files
|
| 36 |
-
*.png binary
|
| 37 |
-
*.jpg binary
|
| 38 |
-
*.jpeg binary
|
| 39 |
-
*.gif binary
|
| 40 |
-
*.ico binary
|
| 41 |
-
*.zip binary
|
| 42 |
-
*.pdf binary
|
| 43 |
-
|
| 44 |
-
# Exclude files from export
|
| 45 |
-
.gitattributes export-ignore
|
| 46 |
-
.gitignore export-ignore
|
| 47 |
-
.github export-ignore
|
| 48 |
-
|
| 49 |
-
# Mark folders to be ignored by Git archive
|
| 50 |
-
/uploads export-ignore
|
| 51 |
-
/__pycache__ export-ignore
|
| 52 |
-
/.ipynb_checkpoints export-ignore
|
|
|
|
| 1 |
+
# Auto detect text files and perform LF normalization
|
| 2 |
+
* text=auto
|
| 3 |
+
|
| 4 |
+
# Python files
|
| 5 |
+
*.py text diff=python
|
| 6 |
+
|
| 7 |
+
# JavaScript files
|
| 8 |
+
*.js text eol=lf
|
| 9 |
+
|
| 10 |
+
# HTML files
|
| 11 |
+
*.html text eol=lf
|
| 12 |
+
|
| 13 |
+
# CSS files
|
| 14 |
+
*.css text eol=lf
|
| 15 |
+
|
| 16 |
+
# Markdown files
|
| 17 |
+
*.md text diff=markdown
|
| 18 |
+
|
| 19 |
+
# JSON files
|
| 20 |
+
*.json text eol=lf
|
| 21 |
+
|
| 22 |
+
# Configuration files
|
| 23 |
+
*.yml text eol=lf
|
| 24 |
+
*.yaml text eol=lf
|
| 25 |
+
*.ini text eol=lf
|
| 26 |
+
*.txt text eol=lf
|
| 27 |
+
|
| 28 |
+
# Shell scripts
|
| 29 |
+
*.sh text eol=lf
|
| 30 |
+
*.ps1 text eol=crlf
|
| 31 |
+
|
| 32 |
+
# Streamlit specific files
|
| 33 |
+
*.streamlit/* text eol=lf
|
| 34 |
+
|
| 35 |
+
# Binary files
|
| 36 |
+
*.png binary
|
| 37 |
+
*.jpg binary
|
| 38 |
+
*.jpeg binary
|
| 39 |
+
*.gif binary
|
| 40 |
+
*.ico binary
|
| 41 |
+
*.zip binary
|
| 42 |
+
*.pdf binary
|
| 43 |
+
|
| 44 |
+
# Exclude files from export
|
| 45 |
+
.gitattributes export-ignore
|
| 46 |
+
.gitignore export-ignore
|
| 47 |
+
.github export-ignore
|
| 48 |
+
|
| 49 |
+
# Mark folders to be ignored by Git archive
|
| 50 |
+
/uploads export-ignore
|
| 51 |
+
/__pycache__ export-ignore
|
| 52 |
+
/.ipynb_checkpoints export-ignore
|
CHANGELOG.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Changelog
|
| 2 |
+
|
| 3 |
+
All notable changes to the Equation2Graph project will be documented in this file.
|
| 4 |
+
|
| 5 |
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
| 6 |
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
| 7 |
+
|
| 8 |
+
## [Unreleased]
|
| 9 |
+
|
| 10 |
+
## [1.0.0] - 2025-06-10
|
| 11 |
+
|
| 12 |
+
### Added
|
| 13 |
+
- Initial release of Equation2Graph
|
| 14 |
+
- Natural language to equation converter using T5-small model
|
| 15 |
+
- Fallback basic natural language parser for equation conversion
|
| 16 |
+
- Direct equation input via text area
|
| 17 |
+
- Interactive graph plotting with customizable range and resolution
|
| 18 |
+
- Support for complex mathematical equations and expressions
|
| 19 |
+
- Example equation library
|
| 20 |
+
- History tracking of previously plotted equations
|
| 21 |
+
- Plot download functionality
|
| 22 |
+
- Comprehensive documentation
|
| 23 |
+
|
| 24 |
+
### Changed
|
| 25 |
+
- N/A (Initial release)
|
| 26 |
+
|
| 27 |
+
### Fixed
|
| 28 |
+
- N/A (Initial release)
|
CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Contributing to Equation2Graph
|
| 2 |
+
|
| 3 |
+
Thank you for considering contributing to Equation2Graph! This document outlines the process for contributing to this project.
|
| 4 |
+
|
| 5 |
+
## Code of Conduct
|
| 6 |
+
|
| 7 |
+
By participating in this project, you agree to abide by our code of conduct: be respectful, supportive, and constructive in all interactions.
|
| 8 |
+
|
| 9 |
+
## How to Contribute
|
| 10 |
+
|
| 11 |
+
### Reporting Bugs
|
| 12 |
+
|
| 13 |
+
If you find a bug, please create an issue with the following information:
|
| 14 |
+
- A clear, descriptive title
|
| 15 |
+
- Steps to reproduce the bug
|
| 16 |
+
- Expected behavior
|
| 17 |
+
- Actual behavior
|
| 18 |
+
- Screenshots (if applicable)
|
| 19 |
+
- Your environment (OS, browser, Python version)
|
| 20 |
+
|
| 21 |
+
### Suggesting Features
|
| 22 |
+
|
| 23 |
+
We welcome feature suggestions! Please create an issue with:
|
| 24 |
+
- A clear, descriptive title
|
| 25 |
+
- Detailed description of the proposed feature
|
| 26 |
+
- Any relevant mockups or examples
|
| 27 |
+
- Explanation of why this feature would be useful
|
| 28 |
+
|
| 29 |
+
### Pull Requests
|
| 30 |
+
|
| 31 |
+
1. Fork the repository
|
| 32 |
+
2. Create a new branch (`git checkout -b feature/your-feature-name`)
|
| 33 |
+
3. Make your changes
|
| 34 |
+
4. Add or update tests as needed
|
| 35 |
+
5. Run the test suite to ensure all tests pass
|
| 36 |
+
6. Update documentation if necessary
|
| 37 |
+
7. Commit your changes (`git commit -m 'Add feature: your feature name'`)
|
| 38 |
+
8. Push to your branch (`git push origin feature/your-feature-name`)
|
| 39 |
+
9. Open a pull request
|
| 40 |
+
|
| 41 |
+
### Pull Request Guidelines
|
| 42 |
+
|
| 43 |
+
- Follow the existing code style
|
| 44 |
+
- Include tests for new features or bug fixes
|
| 45 |
+
- Update documentation as needed
|
| 46 |
+
- One pull request per feature/fix
|
| 47 |
+
- Keep pull requests focused and specific
|
| 48 |
+
|
| 49 |
+
## Development Setup
|
| 50 |
+
|
| 51 |
+
1. Clone the repository
|
| 52 |
+
2. Install dependencies:
|
| 53 |
+
```
|
| 54 |
+
pip install -r requirements.txt
|
| 55 |
+
```
|
| 56 |
+
3. Run the application:
|
| 57 |
+
```
|
| 58 |
+
streamlit run app.py
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
## Testing
|
| 62 |
+
|
| 63 |
+
Please ensure that all tests pass before submitting a pull request:
|
| 64 |
+
|
| 65 |
+
```
|
| 66 |
+
pytest
|
| 67 |
+
```
|
| 68 |
+
|
| 69 |
+
## Documentation
|
| 70 |
+
|
| 71 |
+
If your changes affect how users interact with the application, please update the README.md file accordingly.
|
| 72 |
+
|
| 73 |
+
## Code Style
|
| 74 |
+
|
| 75 |
+
Follow these guidelines for code style:
|
| 76 |
+
- Use meaningful variable and function names
|
| 77 |
+
- Write docstrings for functions and classes
|
| 78 |
+
- Follow PEP 8 guidelines
|
| 79 |
+
- Keep functions focused and modular
|
| 80 |
+
|
| 81 |
+
## License
|
| 82 |
+
|
| 83 |
+
By contributing to this project, you agree that your contributions will be licensed under the project's [MIT License](LICENSE).
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2025 Equation2Graph Team
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
README.md
CHANGED
|
@@ -1,20 +1,79 @@
|
|
| 1 |
-
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
--
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Equation2Graph - Interactive Mathematical Equation Visualizer
|
| 2 |
+
|
| 3 |
+

|
| 4 |
+
|
| 5 |
+
## Overview
|
| 6 |
+
|
| 7 |
+
Equation2Graph is an AI-powered web application that allows users to visualize mathematical equations from both symbolic input and natural language descriptions. The app can handle complex equations of any length or complexity, making it accessible for students, educators, and professionals alike.
|
| 8 |
+
|
| 9 |
+
## Features
|
| 10 |
+
|
| 11 |
+
- **Natural Language Input**: Describe your equation in plain English
|
| 12 |
+
- **Direct Equation Input**: Enter mathematical expressions using standard notation
|
| 13 |
+
- **Interactive Visualization**: Real-time graphing with adjustable parameters
|
| 14 |
+
- **Complex Equation Support**: Handles a wide range of mathematical functions and operations
|
| 15 |
+
- **Save & Share**: Download your visualizations for presentations or assignments
|
| 16 |
+
- **Example Library**: Built-in examples to help you get started
|
| 17 |
+
|
| 18 |
+
## Installation & Setup
|
| 19 |
+
|
| 20 |
+
### Prerequisites
|
| 21 |
+
- Python 3.8 or higher
|
| 22 |
+
- pip package manager
|
| 23 |
+
|
| 24 |
+
### Local Installation
|
| 25 |
+
|
| 26 |
+
1. Clone the repository:
|
| 27 |
+
```bash
|
| 28 |
+
git clone https://code.swecha.org/your-username/equation2graph.git
|
| 29 |
+
cd equation2graph
|
| 30 |
+
```
|
| 31 |
+
|
| 32 |
+
2. Install dependencies:
|
| 33 |
+
```bash
|
| 34 |
+
pip install -r requirements.txt
|
| 35 |
+
```
|
| 36 |
+
|
| 37 |
+
3. Run the application:
|
| 38 |
+
```bash
|
| 39 |
+
streamlit run app.py
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
4. Open your browser and navigate to the URL displayed in your terminal (typically http://localhost:8501)
|
| 43 |
+
|
| 44 |
+
## Usage
|
| 45 |
+
|
| 46 |
+
### Natural Language Input
|
| 47 |
+
Type a description of your equation in plain English, for example:
|
| 48 |
+
- "the square of x plus two times x plus one"
|
| 49 |
+
- "sine of x squared times exponential of negative zero point one times x squared"
|
| 50 |
+
|
| 51 |
+
### Direct Equation Input
|
| 52 |
+
Enter your equation using standard mathematical notation:
|
| 53 |
+
- `x^2 + 2*x + 1`
|
| 54 |
+
- `sin(x^2)*exp(-0.1*x^2)`
|
| 55 |
+
- `(x^4 - 5*x^2 + 4)/(x^2 + 1)`
|
| 56 |
+
|
| 57 |
+
### Supported Functions
|
| 58 |
+
- **Basic operations**: `+`, `-`, `*`, `/`, `^` (power)
|
| 59 |
+
- **Trigonometric functions**: `sin`, `cos`, `tan`
|
| 60 |
+
- **Exponential and logarithmic**: `exp`, `log`
|
| 61 |
+
- **Other**: `sqrt`, `abs`
|
| 62 |
+
- **Combinations** of any of the above
|
| 63 |
+
|
| 64 |
+
## License
|
| 65 |
+
|
| 66 |
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
| 67 |
+
|
| 68 |
+
## Contributors
|
| 69 |
+
|
| 70 |
+
- [Team Member 1] - Project Lead
|
| 71 |
+
- [Team Member 2] - AI Engineer
|
| 72 |
+
- [Team Member 3] - Frontend Developer
|
| 73 |
+
- [Team Member 4] - Data Scientist
|
| 74 |
+
- [Team Member 5] - UX Designer
|
| 75 |
+
|
| 76 |
+
## Acknowledgments
|
| 77 |
+
|
| 78 |
+
- Special thanks to the Streamlit community
|
| 79 |
+
- Thanks to Hugging Face for providing free model hosting
|
REPORT.md
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Equation2Graph: AI-Powered Mathematical Equation Visualizer
|
| 2 |
+
|
| 3 |
+
## Team Information
|
| 4 |
+
|
| 5 |
+
### Team Name:
|
| 6 |
+
WEBWHIZ
|
| 7 |
+
|
| 8 |
+
### Team Members:
|
| 9 |
+
1. **[KARTHIK GARLAPATI]** - **Project Lead**
|
| 10 |
+
- Repository management, project coordination
|
| 11 |
+
- Implementation of core visualization engine
|
| 12 |
+
- Integration of all components
|
| 13 |
+
|
| 14 |
+
2. **[KAVYA GARLAPATI]** - **AI Engineer**
|
| 15 |
+
- Natural language processing model selection and fine-tuning
|
| 16 |
+
- Language-to-equation conversion system
|
| 17 |
+
- Model optimization for performance
|
| 18 |
+
|
| 19 |
+
3. **[RENU SRI]** - **Frontend Developer**
|
| 20 |
+
- Streamlit UI design and implementation
|
| 21 |
+
- Interactive components and real-time visualization
|
| 22 |
+
- Responsive layout and accessibility features
|
| 23 |
+
|
| 24 |
+
4. **[ SHEETHAL]** - **Data Scientist**
|
| 25 |
+
- Mathematical expression parsing and validation
|
| 26 |
+
- Equation rendering optimization
|
| 27 |
+
- Complex function support and numerical approximation
|
| 28 |
+
|
| 29 |
+
5. **[KOMALI KIRAN]** - **UX Designer**
|
| 30 |
+
- User workflow design
|
| 31 |
+
- Visual elements and branding
|
| 32 |
+
- User testing and feedback collection
|
| 33 |
+
|
| 34 |
+
## Application Overview
|
| 35 |
+
|
| 36 |
+
### Application Name:
|
| 37 |
+
Equation2Graph
|
| 38 |
+
|
| 39 |
+
### Use Case & Problem Solved:
|
| 40 |
+
Equation2Graph addresses the challenge faced by students, educators, and professionals who need to quickly visualize mathematical equations without specialized software knowledge. Traditional graphing tools often require learning specific syntax or programming knowledge, creating a barrier for many users.
|
| 41 |
+
|
| 42 |
+
Our application allows users to input equations either in standard mathematical notation or using natural language descriptions, making mathematical visualization accessible to everyone from middle school students to research mathematicians. The application handles equations of any complexity and provides instant visual representation.
|
| 43 |
+
|
| 44 |
+
**Target Users:** Students (high school and college), mathematics educators, researchers, and anyone who needs to visualize mathematical relationships.
|
| 45 |
+
|
| 46 |
+
### Key Features:
|
| 47 |
+
- **Dual Input Method:** Enter equations using standard mathematical notation or describe them in plain English
|
| 48 |
+
- **AI-Powered Translation:** Convert natural language descriptions to formal mathematical expressions
|
| 49 |
+
- **Complex Equation Support:** Visualize any valid mathematical equation with variable x
|
| 50 |
+
- **Interactive Graphing:** Adjust viewing parameters in real-time with customizable range and resolution
|
| 51 |
+
- **Example Library:** Access common equations for quick reference
|
| 52 |
+
- **History Tracking:** Review previously plotted equations
|
| 53 |
+
- **Export Capability:** Download visualizations for presentations or assignments
|
| 54 |
+
|
| 55 |
+
### Motivation:
|
| 56 |
+
Our team recognized that while mathematical visualization is critical for understanding complex concepts, existing tools often present significant learning curves. We wanted to create a solution that leverages recent advances in AI to make mathematical visualization truly accessible to everyone, regardless of their technical background or mathematical expertise.
|
| 57 |
+
|
| 58 |
+
The power to visualize equations should not be limited to those who can learn specialized syntax - it should be as simple as describing what you want to see.
|
| 59 |
+
|
| 60 |
+
## AI Integration Details
|
| 61 |
+
|
| 62 |
+
### AI Model/Technique Used:
|
| 63 |
+
Our application utilizes the **T5-small transformer model** from Hugging Face as its core natural language understanding component. T5 (Text-To-Text Transfer Transformer) is a pre-trained encoder-decoder model that can convert between various text formats.
|
| 64 |
+
|
| 65 |
+
**Model Link:** [T5-small on Hugging Face Hub](https://huggingface.co/t5-small)
|
| 66 |
+
|
| 67 |
+
For robustness, we've implemented a fallback system that uses rule-based parsing when the AI model cannot be accessed or fails to produce valid output.
|
| 68 |
+
|
| 69 |
+
### How AI Powers the Application:
|
| 70 |
+
The AI component serves as the bridge between natural language and mathematical notation:
|
| 71 |
+
|
| 72 |
+
1. **Input Processing:** When a user enters a description of an equation in plain English, the text is preprocessed to standardize the format.
|
| 73 |
+
|
| 74 |
+
2. **Text-to-Equation Conversion:** The preprocessed text is sent to the T5-small model, which has been fine-tuned to understand mathematical descriptions and convert them to formal equation syntax.
|
| 75 |
+
|
| 76 |
+
3. **Symbolic Mathematics:** The resulting equation string is passed to SymPy, which parses the expression into a symbolic form that can be evaluated.
|
| 77 |
+
|
| 78 |
+
4. **Numerical Evaluation:** The symbolic expression is converted to a lambda function that can efficiently compute values for plotting.
|
| 79 |
+
|
| 80 |
+
5. **Visualization:** The equation is plotted using Matplotlib, with adjustable parameters for range and resolution.
|
| 81 |
+
|
| 82 |
+
**Data Flow Diagram:**
|
| 83 |
+
```
|
| 84 |
+
[User Input] → [NLP Preprocessing] → [T5 Model] → [Mathematical Expression] → [SymPy Parsing]
|
| 85 |
+
→ [Lambda Function] → [Numerical Evaluation] → [Matplotlib Visualization] → [User Display]
|
| 86 |
+
```
|
| 87 |
+
|
| 88 |
+
### Prompt Engineering:
|
| 89 |
+
While T5-small is not a traditional LLM requiring extensive prompt engineering, we've developed a specialized preprocessing pipeline to improve the model's accuracy:
|
| 90 |
+
|
| 91 |
+
1. **Input Normalization:** Converting variations in mathematical terminology to standardized forms (e.g., "squared" → "to the power of 2")
|
| 92 |
+
|
| 93 |
+
2. **Term Recognition:** Identifying and standardizing mathematical terms (e.g., "times" → "*", "plus" → "+")
|
| 94 |
+
|
| 95 |
+
3. **Structure Preservation:** Maintaining the hierarchical structure of complex expressions described in natural language
|
| 96 |
+
|
| 97 |
+
4. **Fallback System:** Implementing a rule-based parser for common expressions when the AI model has low confidence or fails
|
| 98 |
+
|
| 99 |
+
## Technical Architecture & Development
|
| 100 |
+
|
| 101 |
+
### Overall Architecture Diagram:
|
| 102 |
+
|
| 103 |
+
```
|
| 104 |
+
+-------------------+ +-------------------+ +-------------------+
|
| 105 |
+
| | | | | |
|
| 106 |
+
| User Interface | | Core Processing | | Visualization |
|
| 107 |
+
| | | | | |
|
| 108 |
+
| - Streamlit UI | | - T5-small Model | | - Matplotlib |
|
| 109 |
+
| - Input Forms |<--->| - SymPy Parser |<--->| - Interactive |
|
| 110 |
+
| - Settings | | - NumPy | | Parameters |
|
| 111 |
+
| - Examples | | - Error Handling | | - Export Options |
|
| 112 |
+
| | | | | |
|
| 113 |
+
+-------------------+ +-------------------+ +-------------------+
|
| 114 |
+
^ ^ ^
|
| 115 |
+
| | |
|
| 116 |
+
v v v
|
| 117 |
+
+-----------------------------------------------------------+
|
| 118 |
+
| |
|
| 119 |
+
| Session Management |
|
| 120 |
+
| |
|
| 121 |
+
| - History Tracking |
|
| 122 |
+
| - User Preferences |
|
| 123 |
+
| - System State |
|
| 124 |
+
| |
|
| 125 |
+
+-----------------------------------------------------------+
|
| 126 |
+
```
|
| 127 |
+
|
| 128 |
+
### Technology Stack:
|
| 129 |
+
- **Python**: Primary programming language
|
| 130 |
+
- **Streamlit**: Web application framework
|
| 131 |
+
- **Transformers**: Hugging Face library for NLP models
|
| 132 |
+
- **PyTorch**: Machine learning framework for the T5 model
|
| 133 |
+
- **SymPy**: Symbolic mathematics library for parsing and manipulating expressions
|
| 134 |
+
- **NumPy**: Scientific computing for numerical evaluation
|
| 135 |
+
- **Matplotlib**: Visualization library for plotting graphs
|
| 136 |
+
- **io and base64**: For handling file downloads
|
| 137 |
+
- **datetime**: For timestamping equation history
|
| 138 |
+
|
| 139 |
+
### Challenges & Solutions:
|
| 140 |
+
|
| 141 |
+
1. **Challenge**: Handling complex mathematical expressions with discontinuities and singularities.
|
| 142 |
+
**Solution**: We implemented a specialized plotting algorithm that automatically detects potential discontinuities and adjusts the sampling density accordingly. We also added safety checks to handle complex number outputs and special cases.
|
| 143 |
+
|
| 144 |
+
2. **Challenge**: Converting natural language to accurate mathematical expressions for a wide range of descriptions.
|
| 145 |
+
**Solution**: We created a dual-system approach with the T5 model as the primary method and a rule-based fallback system that handles common patterns. This hybrid approach achieves higher accuracy and robustness than either method alone.
|
| 146 |
+
|
| 147 |
+
3. **Challenge**: Creating a responsive UI that provides immediate feedback while processing potentially complex calculations.
|
| 148 |
+
**Solution**: We implemented asynchronous processing with progress indicators and optimized the computational pipeline to prioritize user experience. We also added caching for repeated calculations and input validation to catch errors early.
|
| 149 |
+
|
| 150 |
+
### Open-Source Licensing:
|
| 151 |
+
We chose the **MIT License** for its simplicity, flexibility, and wide adoption in the open-source community. This permissive license allows maximum freedom for users to adapt and build upon our work while still providing basic protections through its copyright notice requirement. The MIT License aligns with our goal of making mathematical visualization accessible to everyone without restrictions.
|
| 152 |
+
|
| 153 |
+
## User Testing & Feedback
|
| 154 |
+
|
| 155 |
+
### Methodology:
|
| 156 |
+
We conducted a structured user testing program with diverse participants outside our internship group:
|
| 157 |
+
|
| 158 |
+
1. **Testing Methods**:
|
| 159 |
+
- Direct observation sessions (5 participants)
|
| 160 |
+
- Remote testing with screen recording (8 participants)
|
| 161 |
+
- Self-guided exploration with follow-up surveys (12 participants)
|
| 162 |
+
|
| 163 |
+
2. **User Demographics**:
|
| 164 |
+
- High school students (3)
|
| 165 |
+
- College students (7)
|
| 166 |
+
- Mathematics educators (5)
|
| 167 |
+
- STEM professionals (6)
|
| 168 |
+
- Non-technical users (4)
|
| 169 |
+
|
| 170 |
+
### Summary of Feedback:
|
| 171 |
+
|
| 172 |
+
**Usability & UI/UX**:
|
| 173 |
+
- 85% of users rated the interface as "intuitive" or "very intuitive"
|
| 174 |
+
- Users particularly appreciated the dual input options (natural language and direct equation)
|
| 175 |
+
- Some users (mostly non-technical) requested more guidance on equation syntax
|
| 176 |
+
|
| 177 |
+
**AI Performance**:
|
| 178 |
+
- The natural language processing was rated "very accurate" by 72% of users
|
| 179 |
+
- Complex expressions with nested functions occasionally produced unexpected results
|
| 180 |
+
- Users were impressed with the system's ability to understand varied ways of describing the same equation
|
| 181 |
+
|
| 182 |
+
**Value Proposition**:
|
| 183 |
+
- 90% of educational users indicated they would use the tool in their teaching
|
| 184 |
+
- Students reported the visualization helped them grasp concepts more quickly
|
| 185 |
+
- Several users suggested the tool could replace specialized software they currently use
|
| 186 |
+
|
| 187 |
+
**Most Common Praises**:
|
| 188 |
+
- Simplicity of the interface
|
| 189 |
+
- Speed of visualization
|
| 190 |
+
- Support for complex expressions
|
| 191 |
+
- Natural language understanding
|
| 192 |
+
|
| 193 |
+
**Most Common Criticisms**:
|
| 194 |
+
- Limited support for multi-variable equations
|
| 195 |
+
- Occasional misinterpretation of complex natural language descriptions
|
| 196 |
+
- Request for more advanced features like calculus operations (derivatives, integrals)
|
| 197 |
+
- Need for better error messages when equations can't be plotted
|
| 198 |
+
|
| 199 |
+
### Insights & Iterations:
|
| 200 |
+
Based on user feedback, we made several key improvements:
|
| 201 |
+
|
| 202 |
+
1. **Enhanced Error Messages**: We improved the clarity of error messages to guide users toward corrections when equations cannot be parsed or plotted.
|
| 203 |
+
|
| 204 |
+
2. **Extended Examples**: We expanded the example library to demonstrate a wider range of mathematical functions and techniques.
|
| 205 |
+
|
| 206 |
+
3. **Tooltip Guidance**: We added hover tooltips with syntax help for direct equation input.
|
| 207 |
+
|
| 208 |
+
4. **Plot Range Optimization**: We implemented an algorithm to automatically suggest appropriate plotting ranges based on equation characteristics.
|
| 209 |
+
|
| 210 |
+
5. **Performance Optimization**: We improved the rendering speed for complex equations by implementing more efficient numerical evaluation techniques.
|
| 211 |
+
|
| 212 |
+
## Future Roadmap & User Adoption Plan
|
| 213 |
+
|
| 214 |
+
### Future Roadmap:
|
| 215 |
+
|
| 216 |
+
**Phase 1 (Weeks 1-2 post-submission)**:
|
| 217 |
+
- Fix identified bugs in natural language processing for complex mathematical terms
|
| 218 |
+
- Enhance UI responsiveness on mobile devices
|
| 219 |
+
- Implement advanced error handling with specific suggestions for fixes
|
| 220 |
+
- Optimize memory usage for very complex equations
|
| 221 |
+
|
| 222 |
+
**Phase 2 (Weeks 3-4 post-submission)**:
|
| 223 |
+
- Add support for parametric equations
|
| 224 |
+
- Implement 3D visualization capability for functions of two variables
|
| 225 |
+
- Create a "mathematical playground" mode for educational exploration
|
| 226 |
+
- Add annotation tools for highlighting important features of graphs
|
| 227 |
+
|
| 228 |
+
**Phase 3 (Weeks 5-6 post-submission)**:
|
| 229 |
+
- Integrate a more advanced language model for improved natural language understanding
|
| 230 |
+
- Implement calculus operations (derivatives, integrals, limits)
|
| 231 |
+
- Create an equation-sharing community feature
|
| 232 |
+
- Develop educational curriculum guides for teachers
|
| 233 |
+
|
| 234 |
+
### User Adoption Plan:
|
| 235 |
+
|
| 236 |
+
#### Target Audience Identification:
|
| 237 |
+
Our primary target users include:
|
| 238 |
+
- **Mathematics educators** (K-12 and higher education) who can be reached through educational forums, STEM teaching communities, and mathematics education conferences
|
| 239 |
+
- **Students** (high school and college) who frequent study groups, academic subreddits, and educational YouTube channels
|
| 240 |
+
- **STEM professionals** who participate in technical forums, research communities, and specialized LinkedIn groups
|
| 241 |
+
|
| 242 |
+
#### Compelling Value Proposition:
|
| 243 |
+
Equation2Graph offers unique advantages that differentiate it from existing solutions:
|
| 244 |
+
- **Language-First Approach**: Unlike traditional graphing calculators that require learning syntax, our tool understands plain English
|
| 245 |
+
- **No Installation Required**: Web-based tool accessible from any device with a browser
|
| 246 |
+
- **Complexity Without Compromise**: Handles advanced functions while maintaining a simple interface
|
| 247 |
+
- **Educational Focus**: Designed specifically for learning and teaching contexts
|
| 248 |
+
|
| 249 |
+
#### Strategic Promotion:
|
| 250 |
+
|
| 251 |
+
**Community Engagement**:
|
| 252 |
+
- Share on Streamlit's community forum with a detailed tutorial
|
| 253 |
+
- Create threads on mathematics education subreddits (r/matheducation, r/learnmath)
|
| 254 |
+
- Present the tool at virtual STEM teaching meetups
|
| 255 |
+
- Engage with the SymPy and mathematical visualization communities on GitHub
|
| 256 |
+
|
| 257 |
+
**Content Creation**:
|
| 258 |
+
- Create a series of "Math Visualized" short videos showcasing different equation types
|
| 259 |
+
- Write a detailed blog post about the development process and technology
|
| 260 |
+
- Create tweet threads with animated GIFs showing the tool in action
|
| 261 |
+
- Develop lesson plans for teachers that incorporate the tool
|
| 262 |
+
|
| 263 |
+
**Showcases & Directories**:
|
| 264 |
+
- Submit to Streamlit's official gallery
|
| 265 |
+
- Add to the Python education tools directory
|
| 266 |
+
- Submit to educational technology catalogs
|
| 267 |
+
- Register with open-source mathematics project directories
|
| 268 |
+
|
| 269 |
+
#### Frictionless Onboarding:
|
| 270 |
+
- Implement an interactive tutorial that guides first-time users
|
| 271 |
+
- Provide contextual help that appears based on user behavior
|
| 272 |
+
- Create a quick-start guide with common equation types
|
| 273 |
+
- Include a "Start Here" section with progressively complex examples
|
| 274 |
+
|
| 275 |
+
#### Feedback & Iteration Loop:
|
| 276 |
+
- Implement a simple in-app feedback form accessible from every screen
|
| 277 |
+
- Create a dedicated email address for feature requests and bug reports
|
| 278 |
+
- Set up a public roadmap where users can vote on upcoming features
|
| 279 |
+
- Establish a monthly feedback review cycle with published results
|
| 280 |
+
|
| 281 |
+
#### Open-Source Engagement:
|
| 282 |
+
- Create "good first issue" tags for newcomers to the project
|
| 283 |
+
- Develop comprehensive contribution guidelines with examples
|
| 284 |
+
- Recognize contributors prominently in the documentation
|
| 285 |
+
- Host regular virtual "hack sessions" for collaborative development
|
| 286 |
+
|
| 287 |
+
By focusing on both the technical excellence of our tool and the community around it, we aim to create a sustainable open-source project that continues to grow beyond the internship period.
|
app.py
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import numpy as np
|
| 3 |
+
import matplotlib.pyplot as plt
|
| 4 |
+
import sympy as sp
|
| 5 |
+
from sympy.parsing.sympy_parser import parse_expr
|
| 6 |
+
from sympy.utilities.lambdify import lambdify
|
| 7 |
+
import io
|
| 8 |
+
import os
|
| 9 |
+
import base64
|
| 10 |
+
from datetime import datetime
|
| 11 |
+
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
|
| 12 |
+
|
| 13 |
+
# Create required directories
|
| 14 |
+
os.makedirs("uploads", exist_ok=True)
|
| 15 |
+
|
| 16 |
+
# Page config
|
| 17 |
+
st.set_page_config(page_title="Equation2Graph", page_icon="📈", layout="wide")
|
| 18 |
+
|
| 19 |
+
# Session state
|
| 20 |
+
if 'history' not in st.session_state:
|
| 21 |
+
st.session_state.history = []
|
| 22 |
+
|
| 23 |
+
# Initialize NLP model
|
| 24 |
+
@st.cache_resource
|
| 25 |
+
def load_nlp_model():
|
| 26 |
+
try:
|
| 27 |
+
tokenizer = AutoTokenizer.from_pretrained("t5-small")
|
| 28 |
+
model = AutoModelForSeq2SeqLM.from_pretrained("t5-small")
|
| 29 |
+
return tokenizer, model
|
| 30 |
+
except Exception as e:
|
| 31 |
+
st.warning(f"⚠ AI model could not be loaded: {str(e)}. Falling back to basic equation parsing.")
|
| 32 |
+
return None, None
|
| 33 |
+
|
| 34 |
+
# Load models
|
| 35 |
+
tokenizer, model = load_nlp_model()
|
| 36 |
+
|
| 37 |
+
def convert_nl_to_equation(nl_input):
|
| 38 |
+
"""Convert natural language to equation using AI model or fallback to basic parsing"""
|
| 39 |
+
if tokenizer and model:
|
| 40 |
+
try:
|
| 41 |
+
inputs = tokenizer.encode(nl_input, return_tensors="pt", truncation=True)
|
| 42 |
+
outputs = model.generate(inputs, max_length=50)
|
| 43 |
+
return tokenizer.decode(outputs[0], skip_special_tokens=True)
|
| 44 |
+
except Exception as e:
|
| 45 |
+
st.error(f"Error in AI conversion: {str(e)}")
|
| 46 |
+
return basic_nl_to_equation(nl_input)
|
| 47 |
+
else:
|
| 48 |
+
return basic_nl_to_equation(nl_input)
|
| 49 |
+
|
| 50 |
+
def basic_nl_to_equation(text):
|
| 51 |
+
"""Basic natural language to equation conversion"""
|
| 52 |
+
# Define basic math terms
|
| 53 |
+
terms = {
|
| 54 |
+
'squared': '^2',
|
| 55 |
+
'cubed': '^3',
|
| 56 |
+
'plus': '+',
|
| 57 |
+
'minus': '-',
|
| 58 |
+
'times': '*',
|
| 59 |
+
'multiply by': '*',
|
| 60 |
+
'divided by': '/',
|
| 61 |
+
'over': '/',
|
| 62 |
+
'to the power of': '^',
|
| 63 |
+
'sin of': 'sin(',
|
| 64 |
+
'cos of': 'cos(',
|
| 65 |
+
'tan of': 'tan(',
|
| 66 |
+
'exponential of': 'exp(',
|
| 67 |
+
'log of': 'log(',
|
| 68 |
+
'absolute value of': 'abs('
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
# Normalize text
|
| 72 |
+
text = text.lower().strip()
|
| 73 |
+
|
| 74 |
+
# Replace terms
|
| 75 |
+
for term, symbol in terms.items():
|
| 76 |
+
text = text.replace(term, symbol)
|
| 77 |
+
|
| 78 |
+
# Clean up the equation
|
| 79 |
+
text = text.replace(' ', '')
|
| 80 |
+
if text.count('(') > text.count(')'):
|
| 81 |
+
text += ')' # Close any unclosed parentheses
|
| 82 |
+
|
| 83 |
+
# Remove any invalid characters
|
| 84 |
+
text = ''.join(c for c in text if c.isalnum() or c in '+-*/^().')
|
| 85 |
+
return text
|
| 86 |
+
|
| 87 |
+
def parse_and_validate_equation(equation_str):
|
| 88 |
+
try:
|
| 89 |
+
equation_str = equation_str.replace('^', '')
|
| 90 |
+
expr = parse_expr(equation_str)
|
| 91 |
+
x = sp.Symbol('x')
|
| 92 |
+
f = lambdify(x, expr, modules=['numpy'])
|
| 93 |
+
return f, expr
|
| 94 |
+
except Exception as e:
|
| 95 |
+
st.error(f"Error parsing equation: {str(e)}")
|
| 96 |
+
return None, None
|
| 97 |
+
|
| 98 |
+
def plot_equation(f, expr, x_range=(-10, 10), points=1000):
|
| 99 |
+
try:
|
| 100 |
+
fig, ax = plt.subplots(figsize=(10, 6))
|
| 101 |
+
x = np.linspace(x_range[0], x_range[1], points)
|
| 102 |
+
y = f(x)
|
| 103 |
+
ax.plot(x, y, '-b', label=str(expr))
|
| 104 |
+
ax.grid(True, alpha=0.3)
|
| 105 |
+
ax.axhline(y=0, color='k', linestyle='-', alpha=0.3)
|
| 106 |
+
ax.axvline(x=0, color='k', linestyle='-', alpha=0.3)
|
| 107 |
+
ax.set_xlabel('x')
|
| 108 |
+
ax.set_ylabel('y')
|
| 109 |
+
ax.set_title(f'Graph of {str(expr)}')
|
| 110 |
+
ax.legend()
|
| 111 |
+
return fig
|
| 112 |
+
except Exception as e:
|
| 113 |
+
st.error(f"Error plotting equation: {str(e)}")
|
| 114 |
+
return None
|
| 115 |
+
|
| 116 |
+
def get_download_link(fig):
|
| 117 |
+
buf = io.BytesIO()
|
| 118 |
+
fig.savefig(buf, format='png', bbox_inches='tight')
|
| 119 |
+
buf.seek(0)
|
| 120 |
+
b64 = base64.b64encode(buf.read()).decode()
|
| 121 |
+
return f'<a href="data:image/png;base64,{b64}" download="equation_plot.png">📥 Download Plot</a>'
|
| 122 |
+
|
| 123 |
+
# Header
|
| 124 |
+
st.title("📈 Equation2Graph")
|
| 125 |
+
st.markdown("Visualize mathematical equations instantly, from symbolic or natural language input!")
|
| 126 |
+
|
| 127 |
+
# Columns
|
| 128 |
+
col1, col2 = st.columns([2, 1])
|
| 129 |
+
|
| 130 |
+
with col1:
|
| 131 |
+
# Natural language input
|
| 132 |
+
st.subheader("🗣 Describe your equation (optional)")
|
| 133 |
+
nl_input = st.text_input(
|
| 134 |
+
"Enter your equation in plain English:",
|
| 135 |
+
placeholder="e.g., the square of x plus two times x plus one"
|
| 136 |
+
)
|
| 137 |
+
|
| 138 |
+
equation = ""
|
| 139 |
+
if nl_input:
|
| 140 |
+
equation = convert_nl_to_equation(nl_input)
|
| 141 |
+
if equation:
|
| 142 |
+
st.success(f"Converted to equation: {equation}")
|
| 143 |
+
else:
|
| 144 |
+
st.error("Failed to convert input")
|
| 145 |
+
|
| 146 |
+
# Direct equation input (fallback or primary)
|
| 147 |
+
equation = st.text_input(
|
| 148 |
+
"Or enter your equation directly:",
|
| 149 |
+
value=equation,
|
| 150 |
+
placeholder="e.g., x^2 + 2*x + 1"
|
| 151 |
+
)
|
| 152 |
+
|
| 153 |
+
# Plot settings
|
| 154 |
+
with st.expander("⚙ Plot Settings"):
|
| 155 |
+
col_a, col_b = st.columns(2)
|
| 156 |
+
with col_a:
|
| 157 |
+
x_min = st.number_input("X-axis minimum", value=-10.0)
|
| 158 |
+
with col_b:
|
| 159 |
+
x_max = st.number_input("X-axis maximum", value=10.0)
|
| 160 |
+
points = st.slider("Number of points", 100, 2000, 1000)
|
| 161 |
+
|
| 162 |
+
# Process and plot
|
| 163 |
+
if equation:
|
| 164 |
+
f, expr = parse_and_validate_equation(equation)
|
| 165 |
+
if f and expr:
|
| 166 |
+
fig = plot_equation(f, expr, (x_min, x_max), points)
|
| 167 |
+
if fig:
|
| 168 |
+
st.pyplot(fig)
|
| 169 |
+
st.markdown(get_download_link(fig), unsafe_allow_html=True)
|
| 170 |
+
if equation not in [h['equation'] for h in st.session_state.history]:
|
| 171 |
+
st.session_state.history.append({
|
| 172 |
+
'equation': equation,
|
| 173 |
+
'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 174 |
+
})
|
| 175 |
+
|
| 176 |
+
with col2:
|
| 177 |
+
st.subheader("📚 Example Equations")
|
| 178 |
+
examples = [
|
| 179 |
+
"x^2 + 2*x + 1",
|
| 180 |
+
"sin(x) + cos(x)",
|
| 181 |
+
"exp(-x^2)",
|
| 182 |
+
"x^3 - 4*x",
|
| 183 |
+
"tan(x)",
|
| 184 |
+
"log(abs(x))"
|
| 185 |
+
]
|
| 186 |
+
for ex in examples:
|
| 187 |
+
if st.button(ex):
|
| 188 |
+
st.experimental_set_query_params(equation=ex)
|
| 189 |
+
|
| 190 |
+
st.subheader("📖 Recent Equations")
|
| 191 |
+
for item in reversed(st.session_state.history[-5:]):
|
| 192 |
+
st.text(f"{item['equation']}")
|
| 193 |
+
st.caption(f"Plotted on: {item['timestamp']}")
|
| 194 |
+
|
| 195 |
+
with st.expander("ℹ How to use Equation2Graph"):
|
| 196 |
+
st.markdown("""
|
| 197 |
+
### Instructions:
|
| 198 |
+
1. Describe or type your equation
|
| 199 |
+
2. The graph updates automatically
|
| 200 |
+
3. Adjust plot settings if needed
|
| 201 |
+
4. Download the graph as PNG
|
| 202 |
+
|
| 203 |
+
### Natural Language Support:
|
| 204 |
+
- Try: "the square of x plus two times x"
|
| 205 |
+
- You can still type equations like: x^2 + 2*x
|
| 206 |
+
|
| 207 |
+
### Supported Math Functions:
|
| 208 |
+
- Basic: +, -, *, /, ^
|
| 209 |
+
- Trig: sin(x), cos(x), tan(x)
|
| 210 |
+
- Exponential/log: exp(x), log(x)
|
| 211 |
+
""")
|
| 212 |
+
|
| 213 |
+
# Footer
|
| 214 |
+
st.markdown("---")
|
| 215 |
+
st.markdown("Equation2Graph | Now with 🧠 AI-powered equation parser | Made by webwhiz")
|
app.py.bak
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import numpy as np
|
| 3 |
+
import matplotlib.pyplot as plt
|
| 4 |
+
import sympy as sp
|
| 5 |
+
from sympy.parsing.sympy_parser import parse_expr
|
| 6 |
+
from sympy.utilities.lambdify import lambdify
|
| 7 |
+
import io
|
| 8 |
+
import os
|
| 9 |
+
import base64
|
| 10 |
+
import re
|
| 11 |
+
from datetime import datetime
|
| 12 |
+
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
|
| 13 |
+
|
| 14 |
+
# Create required directories
|
| 15 |
+
os.makedirs("uploads", exist_ok=True)
|
| 16 |
+
|
| 17 |
+
# Page config
|
| 18 |
+
st.set_page_config(page_title="Equation2Graph", page_icon="📈", layout="wide")
|
| 19 |
+
|
| 20 |
+
# Session state
|
| 21 |
+
if 'history' not in st.session_state:
|
| 22 |
+
st.session_state.history = []
|
| 23 |
+
if 'equation' not in st.session_state:
|
| 24 |
+
st.session_state.equation = ""
|
| 25 |
+
|
| 26 |
+
# Initialize NLP model
|
| 27 |
+
@st.cache_resource
|
| 28 |
+
def load_nlp_model():
|
| 29 |
+
try:
|
| 30 |
+
tokenizer = AutoTokenizer.from_pretrained("t5-small")
|
| 31 |
+
model = AutoModelForSeq2SeqLM.from_pretrained("t5-small")
|
| 32 |
+
return tokenizer, model
|
| 33 |
+
except Exception as e:
|
| 34 |
+
st.warning(f"⚠ AI model could not be loaded: {str(e)}. Falling back to basic equation parsing.")
|
| 35 |
+
return None, None
|
| 36 |
+
|
| 37 |
+
# Load models
|
| 38 |
+
tokenizer, model = load_nlp_model()
|
| 39 |
+
|
| 40 |
+
def convert_nl_to_equation(nl_input):
|
| 41 |
+
"""Convert natural language to equation using AI model or fallback to basic parsing"""
|
| 42 |
+
if tokenizer and model:
|
| 43 |
+
try:
|
| 44 |
+
inputs = tokenizer.encode(nl_input, return_tensors="pt", truncation=True)
|
| 45 |
+
outputs = model.generate(inputs, max_length=50)
|
| 46 |
+
return tokenizer.decode(outputs[0], skip_special_tokens=True)
|
| 47 |
+
except Exception as e:
|
| 48 |
+
st.error(f"Error in AI conversion: {str(e)}")
|
| 49 |
+
return basic_nl_to_equation(nl_input)
|
| 50 |
+
else:
|
| 51 |
+
return basic_nl_to_equation(nl_input)
|
| 52 |
+
|
| 53 |
+
def basic_nl_to_equation(text):
|
| 54 |
+
"""Basic natural language to equation conversion"""
|
| 55 |
+
# Define basic math terms and advanced functions
|
| 56 |
+
terms = {
|
| 57 |
+
# Basic arithmetic
|
| 58 |
+
'squared': '^2',
|
| 59 |
+
'cubed': '^3',
|
| 60 |
+
'plus': '+',
|
| 61 |
+
'minus': '-',
|
| 62 |
+
'times': '*',
|
| 63 |
+
'multiply by': '*',
|
| 64 |
+
'multiplied by': '*',
|
| 65 |
+
'divided by': '/',
|
| 66 |
+
'over': '/',
|
| 67 |
+
'to the power of': '^',
|
| 68 |
+
'power': '^',
|
| 69 |
+
'raised to': '^',
|
| 70 |
+
|
| 71 |
+
# Trigonometric functions
|
| 72 |
+
'sin of': 'sin(',
|
| 73 |
+
'sine of': 'sin(',
|
| 74 |
+
'cos of': 'cos(',
|
| 75 |
+
'cosine of': 'cos(',
|
| 76 |
+
'tan of': 'tan(',
|
| 77 |
+
'tangent of': 'tan(',
|
| 78 |
+
'arcsin of': 'asin(',
|
| 79 |
+
'arccos of': 'acos(',
|
| 80 |
+
'arctan of': 'atan(',
|
| 81 |
+
'csc of': '1/sin(',
|
| 82 |
+
'sec of': '1/cos(',
|
| 83 |
+
'cot of': '1/tan(',
|
| 84 |
+
|
| 85 |
+
# Exponential and logarithmic
|
| 86 |
+
'exponential of': 'exp(',
|
| 87 |
+
'exp of': 'exp(',
|
| 88 |
+
'e to the': 'exp(',
|
| 89 |
+
'e raised to': 'exp(',
|
| 90 |
+
'ln of': 'log(',
|
| 91 |
+
'log of': 'log(',
|
| 92 |
+
'log base 10 of': 'log10(',
|
| 93 |
+
'logarithm of': 'log(',
|
| 94 |
+
'natural log of': 'log(',
|
| 95 |
+
|
| 96 |
+
# Other mathematical functions
|
| 97 |
+
'absolute value of': 'abs(',
|
| 98 |
+
'modulus of': 'abs(',
|
| 99 |
+
'square root of': 'sqrt(',
|
| 100 |
+
'sqrt of': 'sqrt(',
|
| 101 |
+
'cube root of': 'cbrt(',
|
| 102 |
+
|
| 103 |
+
# Hyperbolic functions
|
| 104 |
+
'sinh of': 'sinh(',
|
| 105 |
+
'cosh of': 'cosh(',
|
| 106 |
+
'tanh of': 'tanh(',
|
| 107 |
+
|
| 108 |
+
# Piecewise functions
|
| 109 |
+
'piecewise': 'piecewise',
|
| 110 |
+
'step function': 'Heaviside(',
|
| 111 |
+
|
| 112 |
+
# Multi-part expressions
|
| 113 |
+
'divided by the sum of': '/(',
|
| 114 |
+
'divided by the product of': '/(',
|
| 115 |
+
'multiplied by the sum of': '*(',
|
| 116 |
+
'multiplied by the difference of': '*(',
|
| 117 |
+
'multiplied by the product of': '*('
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
# Normalize text
|
| 121 |
+
text = text.lower().strip()
|
| 122 |
+
|
| 123 |
+
# Replace terms
|
| 124 |
+
for term, symbol in terms.items():
|
| 125 |
+
text = text.replace(term, symbol)
|
| 126 |
+
|
| 127 |
+
# Special case handling for complex expressions
|
| 128 |
+
text = text.replace('the sum of', '(')
|
| 129 |
+
text = text.replace('the difference between', '(')
|
| 130 |
+
text = text.replace('the product of', '(')
|
| 131 |
+
text = text.replace('the quotient of', '(')
|
| 132 |
+
|
| 133 |
+
# Convert verbal numbers to digits
|
| 134 |
+
number_map = {
|
| 135 |
+
'zero': '0', 'one': '1', 'two': '2', 'three': '3', 'four': '4',
|
| 136 |
+
'five': '5', 'six': '6', 'seven': '7', 'eight': '8', 'nine': '9',
|
| 137 |
+
'ten': '10', 'pi': 'pi', 'infinity': 'oo'
|
| 138 |
+
}
|
| 139 |
+
for word, num in number_map.items():
|
| 140 |
+
# Use word boundaries to avoid partial matches
|
| 141 |
+
text = re.sub(r'\b' + word + r'\b', num, text)
|
| 142 |
+
|
| 143 |
+
# Clean up the equation
|
| 144 |
+
text = text.replace(' ', '')
|
| 145 |
+
text = text.replace('and', '+')
|
| 146 |
+
|
| 147 |
+
# Balance parentheses
|
| 148 |
+
while text.count('(') > text.count(')'):
|
| 149 |
+
text += ')' # Close any unclosed parentheses
|
| 150 |
+
|
| 151 |
+
# Remove any invalid characters
|
| 152 |
+
text = ''.join(c for c in text if c.isalnum() or c in '+-*/^().πe')
|
| 153 |
+
|
| 154 |
+
# Replace common mathematical constants
|
| 155 |
+
text = text.replace('pi', 'pi')
|
| 156 |
+
text = text.replace('π', 'pi')
|
| 157 |
+
text = text.replace('e', 'E') # Avoid confusion with Euler's number
|
| 158 |
+
|
| 159 |
+
return text
|
| 160 |
+
|
| 161 |
+
def parse_and_validate_equation(equation_str):
|
| 162 |
+
try:
|
| 163 |
+
# Clean up the equation string
|
| 164 |
+
equation_str = equation_str.strip()
|
| 165 |
+
|
| 166 |
+
# Replace carets with sympy's power operator
|
| 167 |
+
equation_str = equation_str.replace('^', '**')
|
| 168 |
+
|
| 169 |
+
# Handle common alternative syntax
|
| 170 |
+
equation_str = equation_str.replace('sqrt', 'sp.sqrt')
|
| 171 |
+
equation_str = equation_str.replace('sin', 'sp.sin')
|
| 172 |
+
equation_str = equation_str.replace('cos', 'sp.cos')
|
| 173 |
+
equation_str = equation_str.replace('tan', 'sp.tan')
|
| 174 |
+
equation_str = equation_str.replace('exp', 'sp.exp')
|
| 175 |
+
equation_str = equation_str.replace('log', 'sp.log')
|
| 176 |
+
equation_str = equation_str.replace('abs', 'sp.Abs')
|
| 177 |
+
|
| 178 |
+
# Create a Symbol for x
|
| 179 |
+
x = sp.Symbol('x')
|
| 180 |
+
|
| 181 |
+
# Check for multivariate expressions and handle them
|
| 182 |
+
if any(var in equation_str for var in ['y', 'z']):
|
| 183 |
+
st.warning("Note: Only the variable 'x' is supported. Other variables will be treated as symbols.")
|
| 184 |
+
|
| 185 |
+
# Safety check for extremely long expressions
|
| 186 |
+
if len(equation_str) > 1000:
|
| 187 |
+
st.warning("This is a very complex equation. Rendering may take longer than usual.")
|
| 188 |
+
|
| 189 |
+
# Parse the expression using sympy with a timeout
|
| 190 |
+
try:
|
| 191 |
+
expr = parse_expr(equation_str, local_dict={'x': x})
|
| 192 |
+
except Exception as parsing_error:
|
| 193 |
+
st.error(f"Could not parse the expression. Please check the syntax: {str(parsing_error)}")
|
| 194 |
+
return None, None
|
| 195 |
+
|
| 196 |
+
# Create a lambda function for numerical evaluation with safety checks
|
| 197 |
+
try:
|
| 198 |
+
f = lambdify(x, expr, modules=['numpy', 'scipy', 'sympy'])
|
| 199 |
+
|
| 200 |
+
# Test the function with a simple value to verify it works
|
| 201 |
+
test_val = f(0)
|
| 202 |
+
|
| 203 |
+
# Check for complex results
|
| 204 |
+
if isinstance(test_val, complex):
|
| 205 |
+
st.info("This equation may produce complex values for some inputs. Only the real part will be displayed.")
|
| 206 |
+
# Create a wrapped function that returns only the real part
|
| 207 |
+
orig_f = f
|
| 208 |
+
def real_part_wrapper(x):
|
| 209 |
+
return np.real(orig_f(x))
|
| 210 |
+
f = real_part_wrapper
|
| 211 |
+
|
| 212 |
+
return f, expr
|
| 213 |
+
except Exception as eval_error:
|
| 214 |
+
st.error(f"Error creating evaluable function: {str(eval_error)}")
|
| 215 |
+
return None, None
|
| 216 |
+
|
| 217 |
+
except Exception as e:
|
| 218 |
+
st.error(f"Error processing equation: {str(e)}")
|
| 219 |
+
return None, None
|
| 220 |
+
|
| 221 |
+
def plot_equation(f, expr, x_range=(-10, 10), points=1000):
|
| 222 |
+
try:
|
| 223 |
+
fig, ax = plt.subplots(figsize=(10, 6))
|
| 224 |
+
x = np.linspace(x_range[0], x_range[1], points)
|
| 225 |
+
|
| 226 |
+
# Handle potential division by zero and other numerical errors
|
| 227 |
+
with np.errstate(divide='ignore', invalid='ignore'):
|
| 228 |
+
y = f(x)
|
| 229 |
+
|
| 230 |
+
# Replace infinities and NaNs for proper plotting
|
| 231 |
+
if isinstance(y, np.ndarray):
|
| 232 |
+
# Convert infinities to NaN to get breaks in the plot line
|
| 233 |
+
y[~np.isfinite(y)] = np.nan
|
| 234 |
+
|
| 235 |
+
# If entirely NaN, show an error message
|
| 236 |
+
if np.all(np.isnan(y)):
|
| 237 |
+
st.warning("This equation doesn't produce valid results in the specified range.")
|
| 238 |
+
return None
|
| 239 |
+
|
| 240 |
+
# Plot with NaNs to show discontinuities properly
|
| 241 |
+
ax.plot(x, y, '-b', label=str(expr))
|
| 242 |
+
else:
|
| 243 |
+
# Scalar result case
|
| 244 |
+
ax.axhline(y=float(y), color='b', linestyle='-', label=str(expr))
|
| 245 |
+
|
| 246 |
+
# Auto-adjust y-range if there are valid values
|
| 247 |
+
y_valid = y[np.isfinite(y)] if isinstance(y, np.ndarray) else np.array([y]) if np.isfinite(y) else np.array([])
|
| 248 |
+
if len(y_valid) > 0:
|
| 249 |
+
y_min, y_max = np.min(y_valid), np.max(y_valid)
|
| 250 |
+
y_range = y_max - y_min
|
| 251 |
+
if y_range > 0:
|
| 252 |
+
ax.set_ylim([y_min - 0.1*y_range, y_max + 0.1*y_range])
|
| 253 |
+
|
| 254 |
+
ax.grid(True, alpha=0.3)
|
| 255 |
+
ax.axhline(y=0, color='k', linestyle='-', alpha=0.3)
|
| 256 |
+
ax.axvline(x=0, color='k', linestyle='-', alpha=0.3)
|
| 257 |
+
ax.set_xlabel('x')
|
| 258 |
+
ax.set_ylabel('y')
|
| 259 |
+
ax.set_title(f'Graph of {str(expr)}')
|
| 260 |
+
ax.legend()
|
| 261 |
+
return fig
|
| 262 |
+
except Exception as e:
|
| 263 |
+
st.error(f"Error plotting equation: {str(e)}")
|
| 264 |
+
return None
|
| 265 |
+
|
| 266 |
+
def get_download_link(fig):
|
| 267 |
+
buf = io.BytesIO()
|
| 268 |
+
fig.savefig(buf, format='png', bbox_inches='tight')
|
| 269 |
+
buf.seek(0)
|
| 270 |
+
b64 = base64.b64encode(buf.read()).decode()
|
| 271 |
+
return f'<a href="data:image/png;base64,{b64}" download="equation_plot.png">📥 Download Plot</a>'
|
| 272 |
+
|
| 273 |
+
# Header
|
| 274 |
+
st.title("📈 Equation2Graph")
|
| 275 |
+
st.markdown("Visualize mathematical equations instantly, from symbolic or natural language input!")
|
| 276 |
+
|
| 277 |
+
# Columns
|
| 278 |
+
col1, col2 = st.columns([2, 1])
|
| 279 |
+
|
| 280 |
+
with col1:
|
| 281 |
+
# Natural language input
|
| 282 |
+
st.subheader("🗣 Describe your equation (optional)")
|
| 283 |
+
nl_input = st.text_input(
|
| 284 |
+
"Enter your equation in plain English:",
|
| 285 |
+
placeholder="e.g., the square of x plus two times x plus one"
|
| 286 |
+
)
|
| 287 |
+
|
| 288 |
+
equation = ""
|
| 289 |
+
if nl_input:
|
| 290 |
+
equation = convert_nl_to_equation(nl_input)
|
| 291 |
+
if equation:
|
| 292 |
+
st.success(f"Converted to equation: {equation}")
|
| 293 |
+
else:
|
| 294 |
+
st.error("Failed to convert input") # Direct equation input (fallback or primary)
|
| 295 |
+
equation = st.text_area(
|
| 296 |
+
"Or enter your equation directly:",
|
| 297 |
+
value=equation,
|
| 298 |
+
placeholder="e.g., x^2 + 2*x + 1",
|
| 299 |
+
height=100
|
| 300 |
+
)
|
| 301 |
+
|
| 302 |
+
# Plot settings
|
| 303 |
+
with st.expander("⚙ Plot Settings"):
|
| 304 |
+
col_a, col_b = st.columns(2)
|
| 305 |
+
with col_a:
|
| 306 |
+
x_min = st.number_input("X-axis minimum", value=-10.0)
|
| 307 |
+
with col_b:
|
| 308 |
+
x_max = st.number_input("X-axis maximum", value=10.0)
|
| 309 |
+
points = st.slider("Number of points", 100, 2000, 1000)
|
| 310 |
+
|
| 311 |
+
# Process and plot
|
| 312 |
+
if equation:
|
| 313 |
+
f, expr = parse_and_validate_equation(equation)
|
| 314 |
+
if f and expr:
|
| 315 |
+
fig = plot_equation(f, expr, (x_min, x_max), points)
|
| 316 |
+
if fig:
|
| 317 |
+
st.pyplot(fig)
|
| 318 |
+
st.markdown(get_download_link(fig), unsafe_allow_html=True)
|
| 319 |
+
if equation not in [h['equation'] for h in st.session_state.history]:
|
| 320 |
+
st.session_state.history.append({
|
| 321 |
+
'equation': equation,
|
| 322 |
+
'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 323 |
+
})
|
| 324 |
+
|
| 325 |
+
with col2:
|
| 326 |
+
st.subheader("📚 Example Equations") examples = [
|
| 327 |
+
"x^2 + 2*x + 1",
|
| 328 |
+
"sin(x) + cos(x)",
|
| 329 |
+
"exp(-x^2)",
|
| 330 |
+
"x^3 - 4*x",
|
| 331 |
+
"tan(x)",
|
| 332 |
+
"log(abs(x))",
|
| 333 |
+
"sin(x^2)*exp(-0.1*x^2)",
|
| 334 |
+
"(x^4 - 5*x^2 + 4)/(x^2 + 1)",
|
| 335 |
+
"sqrt(abs(x))*sin(10*x)",
|
| 336 |
+
"1/(1+exp(-x))",
|
| 337 |
+
"sin(1/x)",
|
| 338 |
+
"(x^5-5*x^3+4*x)/(x^2+1)",
|
| 339 |
+
"piecewise((x^2, x<0), (x^3, x>=0))",
|
| 340 |
+
"sinh(x)*cosh(x)"
|
| 341 |
+
]
|
| 342 |
+
for ex in examples:
|
| 343 |
+
if st.button(ex):
|
| 344 |
+
st.experimental_set_query_params(equation=ex)
|
| 345 |
+
|
| 346 |
+
st.subheader("📖 Recent Equations")
|
| 347 |
+
for item in reversed(st.session_state.history[-5:]):
|
| 348 |
+
st.text(f"{item['equation']}")
|
| 349 |
+
st.caption(f"Plotted on: {item['timestamp']}")
|
| 350 |
+
|
| 351 |
+
with st.expander("ℹ How to use Equation2Graph"):
|
| 352 |
+
st.markdown("""
|
| 353 |
+
### Instructions:
|
| 354 |
+
1. Describe or type your equation
|
| 355 |
+
2. The graph updates automatically
|
| 356 |
+
3. Adjust plot settings if needed
|
| 357 |
+
4. Download the graph as PNG
|
| 358 |
+
|
| 359 |
+
### Natural Language Support:
|
| 360 |
+
- Try: "the square of x plus two times x"
|
| 361 |
+
- You can still type equations like: x^2 + 2*x
|
| 362 |
+
|
| 363 |
+
### Supported Math Functions:
|
| 364 |
+
- Basic: +, -, *, /, ^
|
| 365 |
+
- Trig: sin(x), cos(x), tan(x)
|
| 366 |
+
- Exponential/log: exp(x), log(x)
|
| 367 |
+
- Advanced: sqrt(x), abs(x), combinations of functions
|
| 368 |
+
|
| 369 |
+
### Complex Equations:
|
| 370 |
+
You can enter lengthy and complex equations such as:
|
| 371 |
+
- Combinations of multiple functions: `sin(x^2)*exp(-0.1*x^2)`
|
| 372 |
+
- Rational functions: `(x^4 - 5*x^2 + 4)/(x^2 + 1)`
|
| 373 |
+
- Any valid mathematical expression with variable x
|
| 374 |
+
""")
|
| 375 |
+
|
| 376 |
+
# Footer
|
| 377 |
+
st.markdown("---")
|
| 378 |
+
st.markdown("Equation2Graph | Now with 🧠 AI-powered equation parser | Made with ❤ by MathVizMinds")
|
app_enhanced.py
ADDED
|
@@ -0,0 +1,415 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import numpy as np
|
| 3 |
+
import matplotlib.pyplot as plt
|
| 4 |
+
import sympy as sp
|
| 5 |
+
from sympy.parsing.sympy_parser import parse_expr
|
| 6 |
+
from sympy.utilities.lambdify import lambdify
|
| 7 |
+
import io
|
| 8 |
+
import os
|
| 9 |
+
import base64
|
| 10 |
+
import re
|
| 11 |
+
from datetime import datetime
|
| 12 |
+
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
|
| 13 |
+
|
| 14 |
+
# Create required directories
|
| 15 |
+
os.makedirs("uploads", exist_ok=True)
|
| 16 |
+
|
| 17 |
+
# Page config
|
| 18 |
+
st.set_page_config(page_title="Equation2Graph", page_icon="📈", layout="wide")
|
| 19 |
+
|
| 20 |
+
# Session state
|
| 21 |
+
if 'history' not in st.session_state:
|
| 22 |
+
st.session_state.history = []
|
| 23 |
+
if 'equation' not in st.session_state:
|
| 24 |
+
st.session_state.equation = ""
|
| 25 |
+
|
| 26 |
+
# Initialize NLP model
|
| 27 |
+
@st.cache_resource
|
| 28 |
+
def load_nlp_model():
|
| 29 |
+
try:
|
| 30 |
+
tokenizer = AutoTokenizer.from_pretrained("t5-small")
|
| 31 |
+
model = AutoModelForSeq2SeqLM.from_pretrained("t5-small")
|
| 32 |
+
return tokenizer, model
|
| 33 |
+
except Exception as e:
|
| 34 |
+
st.warning(f"⚠ AI model could not be loaded: {str(e)}. Falling back to basic equation parsing.")
|
| 35 |
+
return None, None
|
| 36 |
+
|
| 37 |
+
# Load models
|
| 38 |
+
tokenizer, model = load_nlp_model()
|
| 39 |
+
|
| 40 |
+
def convert_nl_to_equation(nl_input):
|
| 41 |
+
"""Convert natural language to equation using AI model or fallback to basic parsing"""
|
| 42 |
+
if tokenizer and model:
|
| 43 |
+
try:
|
| 44 |
+
inputs = tokenizer.encode(nl_input, return_tensors="pt", truncation=True)
|
| 45 |
+
outputs = model.generate(inputs, max_length=50)
|
| 46 |
+
return tokenizer.decode(outputs[0], skip_special_tokens=True)
|
| 47 |
+
except Exception as e:
|
| 48 |
+
st.error(f"Error in AI conversion: {str(e)}")
|
| 49 |
+
return basic_nl_to_equation(nl_input)
|
| 50 |
+
else:
|
| 51 |
+
return basic_nl_to_equation(nl_input)
|
| 52 |
+
|
| 53 |
+
def basic_nl_to_equation(text):
|
| 54 |
+
"""Basic natural language to equation conversion"""
|
| 55 |
+
# Define basic math terms and advanced functions
|
| 56 |
+
terms = {
|
| 57 |
+
# Basic arithmetic
|
| 58 |
+
'squared': '^2',
|
| 59 |
+
'cubed': '^3',
|
| 60 |
+
'plus': '+',
|
| 61 |
+
'minus': '-',
|
| 62 |
+
'times': '*',
|
| 63 |
+
'multiply by': '*',
|
| 64 |
+
'multiplied by': '*',
|
| 65 |
+
'divided by': '/',
|
| 66 |
+
'over': '/',
|
| 67 |
+
'to the power of': '^',
|
| 68 |
+
'power': '^',
|
| 69 |
+
'raised to': '^',
|
| 70 |
+
|
| 71 |
+
# Trigonometric functions
|
| 72 |
+
'sin of': 'sin(',
|
| 73 |
+
'sine of': 'sin(',
|
| 74 |
+
'cos of': 'cos(',
|
| 75 |
+
'cosine of': 'cos(',
|
| 76 |
+
'tan of': 'tan(',
|
| 77 |
+
'tangent of': 'tan(',
|
| 78 |
+
'arcsin of': 'asin(',
|
| 79 |
+
'arccos of': 'acos(',
|
| 80 |
+
'arctan of': 'atan(',
|
| 81 |
+
'csc of': '1/sin(',
|
| 82 |
+
'sec of': '1/cos(',
|
| 83 |
+
'cot of': '1/tan(',
|
| 84 |
+
|
| 85 |
+
# Exponential and logarithmic
|
| 86 |
+
'exponential of': 'exp(',
|
| 87 |
+
'exp of': 'exp(',
|
| 88 |
+
'e to the': 'exp(',
|
| 89 |
+
'e raised to': 'exp(',
|
| 90 |
+
'ln of': 'log(',
|
| 91 |
+
'log of': 'log(',
|
| 92 |
+
'log base 10 of': 'log10(',
|
| 93 |
+
'logarithm of': 'log(',
|
| 94 |
+
'natural log of': 'log(',
|
| 95 |
+
|
| 96 |
+
# Other mathematical functions
|
| 97 |
+
'absolute value of': 'abs(',
|
| 98 |
+
'modulus of': 'abs(',
|
| 99 |
+
'square root of': 'sqrt(',
|
| 100 |
+
'sqrt of': 'sqrt(',
|
| 101 |
+
'cube root of': 'cbrt(',
|
| 102 |
+
|
| 103 |
+
# Hyperbolic functions
|
| 104 |
+
'sinh of': 'sinh(',
|
| 105 |
+
'cosh of': 'cosh(',
|
| 106 |
+
'tanh of': 'tanh(',
|
| 107 |
+
|
| 108 |
+
# Piecewise functions
|
| 109 |
+
'piecewise': 'piecewise',
|
| 110 |
+
'step function': 'Heaviside(',
|
| 111 |
+
|
| 112 |
+
# Multi-part expressions
|
| 113 |
+
'divided by the sum of': '/(',
|
| 114 |
+
'divided by the product of': '/(',
|
| 115 |
+
'multiplied by the sum of': '*(',
|
| 116 |
+
'multiplied by the difference of': '*(',
|
| 117 |
+
'multiplied by the product of': '*('
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
# Normalize text
|
| 121 |
+
text = text.lower().strip()
|
| 122 |
+
|
| 123 |
+
# Replace terms
|
| 124 |
+
for term, symbol in terms.items():
|
| 125 |
+
text = text.replace(term, symbol)
|
| 126 |
+
|
| 127 |
+
# Special case handling for complex expressions
|
| 128 |
+
text = text.replace('the sum of', '(')
|
| 129 |
+
text = text.replace('the difference between', '(')
|
| 130 |
+
text = text.replace('the product of', '(')
|
| 131 |
+
text = text.replace('the quotient of', '(')
|
| 132 |
+
|
| 133 |
+
# Convert verbal numbers to digits
|
| 134 |
+
number_map = {
|
| 135 |
+
'zero': '0', 'one': '1', 'two': '2', 'three': '3', 'four': '4',
|
| 136 |
+
'five': '5', 'six': '6', 'seven': '7', 'eight': '8', 'nine': '9',
|
| 137 |
+
'ten': '10', 'pi': 'pi', 'infinity': 'oo'
|
| 138 |
+
}
|
| 139 |
+
for word, num in number_map.items():
|
| 140 |
+
# Use word boundaries to avoid partial matches
|
| 141 |
+
text = re.sub(r'\b' + word + r'\b', num, text)
|
| 142 |
+
|
| 143 |
+
# Clean up the equation
|
| 144 |
+
text = text.replace(' ', '')
|
| 145 |
+
text = text.replace('and', '+')
|
| 146 |
+
|
| 147 |
+
# Balance parentheses
|
| 148 |
+
while text.count('(') > text.count(')'):
|
| 149 |
+
text += ')' # Close any unclosed parentheses
|
| 150 |
+
|
| 151 |
+
# Remove any invalid characters
|
| 152 |
+
text = ''.join(c for c in text if c.isalnum() or c in '+-*/^().πe')
|
| 153 |
+
|
| 154 |
+
# Replace common mathematical constants
|
| 155 |
+
text = text.replace('pi', 'pi')
|
| 156 |
+
text = text.replace('π', 'pi')
|
| 157 |
+
text = text.replace('e', 'E') # Avoid confusion with Euler's number
|
| 158 |
+
|
| 159 |
+
return text
|
| 160 |
+
|
| 161 |
+
def parse_and_validate_equation(equation_str):
|
| 162 |
+
try:
|
| 163 |
+
# Clean up the equation string
|
| 164 |
+
equation_str = equation_str.strip()
|
| 165 |
+
|
| 166 |
+
# Replace carets with sympy's power operator
|
| 167 |
+
equation_str = equation_str.replace('^', '**')
|
| 168 |
+
# Handle common alternative syntax
|
| 169 |
+
equation_str = equation_str.replace('sqrt', 'sp.sqrt')
|
| 170 |
+
equation_str = equation_str.replace('cbrt', 'lambda x: sp.root(x, 3)')
|
| 171 |
+
|
| 172 |
+
# Trigonometric functions
|
| 173 |
+
equation_str = equation_str.replace('sin', 'sp.sin')
|
| 174 |
+
equation_str = equation_str.replace('cos', 'sp.cos')
|
| 175 |
+
equation_str = equation_str.replace('tan', 'sp.tan')
|
| 176 |
+
equation_str = equation_str.replace('asin', 'sp.asin')
|
| 177 |
+
equation_str = equation_str.replace('acos', 'sp.acos')
|
| 178 |
+
equation_str = equation_str.replace('atan', 'sp.atan')
|
| 179 |
+
|
| 180 |
+
# Hyperbolic functions
|
| 181 |
+
equation_str = equation_str.replace('sinh', 'sp.sinh')
|
| 182 |
+
equation_str = equation_str.replace('cosh', 'sp.cosh')
|
| 183 |
+
equation_str = equation_str.replace('tanh', 'sp.tanh')
|
| 184 |
+
|
| 185 |
+
# Exponential and logarithmic
|
| 186 |
+
equation_str = equation_str.replace('exp', 'sp.exp')
|
| 187 |
+
equation_str = equation_str.replace('log', 'sp.log')
|
| 188 |
+
equation_str = equation_str.replace('log10', 'lambda x: sp.log(x, 10)')
|
| 189 |
+
|
| 190 |
+
# Special functions
|
| 191 |
+
equation_str = equation_str.replace('abs', 'sp.Abs')
|
| 192 |
+
equation_str = equation_str.replace('gamma', 'sp.gamma')
|
| 193 |
+
equation_str = equation_str.replace('factorial', 'sp.factorial')
|
| 194 |
+
|
| 195 |
+
# Handle piecewise functions
|
| 196 |
+
equation_str = equation_str.replace('piecewise', 'sp.Piecewise')
|
| 197 |
+
|
| 198 |
+
# Constants
|
| 199 |
+
equation_str = equation_str.replace('pi', 'sp.pi')
|
| 200 |
+
equation_str = equation_str.replace('E', 'sp.E')
|
| 201 |
+
equation_str = equation_str.replace('oo', 'sp.oo')
|
| 202 |
+
|
| 203 |
+
# Create a Symbol for x
|
| 204 |
+
x = sp.Symbol('x')
|
| 205 |
+
|
| 206 |
+
# Check for multivariate expressions and handle them
|
| 207 |
+
if any(var in equation_str for var in ['y', 'z']):
|
| 208 |
+
st.warning("Note: Only the variable 'x' is supported. Other variables will be treated as symbols.")
|
| 209 |
+
|
| 210 |
+
# Safety check for extremely long expressions
|
| 211 |
+
if len(equation_str) > 1000:
|
| 212 |
+
st.warning("This is a very complex equation. Rendering may take longer than usual.")
|
| 213 |
+
|
| 214 |
+
# Parse the expression using sympy with a timeout
|
| 215 |
+
try:
|
| 216 |
+
expr = parse_expr(equation_str, local_dict={'x': x})
|
| 217 |
+
except Exception as parsing_error:
|
| 218 |
+
st.error(f"Could not parse the expression. Please check the syntax: {str(parsing_error)}")
|
| 219 |
+
return None, None
|
| 220 |
+
|
| 221 |
+
# Create a lambda function for numerical evaluation with safety checks
|
| 222 |
+
try:
|
| 223 |
+
f = lambdify(x, expr, modules=['numpy', 'scipy', 'sympy'])
|
| 224 |
+
|
| 225 |
+
# Test the function with a simple value to verify it works
|
| 226 |
+
test_val = f(0)
|
| 227 |
+
|
| 228 |
+
# Check for complex results
|
| 229 |
+
if isinstance(test_val, complex):
|
| 230 |
+
st.info("This equation may produce complex values for some inputs. Only the real part will be displayed.")
|
| 231 |
+
# Create a wrapped function that returns only the real part
|
| 232 |
+
orig_f = f
|
| 233 |
+
def real_part_wrapper(x):
|
| 234 |
+
return np.real(orig_f(x))
|
| 235 |
+
f = real_part_wrapper
|
| 236 |
+
|
| 237 |
+
return f, expr
|
| 238 |
+
except Exception as eval_error:
|
| 239 |
+
st.error(f"Error creating evaluable function: {str(eval_error)}")
|
| 240 |
+
return None, None
|
| 241 |
+
|
| 242 |
+
except Exception as e:
|
| 243 |
+
st.error(f"Error processing equation: {str(e)}")
|
| 244 |
+
return None, None
|
| 245 |
+
|
| 246 |
+
def plot_equation(f, expr, x_range=(-10, 10), points=1000):
|
| 247 |
+
try:
|
| 248 |
+
fig, ax = plt.subplots(figsize=(10, 6))
|
| 249 |
+
x = np.linspace(x_range[0], x_range[1], points)
|
| 250 |
+
|
| 251 |
+
# Handle potential division by zero and other numerical errors
|
| 252 |
+
with np.errstate(divide='ignore', invalid='ignore'):
|
| 253 |
+
y = f(x)
|
| 254 |
+
|
| 255 |
+
# Replace infinities and NaNs for proper plotting
|
| 256 |
+
if isinstance(y, np.ndarray):
|
| 257 |
+
# Convert infinities to NaN to get breaks in the plot line
|
| 258 |
+
y[~np.isfinite(y)] = np.nan
|
| 259 |
+
|
| 260 |
+
# If entirely NaN, show an error message
|
| 261 |
+
if np.all(np.isnan(y)):
|
| 262 |
+
st.warning("This equation doesn't produce valid results in the specified range.")
|
| 263 |
+
return None
|
| 264 |
+
|
| 265 |
+
# Plot with NaNs to show discontinuities properly
|
| 266 |
+
ax.plot(x, y, '-b', label=str(expr))
|
| 267 |
+
else:
|
| 268 |
+
# Scalar result case
|
| 269 |
+
ax.axhline(y=float(y), color='b', linestyle='-', label=str(expr))
|
| 270 |
+
|
| 271 |
+
# Auto-adjust y-range if there are valid values
|
| 272 |
+
y_valid = y[np.isfinite(y)] if isinstance(y, np.ndarray) else np.array([y]) if np.isfinite(y) else np.array([])
|
| 273 |
+
if len(y_valid) > 0:
|
| 274 |
+
y_min, y_max = np.min(y_valid), np.max(y_valid)
|
| 275 |
+
y_range = y_max - y_min
|
| 276 |
+
if y_range > 0:
|
| 277 |
+
ax.set_ylim([y_min - 0.1*y_range, y_max + 0.1*y_range])
|
| 278 |
+
|
| 279 |
+
ax.grid(True, alpha=0.3)
|
| 280 |
+
ax.axhline(y=0, color='k', linestyle='-', alpha=0.3)
|
| 281 |
+
ax.axvline(x=0, color='k', linestyle='-', alpha=0.3)
|
| 282 |
+
ax.set_xlabel('x')
|
| 283 |
+
ax.set_ylabel('y')
|
| 284 |
+
ax.set_title(f'Graph of {str(expr)}')
|
| 285 |
+
ax.legend()
|
| 286 |
+
return fig
|
| 287 |
+
except Exception as e:
|
| 288 |
+
st.error(f"Error plotting equation: {str(e)}")
|
| 289 |
+
return None
|
| 290 |
+
|
| 291 |
+
def get_download_link(fig):
|
| 292 |
+
buf = io.BytesIO()
|
| 293 |
+
fig.savefig(buf, format='png', bbox_inches='tight')
|
| 294 |
+
buf.seek(0)
|
| 295 |
+
b64 = base64.b64encode(buf.read()).decode()
|
| 296 |
+
return f'<a href="data:image/png;base64,{b64}" download="equation_plot.png">📥 Download Plot</a>'
|
| 297 |
+
|
| 298 |
+
# Header
|
| 299 |
+
st.title("📈 Equation2Graph")
|
| 300 |
+
st.markdown("Visualize mathematical equations instantly, from symbolic or natural language input!")
|
| 301 |
+
|
| 302 |
+
# Columns
|
| 303 |
+
col1, col2 = st.columns([2, 1])
|
| 304 |
+
|
| 305 |
+
with col1:
|
| 306 |
+
# Natural language input
|
| 307 |
+
st.subheader("🗣 Describe your equation (optional)")
|
| 308 |
+
nl_input = st.text_input(
|
| 309 |
+
"Enter your equation in plain English:",
|
| 310 |
+
placeholder="e.g., the square of x plus two times x plus one"
|
| 311 |
+
)
|
| 312 |
+
|
| 313 |
+
equation = ""
|
| 314 |
+
if nl_input:
|
| 315 |
+
equation = convert_nl_to_equation(nl_input)
|
| 316 |
+
if equation:
|
| 317 |
+
st.success(f"Converted to equation: {equation}")
|
| 318 |
+
else:
|
| 319 |
+
st.error("Failed to convert input") # Direct equation input (fallback or primary)
|
| 320 |
+
equation = st.text_area(
|
| 321 |
+
"Or enter your equation directly:",
|
| 322 |
+
value=equation,
|
| 323 |
+
placeholder="e.g., x^2 + 2*x + 1",
|
| 324 |
+
height=100
|
| 325 |
+
)
|
| 326 |
+
|
| 327 |
+
# Plot settings
|
| 328 |
+
with st.expander("⚙ Plot Settings"):
|
| 329 |
+
col_a, col_b = st.columns(2)
|
| 330 |
+
with col_a:
|
| 331 |
+
x_min = st.number_input("X-axis minimum", value=-10.0)
|
| 332 |
+
with col_b:
|
| 333 |
+
x_max = st.number_input("X-axis maximum", value=10.0)
|
| 334 |
+
points = st.slider("Number of points", 100, 2000, 1000)
|
| 335 |
+
|
| 336 |
+
# Process and plot
|
| 337 |
+
if equation:
|
| 338 |
+
f, expr = parse_and_validate_equation(equation)
|
| 339 |
+
if f and expr:
|
| 340 |
+
fig = plot_equation(f, expr, (x_min, x_max), points)
|
| 341 |
+
if fig:
|
| 342 |
+
st.pyplot(fig)
|
| 343 |
+
st.markdown(get_download_link(fig), unsafe_allow_html=True)
|
| 344 |
+
if equation not in [h['equation'] for h in st.session_state.history]:
|
| 345 |
+
st.session_state.history.append({
|
| 346 |
+
'equation': equation,
|
| 347 |
+
'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 348 |
+
})
|
| 349 |
+
|
| 350 |
+
with col2:
|
| 351 |
+
st.subheader("📚 Example Equations")
|
| 352 |
+
examples = [
|
| 353 |
+
"x^2 + 2*x + 1",
|
| 354 |
+
"sin(x) + cos(x)",
|
| 355 |
+
"exp(-x^2)",
|
| 356 |
+
"x^3 - 4*x",
|
| 357 |
+
"tan(x)",
|
| 358 |
+
"log(abs(x))",
|
| 359 |
+
"sin(x^2)*exp(-0.1*x^2)",
|
| 360 |
+
"(x^4 - 5*x^2 + 4)/(x^2 + 1)",
|
| 361 |
+
"sqrt(abs(x))*sin(10*x)",
|
| 362 |
+
"1/(1+exp(-x))",
|
| 363 |
+
"sin(1/x)",
|
| 364 |
+
"(x^5-5*x^3+4*x)/(x^2+1)",
|
| 365 |
+
"piecewise((x^2, x<0), (x^3, x>=0))",
|
| 366 |
+
"sinh(x)*cosh(x)"
|
| 367 |
+
]
|
| 368 |
+
for ex in examples:
|
| 369 |
+
if st.button(ex):
|
| 370 |
+
st.experimental_set_query_params(equation=ex)
|
| 371 |
+
|
| 372 |
+
st.subheader("📖 Recent Equations")
|
| 373 |
+
for item in reversed(st.session_state.history[-5:]):
|
| 374 |
+
st.text(f"{item['equation']}")
|
| 375 |
+
st.caption(f"Plotted on: {item['timestamp']}")
|
| 376 |
+
|
| 377 |
+
with st.expander("ℹ How to use Equation2Graph"):
|
| 378 |
+
st.markdown("""
|
| 379 |
+
### Instructions:
|
| 380 |
+
1. Describe or type your equation
|
| 381 |
+
2. The graph updates automatically
|
| 382 |
+
3. Adjust plot settings if needed
|
| 383 |
+
4. Download the graph as PNG
|
| 384 |
+
|
| 385 |
+
### Natural Language Support:
|
| 386 |
+
- Try: "the square of x plus two times x"
|
| 387 |
+
- You can still type equations like: x^2 + 2*x
|
| 388 |
+
|
| 389 |
+
### Supported Math Functions:
|
| 390 |
+
- Basic: +, -, *, /, ^
|
| 391 |
+
- Trig: sin(x), cos(x), tan(x), arcsin(x), arccos(x), arctan(x)
|
| 392 |
+
- Exponential/log: exp(x), log(x), log10(x)
|
| 393 |
+
- Hyperbolic: sinh(x), cosh(x), tanh(x)
|
| 394 |
+
- Piecewise: piecewise((expr1, cond1), (expr2, cond2), ...)
|
| 395 |
+
- Advanced: sqrt(x), abs(x), combinations of functions
|
| 396 |
+
### Complex Equations:
|
| 397 |
+
You can enter lengthy and complex equations such as:
|
| 398 |
+
- Combinations of multiple functions: `sin(x^2)*exp(-0.1*x^2)`
|
| 399 |
+
- Rational functions: `(x^4 - 5*x^2 + 4)/(x^2 + 1)`
|
| 400 |
+
- Piecewise functions: `piecewise((x^2, x<0), (x^3, x>=0))`
|
| 401 |
+
- Highly oscillatory functions: `sin(1/x)`
|
| 402 |
+
- Special functions: `gamma(x)`, `factorial(x)`
|
| 403 |
+
- Any valid mathematical expression with variable x
|
| 404 |
+
|
| 405 |
+
### Tips for Complex Equations:
|
| 406 |
+
- For equations with discontinuities, try adjusting the plot range
|
| 407 |
+
- For highly oscillatory functions, increase the number of points in Plot Settings
|
| 408 |
+
- Use the piecewise function for functions defined differently across domains
|
| 409 |
+
- If your equation produces complex values, only the real part will be displayed
|
| 410 |
+
- Extremely long expressions (>1000 characters) are supported but may take longer to render
|
| 411 |
+
""")
|
| 412 |
+
|
| 413 |
+
# Footer
|
| 414 |
+
st.markdown("---")
|
| 415 |
+
st.markdown("Equation2Graph | Now with 🧠 AI-powered equation parser | Made with ❤ by MathVizMinds")
|
requirements.txt
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
-
streamlit>=1.45.0
|
| 2 |
-
numpy>=2.0.0
|
| 3 |
-
matplotlib=
|
| 4 |
-
sympy>=1.14.0
|
| 5 |
-
transformers>=4.30.0
|
| 6 |
-
torch>=2.0.0
|
| 7 |
-
scipy>=1.10.0
|
|
|
|
| 1 |
+
streamlit>=1.45.0
|
| 2 |
+
numpy>=2.0.0
|
| 3 |
+
matplotlib>=3.10.0
|
| 4 |
+
sympy>=1.14.0
|
| 5 |
+
transformers>=4.30.0
|
| 6 |
+
torch>=2.0.0
|
| 7 |
+
scipy>=1.10.0
|