I am trying to plot a lognormal distribution so I can compare it with a histogram of my sample data using the code below but my plot does not look right. Is there something with my code that I am not doing correctly?
The C array has a length of 17576
import matplotlib.pyplot as plt
import numpy as np
data=np.loadtxt(F)
C=data[:,3]
x = np.ma.log(C)
avg = np.mean(x)
std = np.std(x)
dist=lognorm(std,loc=avg)
plt.plot(C,dist.pdf(C),'r')
plt.show()
It looks like your x data are not in sorted order. Try this
ind = np.argsort(C)
xx = C[ind]
yy = dist.pdf(C)[ind]
plt.plot(xx, yy, 'r')
Plot just connects all the (x,y) pairs with straight lines, so you need to make sure you trace your function from left-right (or right-left). Alternatively, you can skip the lines between the plot:
plt.plot(C, dist.pdf(C), 'ro')
Related
Have some data that I've plotted on a log-log plot and now I want to fit a straight line through these points. I have tried various methods and can't get what I'm after. Example code:
import numpy as np
import matplotlib.pyplot as plt
import random
x= np.linspace(1,100,10)
y = np.log10(x)+np.log10(np.random.uniform(0,10))
coefficients = np.polyfit(np.log10(x),np.log10(y),1)
polynomial=np.poly1d(coefficients)
y_fit = polynomial(y)
plt.plot(x,y,'o')
plt.plot(x,y_fit,'-')
plt.yscale('log')
plt.xscale('log')
This gives me a ideal 'straight' line in log log offset by a random number to which I then fit a 1d poly. The output is:
So ignoring the offset, which I can deal with, it is not quite what I require as it has basically plotted a straight line between each point and then joined them up whereas I need a 'line of best fit' through the middle of them all so I can measure the gradient of it.
What is the best way to achieve this?
One problem is
y_fit = polynomial(y)
You must plug in the x values, not y, to get y_fit.
Also, you fit log10(y) with log10(x), so to evaluate the linear interpolator, you must plug in log10(x), and the result will be the base-10 log of the y values.
Here's a modified version of your script, followed by the plot it generates.
import numpy as np
import matplotlib.pyplot as plt
import random
x = np.linspace(1,100,10)
y = np.log10(x) + np.log10(np.random.uniform(0,10))
coefficients = np.polyfit(np.log10(x), np.log10(y), 1)
polynomial = np.poly1d(coefficients)
log10_y_fit = polynomial(np.log10(x)) # <-- Changed
plt.plot(x, y, 'o-')
plt.plot(x, 10**log10_y_fit, '*-') # <-- Changed
plt.yscale('log')
plt.xscale('log')
I want to change the the look of the mean in violinplots. I am using matplotlib. I could change the color of the means with the following code:
import matplotlib.pyplot as plt
fig,(axes1,axes2,axes3) = plt.subplots(nrows=3,ncols=1,figsize=(10,20))
r=axes2.violinplot(D,showmeans=True,showmedians=True)
r['cmeans'].set_color('red')
But now I want to change the look of the mean (currently a line, like the median) to a 'small circle'.
Can someone help me with this?
The idea can be to obtain the coordinates of the mean lines and plot a scatter plot at those coordinates.
Obtaining the coordinates can
either be done by looping over the mean lines' paths,
# loop over the paths of the mean lines
xy = [[l.vertices[:,0].mean(),l.vertices[0,1]] for l in r['cmeans'].get_paths()]
xy = np.array(xy)
or by reacalculating the mean from the input data.
#alternatively get the means from the data
y = data.mean(axis=0)
x = np.arange(1,len(y)+1)
xy=np.c_[x,y]
Complete code:
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
data = np.random.normal(size=(50, 2))
fig,ax = plt.subplots()
r=ax.violinplot(data,showmeans=True)
# loop over the paths of the mean lines
xy = [[l.vertices[:,0].mean(),l.vertices[0,1]] for l in r['cmeans'].get_paths()]
xy = np.array(xy)
##alternatively get the means from the data
#y = data.mean(axis=0)
#x = np.arange(1,len(y)+1)
#xy=np.c_[x,y]
ax.scatter(xy[:,0], xy[:,1],s=121, c="crimson", marker="o", zorder=3)
# make lines invisible
r['cmeans'].set_visible(False)
plt.show()
I have a probability density function of that I can only evaluate the logarithm without running into numeric issues. I have a histogram that I would like to plot on the same canvas. However, for the histogram, I need the option log=True to have it plotted in log scale, wheras for the function, I can only have the logarithms of the values directly. How can I plot both on the same canvas?
Please look at this MWE for illustration of the problem:
import matplotlib.pyplot as plt
import random
import math
import numpy as np
sqrt2pi = math.sqrt(2*math.pi)
def gauss(l):
return [ 1/sqrt2pi * math.exp(-x*x) for x in l]
def loggauss(l):
return [ -math.log(sqrt2pi) -x*x for x in l ]
# just fill a histogram
h = [ random.gauss(0,1) for x in range(0,1000) ]
plt.hist(h,bins=21,normed=True,log=True)
# this works nicely
xvals = np.arange(-4,4,0.1)
plt.plot(xvals,gauss(xvals),"-k")
# but I would like to plot this on the same canvas:
# plt.plot(xvals,loggauss(xvals),"-r")
plt.show()
Any suggestions?
If I understand correctly, you want to plot two data sets in the same figure, on the same x-axis, but one on a log y-scale and one on a linear y-scale. You can do this using twinx:
fig, ax = plt.subplots()
ax.hist(h,bins=21,normed=True,log=True)
ax2 = ax.twinx()
ax2.plot(xvals, loggauss(xvals), '-r')
I have 2 lists tab_x (containe the values of x) and tab_z (containe the values of z) which have the same length and a value of y.
I want to plot a 3D curve which is colored by the value of z. I know it's can be plotted as a 2D plot but I want to plot a few of these plot with different values of y to compare so I need it to be 3D.
My tab_z also containe negatives values
I've found the code to color the curve by time (index) in this question but I don't know how to transforme this code to get it work in my case.
Thanks for the help.
I add my code to be more specific:
fig8 = plt.figure()
ax8 = fig8.gca(projection = '3d')
tab_y=[]
for i in range (0,len(tab_x)):
tab_y.append(y)
ax8.plot(tab_x, tab_y, tab_z)
I have this for now
I've tried this code
for i in range (0,len(tab_t)):
ax8.plot(tab_x[i:i+2], tab_y[i:i+2], tab_z[i:i+2],color=plt.cm.rainbow(255*tab_z[i]/max(tab_z)))
A total failure:
Your second attempt almost has it. The only change is that the input to the colormap cm.jet() needs to be on the range of 0 to 1. You can scale your z values to fit this range with Normalize.
import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import colors
fig = plt.figure()
ax = fig.gca(projection='3d')
N = 100
y = np.ones((N,1))
x = np.arange(1,N + 1)
z = 5*np.sin(x/5.)
cn = colors.Normalize(min(z), max(z)) # creates a Normalize object for these z values
for i in xrange(N-1):
ax.plot(x[i:i+2], y[i:i+2], z[i:i+2], color=plt.cm.jet(cn(z[i])))
plt.show()
I have a 2 lists, first with dates (datetime objects) and second with some values for these dates.
When I create a simple plot:
plt.plot_date(x=dates, y=dur, fmt='r-')
I get a very ugly image like this.
How I can smooth this line? I think about extrapolation, but have not found a simple function for this. In Scipy there are very difficult tools for this, but I don't understand what I must add to my data for extrapolation.
You can make it smooth using sp.polyfit
Code:
import scipy as sp
import numpy as np
import matplotlib.pyplot as plt
# sampledata
x = np.arange(199)
r = np.random.rand(100)
y = np.convolve(r, r)
# plot sampledata
plt.plot(x, y, color='grey')
# smoothen sampledata using a 50 degree polynomial
p = sp.polyfit(x, y, deg=50)
y_ = sp.polyval(p, x)
# plot smoothened data
plt.plot(x, y_, color='r', linewidth=2)
plt.show()