matplotlib's 3d scaling bugged? - python

I am trying to work around the limitation of matplotlib that it cannot not scale the axes individually. In trying to achieve that by putting a dot on each axis. Weirdly it is telling me
.../matplotlib/collections.py:1003:RuntimeWarning: invalid value encountered in sqrt
scale = np.sqrt(self._sizes) * dpi / 72.0 * self._factor
Here is my code
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from itertools import permutations
fig = plt.figure()
ax = Axes3D(fig)
a = np.array(list(set(permutations((1, 0, 0), 3)) | set(permutations((-1, 0, 0), 3))))
plt.scatter(a[:, 0], a[:, 1], a[:, 2])

Related

Performing a polar transformation on an image in reverse clock direction using scikit-image

As the following experiment shows, the warp_polar function of the scikit-image library performs the polar transformation in clock direction. However, I want to perform a polar transformation in the reverse clock direction. I should probably flip or rotate the image in some way to achieve the desired end result. However, I am not sure how to do this. I would appreciate any efficient solution.
In a correct solution, the transformed image would have the following sequence of numbers: 3, 2, 1, 12, 11, 10....
from matplotlib import pyplot as plt
import matplotlib.image as mpimg
import matplotlib.gridspec as gridspec
from skimage.transform import warp_polar
import cv2
testImg = cv2.cvtColor(mpimg.imread('clock.png'), cv2.COLOR_BGR2GRAY)
pol = warp_polar(testImg, radius=min(testImg.shape)/2)
# Create 2x2 sub plots
gs = gridspec.GridSpec(1, 2)
fig = plt.figure()
ax1 = fig.add_subplot(gs[0, 0]) # row 0, col 0
ax1.imshow(testImg)
ax1.set_title("Original Image")
ax2 = fig.add_subplot(gs[0, 1]) # row 0, col 1
ax2.imshow(pol)
ax2.set_title("Polar Transformation")
plt.show()
Thanks to the comment, I found out that the solution was much simpler than I thought. Flipping the result of warp_polar vertically is equivalent to applying the polar transformation in the reverse clock direction.
import numpy as np
pol = np.flip(pol,0)
you could flip the image on axis prior to input, then run your current polar warp to get the result like this:
from matplotlib import pyplot as plt
import matplotlib.image as mpimg
import matplotlib.gridspec as gridspec
from skimage.transform import warp_polar
import cv2
testImg = cv2.cvtColor(mpimg.imread('clock.png'), cv2.COLOR_BGR2GRAY)
horizontal_flip = testImg[:, ::-1]
pol = warp_polar(horizontal_flip, radius=min(horizontal_flip.shape)/2)
# Create 2x2 sub plots
gs = gridspec.GridSpec(1, 2)
fig = plt.figure()
ax1 = fig.add_subplot(gs[0, 0]) # row 0, col 0
ax1.imshow(horizontal_flip)
ax1.set_title("Original Image")
ax2 = fig.add_subplot(gs[0, 1]) # row 0, col 1
ax2.imshow(pol)
ax2.set_title("Polar Transformation")
plt.show()

Use same scale for 3D pyplot

I would like to set the same scale for the X and Y axis on a 3D plot. Here is a sample plot:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
X = np.array([-3, 5, 6])
Y = np.array([14, -2, -31])
Z = np.array([0.1, 0, -0.1])
ax = plt.axes(projection='3d')
ax.plot(X, Y, Z)
plt.show()
The scale for the X and Y axis is such that they take up the same amount of space even though the true scale of the Y axis is larger than that of the X axis.
How do I make it so that they have an equal scale?
Edit: ax.set_xlim(Y.min(), Y.max()) worked.
In addition to answer above you can use set_box_aspect.
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
X = np.array([-3, 5, 6])
Y = np.array([14, -2, -31])
Z = np.array([0.1, 0, -0.1])
ax = plt.axes(projection='3d')
ax.set_box_aspect([1,1,1]) #aspect ratio x,y,z
ax.plot(X, Y, Z)
plt.show()

ValueError: c of shape (7303,) not acceptable as a color sequence for x

