22
22
23
23
class FunctionPlotter (QMainWindow ):
24
24
"""
25
- A class representing the main window for the function plotter application.
25
+ Main window for the function plotter application.
26
26
27
27
This class handles the GUI elements, user inputs, and plotting of mathematical functions
28
28
using PySide2 for the GUI and Matplotlib for plotting.
@@ -33,100 +33,75 @@ class FunctionPlotter(QMainWindow):
33
33
def __init__ (self ):
34
34
super ().__init__ ()
35
35
self .setWindowTitle ("Function Plotter" )
36
+ self .setup_ui ()
36
37
37
- # Initialize the central widget and main layout
38
+ def setup_ui (self ):
39
+ """Set up the user interface elements."""
38
40
self .central_widget = QWidget ()
39
41
self .setCentralWidget (self .central_widget )
40
42
self .layout = QVBoxLayout ()
41
- self .input_layout = QHBoxLayout ()
42
43
self .central_widget .setLayout (self .layout )
43
44
44
- # Initialize input fields for the function and range values
45
- self .function_input = QLineEdit ()
46
- self .function_input .setPlaceholderText ("Enter function of x, e.g., 5*x^3 + 2*x" )
47
- self .input_layout .addWidget (self .function_input )
45
+ self .input_layout = QHBoxLayout ()
46
+ self .function_input = self .create_line_edit (
47
+ "Enter function of x, e.g., 5*x^3 + 2*x"
48
+ )
49
+ self .min_input = self .create_line_edit ("Enter min value of x" )
50
+ self .max_input = self .create_line_edit ("Enter max value of x" )
48
51
49
- self .min_input = QLineEdit ()
50
- self .min_input .setPlaceholderText ("Enter min value of x" )
52
+ self .input_layout .addWidget (self .function_input )
51
53
self .input_layout .addWidget (self .min_input )
52
-
53
- self .max_input = QLineEdit ()
54
- self .max_input .setPlaceholderText ("Enter max value of x" )
55
54
self .input_layout .addWidget (self .max_input )
56
-
57
55
self .layout .addLayout (self .input_layout )
58
56
59
- # Initialize the plot button
60
57
self .plot_button = QPushButton ("Plot Function" )
61
58
self .plot_button .clicked .connect (self .plot_function )
62
59
self .layout .addWidget (self .plot_button )
63
60
64
- # Initialize the Matplotlib figure and canvas
65
61
self .figure , self .ax = plt .subplots ()
66
62
self .canvas = FigureCanvas (self .figure )
67
63
self .layout .addWidget (self .canvas )
68
64
69
- def plot_function (self ):
70
- """
71
- Handles the plotting of the function based on user inputs.
65
+ def create_line_edit (self , placeholder ):
72
66
"""
73
- function = self .function_input .text ().replace (" " , "" )
74
- min_x = self .min_input .text ()
75
- max_x = self .max_input .text ()
67
+ Create a QLineEdit with a placeholder text.
76
68
77
- # Validate inputs
78
- if not self .validate_inputs (function , min_x , max_x ):
79
- return
80
-
81
- try :
82
- min_x = float (min_x )
83
- # Make range from -1e20 to 1e20 whatever the input
84
- min_x = max (min (1e20 , min_x ), - 1e20 )
85
- max_x = float (max_x )
86
- # Make range from -1e20 to 1e20 whatever the input
87
- max_x = max (min (1e20 , max_x ), - 1e20 )
88
-
89
- except ValueError :
90
- self .show_error_message ("Min and Max values must be numbers." )
91
- return
69
+ Parameters:
70
+ - placeholder (str): The placeholder text for the QLineEdit.
92
71
93
- if min_x >= max_x :
94
- self .show_error_message ("Min value must be less than Max value." )
95
- return
72
+ Returns:
73
+ - QLineEdit: The created QLineEdit object.
74
+ """
75
+ line_edit = QLineEdit ()
76
+ line_edit .setPlaceholderText (placeholder )
77
+ return line_edit
96
78
97
- if ("log10" in function or "sqrt" in function ) and min_x < 0 :
98
- self .show_error_message (
99
- "Min value must be non-negative for functions with log10 or sqrt."
100
- )
101
- return
79
+ def plot_function (self ):
80
+ """Handle the plotting of the function based on user inputs."""
81
+ function = self .function_input .text ().replace (" " , "" )
82
+ min_x , max_x = self .min_input .text (), self .max_input .text ()
102
83
103
- # deal with the case of division by zero ex(x/0)
104
- if "/0" in function :
105
- self .show_error_message ("Division by zero is not allowed." )
84
+ if not self .validate_inputs (function , min_x , max_x ):
106
85
return
107
86
87
+ min_x , max_x = self .parse_range (min_x , max_x )
108
88
x = np .linspace (min_x , max_x , 400 )
109
89
if "log10" in function :
110
90
x = np .where (
111
91
x == 0 , 1e-15 , x
112
92
) # Add a small value to x where x is 0 if log10 is in the function
93
+
113
94
try :
114
95
y = eval (self .prepare_function (function , x ))
115
96
except Exception as e :
116
97
self .show_error_message (f"Error in function evaluation: { e } " )
117
98
return
118
99
119
- # Clear previous plot and plot new function
120
- self .ax .clear ()
121
- self .ax .plot (x , y )
122
- self .ax .set_title (f"Plot of { function } " )
123
- self .ax .set_xlabel ("x" )
124
- self .ax .set_ylabel ("f(x)" )
125
- self .canvas .draw ()
100
+ self .update_plot (x , y , function )
126
101
127
102
def validate_inputs (self , function , min_x , max_x ):
128
103
"""
129
- Validates the user inputs for the function and range values.
104
+ Validate the user inputs for the function and range values.
130
105
131
106
Parameters:
132
107
- function (str): The mathematical function entered by the user.
@@ -148,11 +123,47 @@ def validate_inputs(self, function, min_x, max_x):
148
123
self .show_error_message ("Min and Max values cannot be empty." )
149
124
return False
150
125
126
+ try :
127
+ min_x = float (min_x )
128
+ max_x = float (max_x )
129
+ except ValueError :
130
+ self .show_error_message ("Min and Max values must be numbers." )
131
+ return False
132
+
133
+ if min_x >= max_x :
134
+ self .show_error_message ("Min value must be less than Max value." )
135
+ return False
136
+
137
+ if ("log10" or "sqrt" ) in function and min_x < 0 :
138
+ self .show_error_message (
139
+ "Min value must be non-negative for functions with log10 or sqrt."
140
+ )
141
+ return False
142
+
143
+ if "/0" in function :
144
+ self .show_error_message ("Division by zero is not allowed." )
145
+ return False
146
+
151
147
return True
152
148
149
+ def parse_range (self , min_x , max_x ):
150
+ """
151
+ Parse and limit the range values to a valid range.
152
+
153
+ Parameters:
154
+ - min_x (str): The minimum value of x entered by the user.
155
+ - max_x (str): The maximum value of x entered by the user.
156
+
157
+ Returns:
158
+ - tuple: The parsed and limited range values.
159
+ """
160
+ min_x = max (min (1e20 , float (min_x )), - 1e20 )
161
+ max_x = max (min (1e20 , float (max_x )), - 1e20 )
162
+ return min_x , max_x
163
+
153
164
def prepare_function (self , function , x ):
154
165
"""
155
- Prepares the function for evaluation by replacing operators with their numpy equivalents.
166
+ Prepare the function for evaluation by replacing operators with their numpy equivalents.
156
167
157
168
Parameters:
158
169
- function (str): The mathematical function entered by the user.
@@ -164,14 +175,30 @@ def prepare_function(self, function, x):
164
175
function = function .replace ("^" , "**" )
165
176
function = function .replace ("log10" , "np.log10" )
166
177
function = function .replace ("sqrt" , "np.sqrt" )
167
- # if function is a constant (e.g. y=5)
178
+
168
179
if "x" not in function :
169
180
function = f"{ function } *np.ones_like(x)"
170
181
return function
171
182
183
+ def update_plot (self , x , y , function ):
184
+ """
185
+ Update the plot with the new function.
186
+
187
+ Parameters:
188
+ - x (np.ndarray): The array of x values.
189
+ - y (np.ndarray): The array of y values.
190
+ - function (str): The mathematical function entered by the user.
191
+ """
192
+ self .ax .clear ()
193
+ self .ax .plot (x , y )
194
+ self .ax .set_title (f"Plot of { function } " )
195
+ self .ax .set_xlabel ("x" )
196
+ self .ax .set_ylabel ("f(x)" )
197
+ self .canvas .draw ()
198
+
172
199
def show_error_message (self , message ):
173
200
"""
174
- Displays an error message dialog.
201
+ Display an error message dialog.
175
202
176
203
Parameters:
177
204
- message (str): The error message to display.
0 commit comments