How to add many values in error-bars chart in Python? - python-3.x

Anyone can help me, please?
x = np.array([['A','B','C','D','E'],['A','B','C','D','E']])
y = np.array([[2.60, 3.04, 2.98, 3.76, 3.00],[2.68, 2.96, 2.94, 3.75,3.03]])
yerr = np.array([[1.26, 1.37, 1.33 , 1.27, 1.38],[ 1.25, 1.38, 1.31, 1.27,1.38 ]])
plt.errorbar(x, y, yerr=yerr, fmt='o')
I am trying to plot error-bars with many values but the Python extracted the errors that
TypeError: unhashable type: 'numpy.ndarray'
although matplotlib.pyplot allows to draw error-bar with array data?
Many thanks,

parameters x and y should be one dimensional array, try to modify like this
x = np.array(['A','B','C','D','E'])
y = np.array([2.60, 3.04, 2.98, 3.76, 3.00])
yerr = np.array([[1.26, 1.37, 1.33 , 1.27, 1.38],[ 1.25, 1.38, 1.31, 1.27,1.38 ]])
plt.errorbar(x, y, yerr=yerr, fmt='o')

Related

Fitting a monotonically increasing spline function using Scipy

I want to fit a monotonically increasing smooth spline function for a dataset
Code:
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
x = [0., 0.75, 1.8, 2.25, 3.75, 4.5, 6.45, 6.75, 7.5, 8.325, 10.875, 11.25, 12.525, 12.75, 15., 20.85, 21.]
y = [2.83811035, 2.81541896, 3.14311655, 3.22373554, 3.43033456, 3.50433385, 3.66794514, 3.462296, 3.59480959,
3.56250726, 3.6209845, 3.63034523, 3.68238915, 3.69096892, 3.75560395, 3.83545191, 3.90419498]
plt.plot(x, y, '*')
plt.show()
f = interp1d(x, y, kind='cubic')
yinp = f(x)
plt.plot(x, yinp)
plt.show()
The current fit looks like the above. I would like to know how to fit a monotonically increasing spline function.
I found an example in r posted here How to make monotonic (increasing) smooth spline with smooth.spline() function?. I am not sure what's the appropriate function in the scipy library.
Suggestions will be really helpful.
EDIT:
I'm looking for something like the below (ref.)
EDIT 2:
I'm now using a smoothing spline function scipy.interpolate.UnivariateSpline
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import UnivariateSpline
x = np.array([0., 0.75, 1.8, 2.25, 3.75, 4.5, 6.45, 6.75,
7.5, 8.325, 10.875, 11.25, 12.525, 12.75, 15.,
20.85, 21.])
y = np.array([2.83811035, 2.81541896, 3.14311655,
3.22373554, 3.43033456, 3.50433385,
3.66794514, 3.462296, 3.59480959,
3.56250726, 3.6209845, 3.63034523,
3.68238915, 3.69096892, 3.75560395,
3.83545191, 3.90419498])
spl = UnivariateSpline(x, y, s=0.05)
xs = np.linspace(x.min(), x.max(), 100)
plt.plot(x, y, 'ro', ms=5)
plt.plot(xs, spl(xs), 'cyan', lw=1)
plt.show()
gives the following result
I could get the coeffs and knots of the spline using
print(spl.get_coeffs())
print(spl.get_knots())
k = 3
tck = splrep(xmean, ymean, k=k, s=0.09)
knots = tck[0]
coeffs = tck[1]
print('knot points=', knots)
print('coefficients=', coeffs)
But I am not sure how to use the coefficients and manually generate the function of the spline curve. Could someone please add a bit more detail to this?
For example, when we have 4 data points
x = [0., 0.75, 1.8, 2.25]
y = [2.83811035, 2.81541896, 3.14311655, 3.22373554]
I would like to print the piecewise polynomial function to understand how the spline function looks like.
Use splrep from scipy.interpolate and manually tweak its s parameter which controls the amount of smoothing.
EDIT: The definition of the spline function that splrep returns, in terms of knots and coefficients, is equivalent to scipy.interpolate.BSpline, https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.BSpline.html

sympy lambdify with sympy matrix and numpy vector inputs