I am trying to visualize some data in Axes3D, but I'm getting an error that I don't know how to solve.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sb
from sklearn.cluster import KMeans
from sklearn.metrics import pairwise_distances_argmin_min
%matplotlib inline
from mpl_toolkits.mplot3d import Axes3D
plt.rcParams['figure.figsize'] = (16, 9)
plt.style.use('ggplot')
These are the axes for my 3D figure:
X = np.array(piv_tb[['00:00', '01:00', '02:00']])
y = np.array(piv_tb['users'])
X.shape
(7303, 3)
fig = plt.figure()
ax = Axes3D(fig)
asignar=[]
for row in y:
asignar.append(row)
ax.scatter(X[:, 0], X[:, 1], X[:, 2], c=asignar)
ValueError: c of shape (7303,) not acceptable as a color sequence for x with size 7303, y with size 7303
Any idea why I'm getting this error and how to solve it?

How to shade a region under a curve

I would like to shade a region under a curve. This is my attempt:
from scipy.stats import lognorm
import matplotlib.pyplot as plt
import numpy as np
xpoints = np.linspace(0,10,100)
plt.vlines(2, 0, lognorm.pdf(2,1), color='r', linestyles='solid')
plt.vlines(3, 0, lognorm.pdf(3,1), color='r', linestyles='solid')
plt.fill_between([2,3], [lognorm.pdf(2,1), lognorm.pdf(3,1)], color='red')
plt.plot(xpoints, lognorm.pdf(xpoints,1))
However this doesn't shade under the curve properly.
How do you do this properly?
Using where
Using the where argument of fill_between allows to select the range over which the filling should occur.
from scipy.stats import lognorm
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = lognorm.pdf(x, 1)
plt.vlines(2, 0, lognorm.pdf(2, 1), color='r', linestyles='solid')
plt.vlines(3, 0, lognorm.pdf(3, 1), color='r', linestyles='solid')
plt.fill_between(x, y, where=((x >= 2) & (x <= 3)), color='red')
plt.plot(x, y)
plt.show()
A problem with this may be that the point of the original curve which is closest to the boundary chosen may still be too far away, such that gaps may occur.
Worthwhile to note that if you choose the points dense enough, or for that matter, just intelligently enough, such problems would be circumvented. I.e. using 101 points, such that 2.0 and 3.0 are actually part of the data,
x = np.linspace(0, 10, 101)
would result in a nice picture:
Plotting a refined version of the curve.
It may hence make sense to reevaluate your function on a denser grid and plot it independently.
from scipy.stats import lognorm
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = lognorm.pdf(x, 1)
plt.vlines(2, 0, lognorm.pdf(2, 1), color='r', linestyles='solid')
plt.vlines(3, 0, lognorm.pdf(3, 1), color='r', linestyles='solid')
xf = np.linspace(2, 3, 301)
yf = lognorm.pdf(xf, 1)
plt.fill_between(xf, yf, color='red')
plt.plot(x, y)
plt.show()
you are filling based on 2 points only, try this instead:
plt.fill_between(xpoints[20:31], [lognorm.pdf(i,1) for i in xpoints[20:31]], color='red')

Matplotlib matrix/image explicitly state axis values

I would use imshow for this, so I will use it to describe my problem.
I have several matrices which I would like to plot on the same axis. Something like this:
import matplotlib.pyplot as plt
import numpy as np
a = np.array([[0,1,2],[0,1,2]])
x = np.array([0,1,2])
y = np.array([0,1])
a2 = np.array([[10,11,12],[10,11,12]])
x2 = np.array([10,11,12])
y2 = np.array([0,1])
plt.imshow(a,extent=[x.min(),x.max(),y.min(),y.max()])
plt.imshow(a2,extent=[x2.min(),x2.max(),y2.min(),y2.max()])
plt.show()
(With this code the first imshow is overwritten by the second)
The reason why I can't combine them into a single matrix with one set of x and y axes (by filling the gaps with zeros) is that the combined matrix would be huge and there are large spaces in between the strips.
It's not overwritten, the axes limits are just reset to the extents of the last image each time.
Just call plt.autoscale().
As a quick example of what you're seeing:
import numpy as np
import matplotlib.pyplot as plt
data1, data2 = np.random.random((2,10,10))
fig, ax = plt.subplots()
ax.imshow(data1, extent=[-10, 0, -10, 0])
ax.imshow(data2, extent=[10, 20, 10, 20])
plt.show()
Now, if we just call autoscale:
import numpy as np
import matplotlib.pyplot as plt
data1, data2 = np.random.random((2,10,10))
fig, ax = plt.subplots()
ax.imshow(data1, extent=[-10, 0, -10, 0])
ax.imshow(data2, extent=[10, 20, 10, 20])
ax.autoscale()
plt.show()

Categories

Resources