Naltharial
Naltharial

Reputation: 2152

Drawing a cuboid to image

I'm in the process of moving a significant application to Python from PHP. All is well, except one particular issue that I can't seem to get to the bottom of.

The old application uses a PHP library Image_3D to draw some cuboids to an image (SVG, though that's not important) and display them on the web page.

I've migrated almost everything to Flask(w/SQLAlchemy) except fo the imaging. I've tried matplotlib, vpython and almost got desperate enough to reach for OpenGL bindings.

This is how PHP currently renders a few examples:

You can see that it remains readable enough even in extreme situations.

My best attempt at Python does fairly poorly:


(source: offblast.si)


(source: offblast.si)

The image is entirely unreadable. I didn't fill in the content, because, frankly, there's no point to it - you can't make anything out. Any attempt at fixing the view with ax.init_view was even worse, no matter the elevation or azimuth.

The code is just a bunch of points, rendered with

fig = plt.figure(frameon=False)

ax = fig.gca(projection='3d')
ax.set_axis_off()
ax.set_aspect('equal')
ax.plot_wireframe(points[:, 0], points[:, 1], points[:, 2], color="b")

plt.savefig(filename, bbox_inches='tight', pad_inches=0)

I'm sure I'm doing something wrong, but I can't figure out how to make readable renders work in Python / matplotlib or if there's a different library better suited for the task.

Update 1

It occurs to me I haven't described the problem correctly - it's a business-restricted subset of the knapsack problem. The container and cuboids within are thus arbitrarily positioned. The visualization module recieves dimensions and positions and needs to render them. The regularity of the previous examples is just a first-order optimal solution and is found often, but not in the majority of situations.

Some more examples to illustrate:

Update 2

A better solution with matplotlib, folowing the answer below. It doesn't seem easy to get MPL to rotate the entire plot as to show a useful overview. ax.view_init should allow for changing the height, but it seems the FOV is too wide for such a narrow plot and all it does is transform the edges slightly.


(source: offblast.si)

Upvotes: 0

Views: 750

Answers (1)

tom10
tom10

Reputation: 69242

You could use either VPython of matplotlib for this. In matplotlib I'd use a 3d box for your bars, and than another for the frame, and turn off the axes. Here's an examples:

enter image description here

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

fig = plt.figure()
ax = fig.add_subplot(111, projection = "3d")

ax.autoscale(enable=False)

xpos = np.arange(5)
ypos = np.zeros(5)
zpos = np.zeros(5)

dx = np.ones(5)
dy = 5*np.ones(5)
dz = 5 + 5*np.random.random(5)

colors = ['r', 'c', 'g', 'y', 'm']
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color=colors, alpha=1)
ax.bar3d(0, 0, 0, 5, 5, 25, color=(1, 1, 1, 0))

ax.set_axis_off()
plt.show()

Upvotes: 1

Related Questions