Program description:
You are given a set of two functions: $$f=x^3-6x^2+x+5; g=(x-2)^2-6$$ Plot them using Matprolib on a user input segment [a; b].
My solution:
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import interpolate # for smoothing
def func(x):
return [pow(x, 3) - 6 * pow(x, 2) + x + 5, pow((x-2), 2) - 6]
# plt.plot([1,5, -3, 0.5], [1, 25, 9, 0.5])
# plt.plot(1, 7, "r+")
# plt.plot(-1, 7, "bo")
f = []
f_1 = []
x = []
interval = [int(x) for x in input("Define segment (i.e. a b): ").split(' ')]
for val in range(interval[0], interval[1] + 1):
x.append(val)
f.append(func(val)[0])
f_1.append(func(val)[1])
linear_space = np.linspace(interval[0], interval[1], 300)
a_BSpline = interpolate.make_interp_spline(x, f)
b_BSpline = interpolate.make_interp_spline(x, f_1)
f_new = a_BSpline(linear_space)
f_1_new = b_BSpline(linear_space)
plt.plot(linear_space, f_new, color="#47c984",
linestyle="solid", linewidth=1)
plt.plot(linear_space, f_1_new, color="#fc6703",
linestyle="solid", linewidth=1)
plt.gca().spines["left"].set_position("zero")
plt.gca().spines["bottom"].set_position("zero")
plt.show()
Input: -10 10
Output:
Question: Is there any way to make this code more concise?
Thank you in advance.
1 Answer 1
As I pointed out in the comments, I do not think smoothing is needed when plotting functions that are already smooth, such as polynominals. In those cases, the graphs would look rough only if the points plotted are not dense enough (on the x axis).
Since you have already imported and used
numpy
, it would be better to usenumpy.polyval
for vectorized evaluation of polynominals.Drawing spines at zero would not work well if the input range does not include zero. In that case, the
"center"
position might be used instead of"zero"
. (I will not implement this logic in my code below)The top and right spines should not be shown.
Consider using
plt.style.use
for setting common style information. See here for alternative options for style setting.Avoid constants like
"#47c984"
. Name them with appropriate constant names for better readability.It is a good practice to comply to the PEP 8 style when writing Python code. Use an IDE (such as PyCharm) or an online checker (such as this) for automatic PEP 8 violation checking.
When running code outside a method / class, it is a good practice to put the code inside a main guard. See here for more explanation.
Here is an improved version:
import numpy as np
import matplotlib.pyplot as plt
if __name__ == "__main__":
# Define constants (color names come from https://colornamer.robertcooper.me/)
INPUT_MESSAGE = "Lower and upper bounds of x, separated by a space: "
NUM_POINTS = 300
PARIS_GREEN = "#47c984"
BLAZE_ORANGE = "#fc6703"
# Read input
lb, ub = map(float, input(INPUT_MESSAGE).split())
# Compute coordinates of points to be plotted
x = np.linspace(lb, ub, NUM_POINTS)
f_x = np.polyval([1, -6, 1, 5], x)
g_x = np.square(x - 2) - 6
# Plotting
plt.style.use({"lines.linestyle": "solid", "lines.linewidth": 1})
plt.plot(x, f_x, color=PARIS_GREEN)
plt.plot(x, g_x, color=BLAZE_ORANGE)
# Adjust spines
spines = plt.gca().spines
spines["left"].set_position("zero")
spines["bottom"].set_position("zero")
spines["right"].set_visible(False)
spines["top"].set_visible(False)
# Display plot
plt.show()
-
\$\begingroup\$ Thank you for detailed answer. Why don't you consider spines to be const? \$\endgroup\$JoshJohnson– JoshJohnson2020年12月06日 08:09:41 +00:00Commented Dec 6, 2020 at 8:09
-
\$\begingroup\$ Using a constant would be the same as using 0. The coordinates have to vary based on the input range.
"center"
is just a convenient way to achieve that. \$\endgroup\$GZ0– GZ02020年12月06日 08:21:36 +00:00Commented Dec 6, 2020 at 8:21 -
\$\begingroup\$ By the way, @GZ0, g(x) is not displayed correctly, it's displayed as a plain line. \$\endgroup\$JoshJohnson– JoshJohnson2020年12月06日 08:35:53 +00:00Commented Dec 6, 2020 at 8:35
-
\$\begingroup\$ Its should be displayed like this: yotx.ru/#!1/3_h/ubWwf7Wwf7Rgzhf23/aP9g/2DfT0qt7W/… \$\endgroup\$JoshJohnson– JoshJohnson2020年12月06日 08:41:49 +00:00Commented Dec 6, 2020 at 8:41
-
\$\begingroup\$
g(x)
is correct. It looks like a line only because of the scale of the y axis. There is a bug in the code and it is fixed in my updated answer. \$\endgroup\$GZ0– GZ02020年12月06日 11:45:03 +00:00Commented Dec 6, 2020 at 11:45
interpolate.make_interp_spline
? If it is required, please update the problem statement and title to include the corresponding logic. \$\endgroup\$