The Wayback Machine - https://web.archive.org/web/20250617182409/https://github.com/matplotlib/matplotlib/issues/20904
Skip to content

[Bug]: Force 3D plots to use the entire figure space #20904

Closed
@Davide-sd

Description

@Davide-sd

Bug summary

I'm trying to create a 3D plot in which the axes adapts to the size of the figure. In the provided example, I'd like for the x and y axis to occupy the entire width of the figure. Ideally, I'd also like to get an equal aspect ratio on all axis.

It used to work with older Matplotlib versions (except for the equal aspect ratio), but I'm unable to replicate the outcome with newer versions.

After spending a couple of hours trying different combinations and reading the docs, I've decided to call this a bug?!?! Please, correct me if I'm wrong by providing a working solution.

Code for reproduction

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(figsize=(5, 2.5))
ax = fig.add_subplot(projection='3d')
ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([1, 1, 1, 0.5]))

u = v = np.linspace(0, 2 * np.pi, 50)
u, v = np.meshgrid(u, v)
X = np.cos(v) * (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v))
Y = (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v)) * np.sin(v)
Z = -np.cos(u - 3 * v) * (5/4 + np.sin(3 * u))

ax.plot_surface(X, Y, Z, rstride=1, cstride=1, color=[0.7] * 3, linewidth=0.25, edgecolor="k")
ax.set_box_aspect([ub - lb for lb, ub in (getattr(ax, f'get_{a}lim')() for a in 'xyz')])

plt.show()

Actual outcome

Note the awful clipping rectangle!

index

Expected outcome

The following output has been generated with Matplotlib v3.1.2 :

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(figsize=(5, 2.5))
ax = fig.add_subplot(projection='3d')

u = v = np.linspace(0, 2 * np.pi, 50)
u, v = np.meshgrid(u, v)
X = np.cos(v) * (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v))
Y = (6 - (5/4 + np.sin(3 * u)) * np.sin(u - 3 * v)) * np.sin(v)
Z = -np.cos(u - 3 * v) * (5/4 + np.sin(3 * u))

ax.plot_surface(X, Y, Z, rstride=1, cstride=1, color=[0.7] * 3, linewidth=0.25, edgecolor="k")

plt.show()

Screenshot_20210825_235131

Operating system

Ubuntu 20.04

Matplotlib Version

3.4.3

Matplotlib Backend

module://ipympl.backend_nbagg, Qt5Agg

Python version

3.8.10

Jupyter version

6.4.0

Other libraries

No response

Installation

pip

Conda channel

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions