fig, ax = plt.subplots(figsize=(5, 5), dpi=150, facecolor="none")
fig.gca().set_aspect("equal", adjustable="box")
ax.set_facecolor("none")
width = ampl.get_value("width")
height = ampl.get_value("height")
tree_slope = ampl.get_value("tree_slope")
frequency = ampl.get_value("frequency")
sine_slope = ampl.get_value("sine_slope")
x = np.linspace(0, width, 1000)
tree_left = tree_slope * x
tree_right = tree_slope * (width - x)
# Draw the borders of the tree
x_line1 = np.linspace(0, width / 2, 1000)
ax.plot(
x_line1,
tree_slope * x_line1,
color=tree_color,
linestyle="-",
path_effects=[patheffects.withStroke(linewidth=3, foreground="white")],
)
x_line2 = np.linspace(width / 2, width, 1000)
ax.plot(
x_line2,
tree_slope * (width - x_line2),
color=tree_color,
linestyle="-",
path_effects=[patheffects.withStroke(linewidth=3, foreground="white")],
)
ax.text(
width / 2,
height,
"★",
fontsize=25,
ha="center",
va="center",
color="gold",
path_effects=[patheffects.withStroke(linewidth=2, foreground="orange")],
)
# Calculate the minimum values between the two functions
tree_y1 = tree_slope * x
tree_y2 = tree_slope * (width - x)
tree_y_min = np.minimum(tree_y1, tree_y2)
# Filling the area where values are smaller than both lines with green color
ax.fill_between(
x,
tree_y_min,
where=(tree_y_min <= tree_y1) & (tree_y_min <= tree_y2),
color=tree_color,
alpha=0.3,
)
# Plot lines and ornaments
solve_info = {}
ornament_colors = ["red", "green", "blue", "orange", "purple", "white"]
ornament_colors = [color for color in ornament_colors if color != tree_color]
ornament_colors = random.sample(ornament_colors, 2)
for i in range(nlevels):
offset = i * height / float(nlevels + 1)
color = ornament_colors[i % len(ornament_colors)]
# Plot lines
sin_line = np.sin(frequency * x) + sine_slope * x + offset
x_line = x[(sin_line < tree_left) & (sin_line < tree_right)]
y_line = sin_line[(sin_line < tree_left) & (sin_line < tree_right)]
if len(x_line) == 0:
continue
ax.plot(
x_line,
y_line,
color=color,
path_effects=[patheffects.withStroke(linewidth=5, foreground="gold")],
)
# Calculate number of ornaments
total_length = np.max(x_line) - np.min(x_line)
cycles = frequency * total_length / (2 * math.pi)
n_ornaments = min(max(3, int(round(per_cycle * cycles))), 10)
if i == nlevels - 1:
n_ornaments = 2
# Solve optimization problem
solution, solve_info[i + 1] = solve(
solver=solver,
objective=objective,
n=n_ornaments,
offset=offset,
)
# Plot ornaments
ax.scatter(
solution.X,
solution.Y,
color=color,
edgecolor="gold",
zorder=3,
s=100,
)
fig.show()