0

I have a function that takes in strings representing 3D functions. When I plot functions like a torus or sphere using set_aspect('equal') they look great, otherwise without set_aspect() they look warped and elongated. On the flip side, when I plot the other function mentioned below, set_aspect() makes it terribly warped/scaled out beyond recognition, whereas without set_aspect() it looks great. I have tried fiddling around with the limits as well as box aspect/set_aspect('auto') to no avail. I want my function to be able to handle a wide variety of math functions, so I'm trying to avoid hardcoding things that would work for some functions but not others. Working in VSCode Matplotlib 3.7.1.

import matplotlib
import matplotlib.pyplot as plt

import sympy
import numpy as np



def queryMatplotlib3dEq(sol, ax):

    lhs, rhs = sol.split("=")

    def f(x, y):
        if (lhs == "z"):
            return eval(rhs)
        else:
            return eval(lhs)

    x = np.linspace(-10, 10, 10000)
    y = np.linspace(-10, 10, 10000)
    X, Y = np.meshgrid(x, y)
    if (lhs == 'z' or rhs == 'z'):
        Z = f(X, Y)
    ax.plot_surface(X, Y, Z, cmap="viridis")
  
    # ax.set_box_aspect((1, 1, 1))


    #Removing this makes some functions look bad, and other functions look good
    # ax.set_aspect('equal')


    # ax.relim()
    # ax.autoscale_view()




#With set_aspect('equal') these looks great, without it they look warped
# qVal = "(8- (x**2 + y**2)**(1/2))**2 + z**2 = 3"
# qVal="x**2+y**2+z**2=100"

# #With set_aspect('equal') this looks terribly warped, without it it looks great
qVal="x*y**3 -y*x**3"


x, y, z = sympy.symbols('x y z')

if ('=' in qVal):
    lhs, rhs = qVal.split('=')
    eq = sympy.Eq(eval(lhs), eval(rhs))
else:
    eq = sympy.Eq(eval('z'), eval(qVal))


sols = ['z=' + v.replace('sqrt', 'np.sqrt')
        for v in map(str, sympy.solve(eq, z))]

fig = plt.figure()
ax = plt.axes(projection="3d")

for sol in sols:
    print(sol)
    queryMatplotlib3dEq(sol, ax)


plt.show()
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
  • What Matplotlib does is what you've asked it to do. If, say, 0 – gboffi Apr 29 '23 at 21:10
  • @gboffi I see youre referring to the x and y linespace that I set. I'm sure the better way would be to set it dynamically depending on the function to be plotted, but I'm not sure how I would go about implementing that. – Joshua Guevara Apr 29 '23 at 21:55
  • Matplotlib has a very good implementation of dynamically scaling the 3D plot, if you have a fixed domain for x and y you can set the aspect ratio only for that plane, as explained and shown in the answer I've linked above, and let Matplotlib do the rest. – gboffi Apr 30 '23 at 07:21

0 Answers0