I cannot plot errors what I exactly want - python

I want to plot with error bars in both directions. My error values are standard error. So I want the error bars to be according to the value they belong to. Here's my code:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
column_names = ["gplx", "gplxerror", "hplx", "hplxerror"]
data=pd.read_csv("hw4.csv", names=column_names)
x=data.gplx.to_list()
xerr=data.gplxerror.to_list()
y=data.hplx.to_list()
yerr=data.hplxerror.to_list()
xx = [1/(i/1000) for i in x]
yy = [1/(j/1000) for j in y]
plt.errorbar(xx, yy, xerr, yerr, fmt='o',
ecolor='pink', color='blue')
plt.xlabel('Gaia Distance(in pc)')
plt.ylabel('Hipparcos Distance (in pc)')
plt.savefig('filename.png', dpi=600)
And this is the plot that I get:
But the error bars are too big. How can I make them smaller?

I used (error/100 * value) to get error as percentage of each value. It worked well. Check the following code:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
column_names = ["gplx", "gplxerror", "hplx","hplxerror"]
data=pd.read_csv("hw42.csv", names=column_names)
x=data.gplx.to_list()
xerr=data.gplxerror.to_list()
y=data.hplx.to_list()
yerr=data.hplxerror.to_list()
xx = [1/(i/1000) for i in x]
yy = [1/(j/1000) for j in y]
xxerr = [(i/100) for i in xerr]
yyerr = [(j/100) for j in yerr]
xe= [a * b for a, b in zip(xx, xxerr)]
ye= [a * b for a, b in zip(yy, yyerr)]
plt.errorbar(xx, yy, xe, ye,fmt='.', alpha=1, ecolor='black',elinewidth=0.5, markersize=4)
plt.xlabel('Gaia Distance(in pc)')
plt.ylabel('Hipparcos Distance (in pc)')
plt.savefig('filename.png', dpi=600)

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)

how to rotate a seaborn lineplot

How can I rotate a seaborn.lineplot so that the result will be as a function of y and not a function of x.
For example, this code:
import pandas as pd
import seaborn as sns
df = pd.DataFrame([[0,1],[0,2],[0,1.5],[1,1],[1,5]], columns=['group','val'])
sns.lineplot(x='group',y='val',data=df)
Create this figure:
But is there a way to rotate the figure in 90° ? so that in the X we will have "val" and in Y we will have "group" and the std will go from left to right and not from bottom to up.
Thanks
EDIT: I've opened a ticket in seaborn to ask for this feature: https://github.com/mwaskom/seaborn/issues/1661
Per the seaborn docs on lineplot, the dataframe passed to data must be
Tidy (“long-form”) dataframe where each column is a variable and each row is an observation.
Which seems to imply there is no way to force the axes to switch, even by manipulating the data. If there is a way to do that I haven't found it - I'm sure there is a more elegant way to do this, but one way you could go about it is to do it by hand so to speak. Something like this would do the trick
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
df = pd.DataFrame([[0,1],[0,2],[0,1.5],[1,1],[1,5]], columns=['group','val'])
group = df['group'].tolist()
val = df['val'].tolist()
yl = list()
yu = list()
avg = list()
ii = 0
while ii < len(group): #Loop through all the groups
g = group[ii]
y0 = val[ii]
y1 = val[ii]
s = 0
jj = ii
while (jj < len(group) and group[jj] == g):
s += val[jj]
#This takes the min and max, but could easily take the standard deviation
if val[jj] > y1:
y1 = val[jj]
if val[jj] < y0:
y0 = val[jj]
jj += 1
avg.append(s/(jj - ii))
ii = jj
yl.append(y0)
yu.append(y1)
x = np.linspace(min(group), max(group), len(yl))
plt.ylabel(df.columns[0])
plt.xlabel(df.columns[1])
plt.plot(avg, x, color="#5a9edd", linestyle="-", linewidth=1.5)
plt.fill_betweenx(x, yl, yu, alpha=0.3)
This will give you the following plot:
For brevity this uses the minimum and maximum from each group to give the error band, but that can be easily changed to standard error or standard deviation as needed.
Consider what you'd do if not using seaborn. You would calculate the mean and standard deviation and plot those as a function of the group. Now it is quite straight forward to exchange x and y for a plot(x,y): plot(y,x). For the filled region, you can use fill_betweenx instead of fill_between.
Below the two cases for comparisson.
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame([[0,1],[0,2],[0,1.5],[1,1],[1,5]], columns=['group','val'])
mean = df.groupby("group").mean()
std = df.groupby("group").std()
fig, (ax, ax2) = plt.subplots(ncols=2)
ax.plot(mean.index, mean["val"].values)
ax.fill_between(mean.index, (mean-std)["val"].values, (mean+std)["val"].values, alpha=.5)
ax.set(xlabel="group", ylabel="val")
ax2.plot(mean["val"].values, mean.index)
ax2.fill_betweenx(mean.index, (mean-std)["val"].values, (mean+std)["val"].values, alpha=.5)
ax2.set(ylabel="group", xlabel="val")
fig.tight_layout()
plt.show()

Python plotting lines parallel to y axis from array