I want to compute a symbolic gradient with sympy, e.g.,
import sympy as sym
x, y, z = sym.symbols("x y z", real=True)
T = sym.cos(x**2+y**2)
gradT = sym.Matrix([sym.diff(T, x), sym.diff(T,y), sym.diff(T,z)])
Now I would like to create a lamddify function with this expression:
func = lambdify((x,y,z), gradT,'numpy')
To use the function I have:
gradT_exact = func(np.linspace(0,2,100), np.linspace(0,2,100), np.linspace(0,2,100))
and I receive the following error:
<lambdifygenerated-3>:2: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
return (array([[-2*x*sin(x**2 + y**2)], [-2*y*sin(x**2 + y**2)], [0]]))
If I change T to be a function of x,y,z it gives me no problems...
Why is it giving warnings when T only depends on x and y and z is set to zero.
Thanks in advance!
The gradT expression:
In [84]: gradT
Out[84]:
⎡ ⎛ 2 2⎞⎤
⎢-2⋅x⋅sin⎝x + y ⎠⎥
⎢ ⎥
⎢ ⎛ 2 2⎞⎥
⎢-2⋅y⋅sin⎝x + y ⎠⎥
⎢ ⎥
⎣ 0 ⎦
and its conversion to numpy:
In [87]: print(func.__doc__)
Created with lambdify. Signature:
func(x, y, z)
Expression:
Matrix([[-2*x*sin(x**2 + y**2)], [-2*y*sin(x**2 + y**2)], [0]])
Source code:
def _lambdifygenerated(x, y, z):
return (array([[-2*x*sin(x**2 + y**2)], [-2*y*sin(x**2 + y**2)], [0]]))
If x and y are arrays, then 2 terms will reflect their dimension(s), but the last is [0]. That's why you get the ragged warning.
lambdify does a rather simple lexical translation. It does not implement any deep understanding of numpy arrays. At some level it's your responsibility to check that the numpy code looks reasonable.
with scalar inputs:
In [88]: func(1,2,3)
Out[88]:
array([[1.91784855],
[3.8356971 ],
[0. ]])
but if one input is an array:
In [90]: func(np.array([1,2]),2,3)
<lambdifygenerated-1>:2: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
return (array([[-2*x*sin(x**2 + y**2)], [-2*y*sin(x**2 + y**2)], [0]]))
Out[90]:
array([[array([ 1.91784855, -3.95743299])],
[array([ 3.8356971 , -3.95743299])],
[0]], dtype=object)
The result is object dtype containing 2 arrays, plus that [0] list.
To avoid this problem, the lambdify would have to produce a function like:
In [95]: def f(x,y,z):
...: temp = 0*x*y
...: return np.array([-2*x*np.sin(x**2 + y**2), -2*y*np.sin(x**2 + y**2)
...: , temp])
where temp is designed to give 0 value, but with a shape that reflects the broadcasted operations on x and y in the other terms. I think that's asking too much of lambdify.
In [96]:
In [96]: f(np.array([1,2]),2,3)
Out[96]:
array([[ 1.91784855, -3.95743299],
[ 3.8356971 , -3.95743299],
[ 0. , 0. ]])

Error when making a decision surface graph on a decision tree

My version of python is 3.
I have adapted this code for my data.
And when trying to make the graph, on the line
X = l_atributos[:, pair]
I have the error:
list indices must be integers or slices, not tuple
But I'm not seeing where the problem is. Could you help me?
for pairidx, pair in enumerate([[0, 1],[0, 2],[0, 3],[1, 2],[1, 3],[2, 3]]):
# We only take the two corresponding features
X = l_atributos[:, pair]
y = etiquetas
# Train
clf = DecisionTreeClassifier().fit(X, y)
# Plot the decision boundary
plt.subplot(2, 3, pairidx + 1)
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, plot_step),
np.arange(y_min, y_max, plot_step))
plt.tight_layout(h_pad=0.5, w_pad=0.5, pad=2.5)
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
cs = plt.contourf(xx, yy, Z, cmap=plt.cm.RdYlBu)
plt.xlabel(['so2', 'no2', 'temp', 'viento', 'precipitacion'][pair[0]])
plt.ylabel(['so2', 'no2', 'temp', 'viento', 'precipitacion'][pair[1]])
# Plot the training points
for i, color in zip(range(n_classes), plot_colors):
idx = np.where(y == i)
plt.scatter(X[idx, 0], X[idx, 1], c=color, label=['nivel 0', 'nivel 1', 'nivel 2', 'nivel 3'][i], cmap=plt.cm.RdYlBu, edgecolor='black', s=15)
plt.suptitle("Decision surface of a decision tree using paired features")
plt.legend(loc='lower right', borderpad=0, handletextpad=0)
plt.axis("tight")
plt.figure()
clf = DecisionTreeClassifier().fit(l_atributos, etiquetas)
plot_tree(clf, filled=True)
plt.show()
The common problem in data structures used to represent the data in the example and your code.
If you print the content of iris example you may see next data:
from sklearn.datasets import load_iris
iris = load_iris()
print(iris.data)
output
array([[5.1, 3.5, 1.4, 0.2],
[4.9, 3. , 1.4, 0.2],
[4.7, 3.2, 1.3, 0.2],
...
As you can see this is the 2D array was wrapped with numpy.array(...) wrapper.
But in your example you have just 2D array:
print(l_atributos[:3])
result
[['66', '26.0', '12.1', '16.0', '0.0'], ['75', '16.0', '10.0', '26.0', '5.9'], ['61', '25.0', '8.0', '23.0', '29.4']]
If you want to use scikit's example with minimum changes just wrap your data with numpy.array:
import numpy as np
l_atributos = np.array([['66', '26.0', '12.1', '16.0', '0.0'], ['75', '16.0', '10.0', '26.0', '5.9'], ['61', '25.0', '8.0', '23.0', '29.4']])

How to plot values on a Python Basemap?

Is it possible to plot values on a basemap?
Let's say I have 3 lists of data.
lat = [50.3, 62.1, 41.4, ...]
lon = [12.4, 14.3, 3.5, ...]
val = [3, 5.4, 7.4, ...]
I've created a simple basemap:
def create_map(ax=None, lllon=6.00, lllat=47.0, urlon=16.00, urlat=55.10):
m = Basemap(llcrnrlon=lllon, llcrnrlat=lllat, \
urcrnrlon=urlon, urcrnrlat=urlat, \
resolution='h', \
projection='tmerc', \
lon_0=(lllon+urlon)/2, lat_0=(lllat+urlat)/2)
m.drawcoastlines()
m.drawcountries()
m.drawrivers()
return m
Now I want to plot the values of the "val" list on this map depending of their coordinates:
m = create_map()
x, y = m(lon,lat)
m.scatter(x, y, val) # somthing like that
plt.show()
Well, i already figured out that basemap is unable to plot 3d values, but is there a way to realize it?
The short, sweet, and simple answer to your first question is yes, you can plot using basemap (here's the documentation for it).
If you're looking to plot in 3d, there is documentation that explains how to plot using Basemap. Here's a simple script to get you started:
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
plt.close('all')
fig = plt.figure()
ax = fig.gca(projection='3d')
extent = [-127, -65, 25, 51]
# make the map and axis.
m = Basemap(llcrnrlon=extent[0], llcrnrlat=extent[2],
urcrnrlon=extent[1], urcrnrlat=extent[3],
projection='cyl', resolution='l', fix_aspect=False, ax=ax)
ax.add_collection3d(m.drawcoastlines(linewidth=0.25))
ax.add_collection3d(m.drawcountries(linewidth=0.25))
ax.add_collection3d(m.drawstates(linewidth=0.25))
ax.view_init(azim = 230, elev = 15)
ax.set_xlabel(u'Longitude (°E)', labelpad=10)
ax.set_ylabel(u'Latitude (°N)', labelpad=10)
ax.set_zlabel(u'Altitude (ft)', labelpad=20)
# values to plot - change as needed. Plots 2 dots, one at elevation 0 and another 100.
# also draws a line between the two.
x, y = m(-85.4808, 32.6099)
ax.plot3D([x, x], [y, y], [0, 100], color = 'green', lw = 0.5)
ax.scatter3D(x, y, 100, s = 5, c = 'k', zorder = 4)
ax.scatter3D(x, y, 0, s = 2, c = 'k', zorder = 4)
ax.set_zlim(0., 400.)
plt.show()

Using Groupyby on data to form box chart

I have (x,y) that looks like this:
[(0.32,0.5), (0.23, 0.3), (0.12, 0.5), (0.14, 0.2)...]
I want to create a box chart like this https://plot.ly/python/box-plots/
where the x axis are intervals like 0-0.1, 0.1-0.2 ...
and the y are the y values in (x, y).
What's the easiest way to do this?
I think this would work. It's a very rough implementation but I think you would get the idea. I ended up using pandas for this example but I think you can equivalently do this using numpy.
def fnc(data):
data[3]=[0]*len(data)
for i in range(1, 10):
data.loc[data[0].between(i*0.1, (i+1)*0.1),3]=i*0.1
data=[(0.32,0.5), (0.23, 0.3), (0, 0.8), (0.12, 0.5),
(0.14, 0.2), (0.25, 0.45), (0.17, 0.4)]
data=pandas.DataFrame(data)
fnc(data)
y = data.iloc[:, 1].values
x = data.iloc[:, 2].values
trace1 = go.Box(
y=y,
x=x
)
data = [trace1]
layout = go.Layout(
yaxis=dict(
title='normalized moisture',
zeroline=False
),
boxmode='group'
)
fig = go.Figure(data=data, layout=layout)
plot(fig)
Here is the following plot I got.

Resources