How differently do matplotlib.pyplot and seaborn treat numpy arrays? - python

Turns out that when trying to plot the same synthetically generated numpy arrays of 2D points (one with 12 data points and another with just 1) in both pyplot and seaborn, I have to change the array dimension of the single-point array so that the program does not yield an error:
points = np.array([[1,2],[5,6],[4,1],[3,8],[7,5],[1,5],[0,8],[4,3],[2,1],[1,7],[3,8],[2,5]])
p = np.array([2.5,2])
import matplotlib.pyplot as plt
plt.style.use("ggplot")
plt.plot(points[:,0], points[:,1],"ro")
plt.plot(p[0],p[1], "bo")
plt.axis([0,7.5,0,8.5]);
With the above code I am able to get the pyplot right. However, if I try in seaborn:
import seaborn as sns
sns.scatterplot(x = points[:,0], y = points[:,1])
sns.scatterplot(x = p[:,0], y = p[:,1])
I get the following error:
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-62-31fe2d015723> in <module>
1 import seaborn as sns
2 sns.scatterplot(x = points[:,0], y = points[:,1])
----> 3 sns.scatterplot(x = p[:,0], y = p[:,1])
IndexError: too many indices for array: array is 1-dimensional, but 2 were indexed
Nonetheless, if I change the dimension of the p array:
p = np.array([[2.5,2]])
It now plots well in seaborn, but no longer works for plotting with pyplot. It yields the following error:
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-63-f26870ae2995> in <module>
5 plt.style.use("ggplot")
6 plt.plot(points[:,0], points[:,1],"ro")
----> 7 plt.plot(p[0],p[1], "bo")
8 plt.axis([0,7.5,0,8.5]);
IndexError: index 1 is out of bounds for axis 0 with size 1
Does anyone know why this happens?

You have an inconsequence in the way you define the point p.
You can either define p as a points array of length = 1:
p = np.array([[2.5,2]])
Then use it in pyplot as follows:
plt.plot(p[:,0],p[:,1], "bo")
and in seaborn:
sns.scatterplot(x = p[:,0], y = p[:,1])
Alternatively, if you really want to have the point p defined as a 1 dimensional array, just pass it as follows:
plt.plot(p[0], p[1], "bo")
sns.scatterplot(x = [p[0]], y = [p[1]])

Pass it like this:
sns.scatterplot(x = [p[0]], y = [p[1]])
Don't pass the values as scalar type. Pass it as a list of elements.

Related

Error bar in python:ErrorbarContainer object of 3 artists

I am trying to make an error plot but I get the error:
import numpy as np
import matplotlib.pyplot as plt
x = np.array([1, 2, 3])
y = np.array([17706973.57161736, 4605821.60887734, 2179197.59021156])
nor = np.array([1.21377113, 0.31571817, 0.14937884])
plt.errorbar(x, y, yerr = nor)
ErrorbarContainer object of 3 artists
and the plot does not contain error bars. Any idea?
What are you getting is not an error, it is the output of plt.errorbar. The reason you do not see the bars is because the scale of the error is way smaller than the scale of the data you are plotting. In fact, if you make the errors larger you will see them:
import numpy as np
import matplotlib.pyplot as plt
x = np.array([1, 2, 3])
y = np.array([17706973.57161736, 4605821.60887734, 2179197.59021156])
# Larger error.
nor = np.array([1.21377113 * 5000000, 0.31571817 * 5000000, 0.14937884 * 5000000])
plt.errorbar(x, y, yerr = nor)

3D plot of Excel data