I have an array containing 5 different numbers:
array([2.40064633, 4.10132553, 8.59968518, 2.40290345, 1.39988773]
and I want to plot the lines on the x axis (parallel to the y axis) equal to each of these numbers i.e.
x = 2.4006463
x = 4.10132553 so on and so forth for all of the numbers in the array.
I tried using plot(x = array[...]) but to no solution.
Is there a clean way of doing this using numpy or mathlab?
This will work:
import matplotlib.pyplot as plt
b =([2.40064633, 4.10132553, 8.59968518, 2.40290345, 1.39988773])
for l in b:
plt.axvline(l)
plt.show()
or is it an numpy array then:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(1,4)
for l in x:
plt.axvline(l)
plt.show()
here is my take. quite the similar as Rahul's only with the lines harshed.
import matplotlib.pyplot as plt
import numpy as np
xcoords = np.array([2.40064633, 4.10132553, 8.59968518, 2.40290345, 1.39988773])
for xc in xcoords:
plt.axvline(x=xc, color='k', linestyle='--')

Plotting a 3D quiver plot and ode

I am trying to do a 3D quiver plot and combining it with odeint to solve a linearized equation. Basically, I want something similar to this but in 3D. The particular issue I am having is that near the end of the code, when I am doing the ax.quiver() plot, I keep getting the error that "val must be a float or nonzero sequence of floats", and I am unsure how to resolve it.
from scipy.integrate import odeint
from numpy import *
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig = plt.figure()
ax =fig.add_subplot(1, 1, 1, projection='3d')
ax.set_xlabel('x')
ax.set_ylabel('u')
ax.set_zlabel('u1')
def testplot(X, t=0,c=0.2):
x = X[0]
u = X[1]
u1=X[2]
dxdt =x**2*(-1+x+u)*(1-x+(-1+c)*u**2)
du1dt =c**2*u*(2+x*(-4+2.25*x)+(-4 + 4*x)*u**2 + 2*u**4 + x**2*u*u1)
dudt=u1*dxdt
return [dxdt, dudt,du1dt]
X0 = [0.01,0.995,-0.01]#initial values
t = linspace(0, 50, 250)
c=[0.2,0.5,1,2]#changing parameter
for m in c:
sol = odeint(testplot,X0,t,mxstep=5000000,args=(m,))#solve ode
ax.plot(sol[:,0],sol[:,1],sol[:,2],lw=1.5,label=r'$c=%.1f$'%m)
x = linspace(-3,3,15)
y = linspace(-4,4,15)
z= linspace(-2,2,15)
x,y,z = meshgrid(x,y,z) #create grid
X,Y,Z = testplot([x,y,z])
M = sqrt(X**2+Y**2+Z**2)#magnitude
M[M==0]=1.
X,Y,Z = X/M, Y/M, Z/M
ax.quiver(x,y,z,X,Y,Z,M,cmap=plt.cm.jet)
ax.minorticks_on()
ax.legend(handletextpad=0,loc='upper left')
setp(ax.get_legend().get_texts(),fontsize=12)
fig.savefig("testplot.svg",bbox_inches="tight",\
pad_inches=.15)
Looks like you have an extra argument in ax.quiver(). From what I can tell, it looks like "M" is the extra argument. Taking that out, your quiver call looks like:
ax.quiver(x,y,z,X,Y,Z,cmap=plt.cm.jet)
The resulting image looks like:

Create heatmap using pandas TimeSeries

I need to create MatplotLib heatmap (pcolormesh) using Pandas DataFrame TimeSeries column (df_all.ts) as my X-axis.
How to convert Pandas TimeSeries column to something which can be used as X-axis in np.meshgrid(x, y) function to create heatmap? The workaround is to create Matplotlib drange using same parameters as in pandas column, but is there a simple way?
x = pd.date_range(df_all.ts.min(),df_all.ts.max(),freq='H')
xt = mdates.drange(df_all.ts.min(), df_all.ts.max(), dt.timedelta(hours=1))
y = arange(ylen)
X,Y = np.meshgrid(xt, y)
I do not know what you mean by heat map for a time series, but for a dataframe you may do as below:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from itertools import product
from string import ascii_uppercase
from matplotlib import patheffects
m, n = 4, 7 # 4 rows, 7 columns
df = pd.DataFrame(np.random.randn(m, n),
columns=list(ascii_uppercase[:n]),
index=list(ascii_uppercase[-m:]))
ax = plt.imshow(df, interpolation='nearest', cmap='Oranges').axes
_ = ax.set_xticks(np.linspace(0, n-1, n))
_ = ax.set_xticklabels(df.columns)
_ = ax.set_yticks(np.linspace(0, m-1, m))
_ = ax.set_yticklabels(df.index)
ax.grid('off')
ax.xaxis.tick_top()
optionally, to print actual values in the middle of each square, with some shadows for readability, you may do:
path_effects = [patheffects.withSimplePatchShadow(shadow_rgbFace=(1,1,1))]
for i, j in product(range(m), range(n)):
_ = ax.text(j, i, '{0:.2f}'.format(df.iloc[i, j]),
size='medium', ha='center', va='center',
path_effects=path_effects)

Categories