2

I have the result of some computations made with numpy.matrix types

import numpy as np
import matplotlib.pyplot as plt

from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = Axes3D(fig)

# [...]

# Downsampling for plotting
# type(verts):  np.matrix
# verts.shape:  (3, 700000)

verts = verts_small[:, ::1000]

ax.plot(verts[0, :], verts[1, :], verts[2, :], 'o')

This has strange behavior. Plots the points all in a line.

If instead:

verts = np.array(verts[:, ::1000])

the 3D-plot works as expected. Is this an intended behavior or is it a bug?

Eric
  • 95,302
  • 53
  • 242
  • 374
rdbisme
  • 850
  • 1
  • 13
  • 39
  • Did you look at the shape of `verts` after the `::1000` indexing? If you start with a 2d array, you need to make sure you are indexing the right dimension. Practice that kind of indexing on something smaller, so you understand the difference. – hpaulj Feb 26 '17 at 23:52
  • @hpaulj there was a typo on the first call that I corrected. By the way the shape that I get after the slicing is the same both for `np.array` and `np.matrix` types. – rdbisme Feb 27 '17 at 00:07
  • 2
    Keep in mind that when you index a `np.matrix` the result will still be 2d. A `np.ndarray` maybe 1d (depending on how you index). – hpaulj Feb 27 '17 at 00:20
  • 1
    _"Strange behaviour of ____ [with] `np.matrix`"_ is in general, not a surprise. Writing code that deals with np.matrix is difficult, because it resists conversion to 1d arrays. There's talk of deprecating `np.matrix` in an immintent release, but we're not there yet. Either way, I'd strongly suggest not using it anyway. – Eric Feb 27 '17 at 02:05
  • @Eric I see your point. But when using `np.array` for linear algebra computations I'm very often clashing with the infamous *"Cannot broadcast [...]"* and I always find myself struggling with `np.reshape` method to achieve calculations that would come out naturally if using the classical matrix notation of linear algebra. – rdbisme Feb 27 '17 at 02:12
  • @SolidSnake: If you clash with that, it's probably because you used `*` when you mean `@` or `np.dot`. `*` is just as much not part of classical matrix notation as `@` ;) – Eric Feb 27 '17 at 02:16
  • @Eric yes, I'm aware of the different operators. But the fact that I need to think which method to use is, in my opinion and for my limited use case, an avoidable overhead. What I mean is that considering everything as a matrix (MATLAB should work like that... ) is easier. – rdbisme Feb 27 '17 at 02:23
  • 1
    The problem with the "consider everything as a matrix" mindset is that every list of numbers can now be horizontal or vertical, and everything needs to cope with that. I think the real problem is that `np.matrix` bundles a semi-useful feature, that `*` always means `np.dot`, with the very frustrating one that everything is 2d – Eric Feb 27 '17 at 02:49
  • 1
    IMO, `some_matrix.reshape((2, 1, 3, 1)).shape != (2, 1, 3, 1)` is just downright evil – Eric Feb 27 '17 at 02:54
  • My top scoring answer, http://stackoverflow.com/a/20765358/901925. `m.A1` gives 1d array. – hpaulj Feb 27 '17 at 03:43
  • 1
    @hpaulij Yes, thanks. Saw this on the docs. :) @Eric In classical mathematics it's already like this. Vectors are column vectors (so vertical). And with this assumption is easy to do everything just using the definition of matrix multiplication. (e.g. Scalar product `v.T*u`, norm `v.T*v`, linear operator `A*v`, matrix x matrix `A*B`. Everything comes flawlessly. :). But I believe it's a matter of opinions, and maybe there are some applications where this is unwanted. Thanks for the fruitful discussion. – rdbisme Feb 27 '17 at 08:26

1 Answers1

1

As hpaulj mentions, the issue here is that the result is 2d:

>>> verts = np.zeros((3, 100))
>>> verts_m = np.matrix(verts)
>>> verts[0, :].shape
(100,)
>>> verts_m[0, :].shape
(1, 100)

Crucially, this breaks any code that expects to be able to iterate over a column or row of a 2d array:

>>> len(verts)
100
>>> len(verts_m)
1

Worse still, verts_m doesn't even behave as a list of lists:

>>> len(verts[0])
1
>>> len(verts[0][0])
1
>>> len(verts[0][0][0][0][0][0][0][0][0][0])
1

In essence, np.matrix breaks most of the rules about shapes when it comes to numpy operations. To support it in matplotlib, they would either need to deliberately work around these rule breakages, or force the inputs to be standard np.arrays.

Eric
  • 95,302
  • 53
  • 242
  • 374