I'm trying to recreate this plot using some of my own excel data but I've hit a wall. So far I have:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
df = pd.read_excel(r'/path/to/data.xlsx')
yr = df['Year']
jd = df['Jday']
dc = df['Discharge']
x = np.asarray(yr)
y = np.asarray(jd)
z = np.asarray(dc)
X,Y,Z = np.meshgrid(x,y,z)
ax = plt.figure().add_subplot(projection='3d')
ax.plot_surface(X,Y,Z, cmap='autumn')
ax.set_xlabel("Year")
ax.set_ylabel("Jday")
ax.set_zlabel("Discharge")
plt.show()
But when I run this I get:
Traceback (most recent call last):
File "/Users/Desktop/main.py", line 19, in <module>
ax.plot_surface(X,Y,Z, cmap='autumn')
File "/Users/venv/lib/python3.10/site-packages/matplotlib/_api/deprecation.py", line 412, in wrapper
return func(*inner_args, **inner_kwargs)
File "/Users/venv/lib/python3.10/site-packages/mpl_toolkits/mplot3d/axes3d.py", line 1581, in plot_surface
raise ValueError("Argument Z must be 2-dimensional.")
ValueError: Argument Z must be 2-dimensional.
Any help would be appreciated.
EDIT:
I changed my code to:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
df = pd.read_excel(r'/path/to/data.xlsx')
yr = df['Year']
jd = df['Jday']
dc = df['Discharge']
X = np.asarray(yr).reshape(-1,2)
Y = np.asarray(jd).reshape(-1,2)
Z = np.asarray(dc).reshape(-1,2)
fig = plt.figure(figsize=(14,8))
ax = plt.axes(projection='3d')
my_cmap = plt.get_cmap('seismic')
surf = ax.plot_surface(X,Y,Z,
cmap = my_cmap,
edgecolor = 'none')
fig.colorbar(surf, ax=ax,
shrink = 0.5, aspect = 5)
plt.show()
When I run this it produces the following plot:
Which obviously doesn't match the other plot. It seems to be plotting the data from each year in a single line instead of creating filled in polygons which is what I think it's supposed to do. I have a feeling this issue has to do with the .reshape function but I'm not entirely sure.
Note: original answer completely rewritten!
The problem is, as your data stated, that the Z-argument must be two-dimensional. In your problem, you don't need np.meshgrid at all. This is typically used to make a 'grid' of all possible combinations of X/Y, after which you can use these combinations to calculate your response matrix Z. However, since all your data is read in, it is merely a reshaping of all 1d-arrays to 2d-arrays:
target_shape = (np.sqrt(X.shape[0]),-1)
X = np.reshape(X, target_shape)
Y = np.reshape(Y, target_shape)
Z = np.reshape(Z, target_shape)
Have a look at the documentation of np.reshape for some more information.

Python TypeError: float() argument must be a string or a number, not 'SingleBlockManager'

I would appreciate any input. I was previously able to obtain image using this code but going back through my work it is now giving me this error. Any ideas how I can fix this?Perhaps this is due to upgrading matplotlib recently?
Code I am using
import pandas as pd
import numpy as np
np.random.seed(12345)
df = pd.DataFrame([np.random.normal(32000,200000,3650),
np.random.normal(43000,100000,3650),
np.random.normal(43500,140000,3650),
np.random.normal(48000,70000,3650)],
index=[1992,1993,1994,1995])
import matplotlib as mpl
import matplotlib.pyplot as plt
import scipy.stats as ss
%matplotlib notebook
n = df.shape[1]
year_means = df.mean(axis=1)
year_std = df.std(axis=1)/(np.sqrt(n))
yerr = year_std * 1.96
y= 37000
norm = mpl.colors.Normalize(vmin=-1.96,vmax=1.96)
cmap = mpl.cm.get_cmap('seismic')
colors = pd.DataFrame([])
colors['intensity'] = norm((year_means-y) / year_std)
colors['color'] = [cmap(x) for x in colors['intensity']]
plt.figure()
bar_plot = plt.bar(range(df.shape[0]), year_means, yerr = yerr, color = colors['color']);
hoz_line = plt.axhline(y=y, color='grey', linewidth=2, linestyle = ':');
y_text = plt.text(3.4, y, 'y = %d' %y, bbox=dict(fc='white',ec='k'));
plt.xticks(range(df.shape[0]), df.index, alpha = 0.8);
Error Message I am receiving
TypeError Traceback (most recent call last)
<ipython-input-10-6b68c0797acf> in <module>()
2 cmap = mpl.cm.get_cmap('seismic')
3 colors = pd.DataFrame([])
----> 4 colors['intensity'] = norm((year_means-y) / year_std)
5 colors['color'] = [cmap(x) for x in colors['intensity']]
6 plt.figure()
TypeError: float() argument must be a string or a number, not 'SingleBlockManager'
I was able to fix. Apparently you cannot call a matplotlib.colors.Normalize with a dataframe any more in matplotlib 2.2. Use the values instead I updated line 4 to
colors['intensity'] = norm(((year_means-y) / year_std).values)

Python 3D isosurface from a set of 2D images

I am using this code:
z = np.asarray(image_list)
mydata = z[::1,::1]
fig = pl.figure(facecolor='w')
ax2 = fig.add_subplot(1,1,1,projection='3d')
x,y = np.mgrid[:mydata.shape[0],:mydata.shape[1]]
ax2.plot_surface(x,y,mydata,cmap=pl.cm.jet,rstride=1,cstride=1,linewidth=0.,antia liased=False)
ax2.set_title('3D')
ax2.set_zlim3d(0,200)
pl.show()
To plot a 3D image using a list containing a set of images, but I get this error:
Traceback (most recent call last):
ax2.plot_surface(x,y,mydata,cmap=pl.cm.jet,rstride=1,cstride=1,linewidth=0.,antialiased=False)
File "/usr/lib/pymodules/python2.7/mpl_toolkits/mplot3d/axes3d.py", line 1553, in plot_surface
X, Y, Z = np.broadcast_arrays(X, Y, Z)
File "/usr/lib/python2.7/dist-packages/numpy/lib/stride_tricks.py", line 100, in broadcast_arrays
"incompatible dimensions on axis %r." % (axis,))
ValueError: shape mismatch: two or more arrays have incompatible dimensions on axis 2
Could anyone help me with this error or suggest some other technique to create a 3D image from a image list containing 2D images?
I can't remember where I found this exactly (it was another StackOverflow thread), but this is working code - yours looks like a sample of the one I have - just change out the filename to load:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pylab as pl
from PIL import Image
import numpy as np
import pylab
img = Image.open('natureWallpaper.jpg').convert('L')
z = np.asarray(img)
#slice notation: "start:stop:step" - here it's referring to the z matrix's x and y dimensions, get the whole of each
mydata = z[::1,::1]
fig = pl.figure(facecolor='w')
# subplot(nrows, ncols, plotnumber)
ax1 = fig.add_subplot(1,2,1)
# im = ax1.imshow(mydata,interpolation='nearest',cmap=pl.cm.jet)
im = ax1.imshow(mydata,interpolation='none',cmap=pl.cm.jet)
ax1.set_title('2D')
ax2 = fig.add_subplot(1,2,2,projection='3d')
x,y = np.mgrid[:mydata.shape[0],:mydata.shape[1]] ax2.plot_surface(x,y,mydata,cmap=pl.cm.jet,rstride=10,cstride=10,linewidth=0.antialiased=False)
ax2.set_title('3D')
ax2.set_zlim3d(0,255)
pl.show()

Looping within matplotlib

I am trying to plot multiple graphs on a single set of axis.
I have a 2D array of data and want to break it down into 111 1D arrays and plot them. Here is an example of my code so far:
from numpy import *
import matplotlib.pyplot as plt
x = linspace(1, 130, 130) # create a 1D array of 130 integers to set as the x axis
y = Te25117.data # set 2D array of data as y
plt.plot(x, y[1], x, y[2], x, y[3])
This code works fine, but I cannot see a way of writing a loop which will loop within the plot itself. I can only make the code work if I explicitly write a number 1 to 111 each time, which is not ideal! (The range of numbers I need to loop over is 1 to 111.)
Let me guess...long time matlab user?
Matplotlib automatically add a line plot to the present plot if you don't create a new one. So your code can be simply:
from numpy import *
import matplotlib.pyplot as plt
x = linspace(1, 130, 130) # create a 1D array of 130 integers to set as the x axis
y = Te25117.data # set 2D array of data as y
L = len(y) # I assume you can infere the size of the data in this way...
#L = 111 # this is if you don't know any better
for i in range(L)
plt.plot(x, y[i], color='mycolor',linewidth=1)
import numpy as np
import matplotlib.pyplot as plt
x = np.array([1,2])
y = np.array([[1,2],[3,4]])
In [5]: x
Out[5]: array([1, 2])
In [6]: y
Out[6]:
array([[1, 2],
[3, 4]])
In [7]: for y_i in y:
....: plt.plot(x, y_i)
Will plot these in one figure.

Categories