I am beginner, and have a question related to plotting in Python - python

I am new to python.
I wanted to know the syntax for a problem
Suppose I want to plot a quantity x = (constant with a fixed given value) * ln (1+z) versus z (which varies from c to d)
How do I define the variables x and z, how do I input an 'ln' function
I have imported numpy, scipy and matplotlib, but do not know how to proceed thereafter

Since you already imported numpy, here is just another answer:
import numpy as np
import matplotlib.pyplot as plt
x_coeff = 10
c = 0
d = 100
z = [i for i in range(c, d)]
x = [x_coeff * np.log(1+v) for i, v in enumerate(z)]
plt.plot(z, x)
plt.show()
It's always better to check the documents, and give out your first try:
https://docs.scipy.org/doc/numpy/reference/generated/numpy.log.html
You might also need to understand "list comprehension".
It's a beautiful and convenient way to create list in python.

For plotting a curve, you need two lists, one of them is domain on x axis and the other is range points on y-axis. first we take a constant as input,using python inbuilt input function and make sure that it is int, use math library and log function to do log as need.
import math
import matplotlib.pyplot as plt
a = int(input("enter a value for constant : "))
c,d = 0,100
xvals = list(range(c,d,1)) # start,end,step
print(xvals)
yvals = [a*math.log(1+x) for x in xvals]
print(yvals)
plt.plot(xvals,yvals)
plt.show()

Related

How can I find the x-corresponding value of a function?

I have a function (Moorse potential in case anybody cares), and I want to find the coordinates of the minimum value in X. I can very easily find the minimum value in y with min(y), but, how can I find the x value asociated witgh the minimum y coordinate?
Copy of my code:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import math
from math import e
#para niquel
D= 0.4205 #profundidad de pozo
f = 2.7540 #distancia de equilibrio
a = 1.4199 #ancho de potencial
x = np.arange(-100,100,0.01) #Distancia interatómica / eje X
y = -D + D*(1-e**(-a*(x-f)))**2
plt.xlabel('Distancia interatómica [$\AA$]')
plt.ylabel('Energía [eV]')
plt.plot(x, y, color = 'mediumturquoise')
plt.xlim(2,5.5)
plt.ylim(-0.5, 0.75)
#plt.annotate('a$_{0}$', xy = (X, min(y)) ) HERE'S WHERE I'D NEED THE X COORDINATE!!
plt.show()
Thanks in advance!
You can use an argmin to find the minimum index of y, then based on how you generated the range, you can work backwards to get the actual value. You can do something like
x[np.argmin(y)]
Note that this might not be equivalent to
np.argmin(y) * 0.01 + -100
due to floating point rounding issues.
With some algebra (or a graphing calculator...) you can resolve the Morse Potential equation in terms of y and get an accurate and quick answer.
I went ahead and did this (using symbolab, you can confirm here) given your constants, and then plotted the graphs here to confirm they looked right. There are two mathematical functions due to the two cases arising when taking the square root.
Here's some code that should compute the x value based off the y value:
import math
def getXfromY(y):
if(y <= 2.754):
return -(math.ln(-math.sqrt(y/0.4205) + 1))/1.4199
elif(y > 2.754):
return -(math.ln(math.sqrt(y/0.4205) + 1))/1.4199

Simulate the compound random variable S

Let S=X_1+X_2+...+X_N where N is a nonnegative integer-valued random variable and X_1,X_2,... are i.i.d random variables.(If N=0, we set S=0).
Simulate S in the case where N ~ Poi(100) and X_i ~ Exp(0.5). (draw histograms and use the numpy or scipy built-in functions).And check the equations E(S)=E(N)*E(X_1) and Var(S)=E(N)*Var(X_1)+E(X_1)^2 *Var(N)
I was trying to solve it, but I'm not sure yet of everything and also got stuck on the histogram part. Note: I'm new to python or more generally , new to programming.
My work:
import scipy.stats as stats
import matplotlib as plt
N = stats.poisson(100)
X = stats.expon(0.5)
arr = X.rvs(N.rvs())
S = 0
for i in arr:
S=S+i
print(arr)
print("S=",S)
expected_S = (N.mean())*(X.mean())
variance_S = (N.mean()*X.var()) + (X.mean()*X.mean()*N.var())
print("E(X)=",expected_S)
print("Var(S)=",variance_S)
Your existing code mostly looks sensible, but I'd simplify:
arr = X.rvs(N.rvs())
S = 0
for i in arr:
S=S+i
down to:
S = X.rvs(N.rvs()).sum()
To draw a histogram, you need many samples from this distribution, which is now easily accomplished via:
arr = []
for _ in range(10_000):
arr.append(X.rvs(N.rvs()).sum())
or, equivalently, using a list comprehension:
arr = [X.rvs(N.rvs()).sum() for _ in range(10_000)]
to plot these in a histogram, you need the pyplot module from Matplotlib, so your import should be:
from matplotlib.pyplot import plt
plt.hist(arr, 50)
The 50 above says to use that number of "bins" when drawing the histogram. We can also compare these to the mean and variance you calculated by assuming the distribution is well approximated by a normal:
approx = stats.norm(expected_S, np.sqrt(variance_S))
_, x, _ = plt.hist(arr, 50, density=True)
plt.plot(x, approx.pdf(x))
This works because the second value returned from matplotlib's hist method are the locations of the bins. I used density=True so I could work with probability densities, but another option could be to just multiply the densities by the number of samples to get expected counts like the previous histogram.
Running this gives me:

How do i solve this equation for m using SciPy root function and how do i write it

```
import numpy as np
K = 1.38e-23
z = 8
J = 1.8e-21
T = 1
m = 0
```
these are just constants
m = np.tanh((z*J*m)/(K*T))
this is the equation
but I need to find it each m value for each T value so I'm not sure if a nested loop would be better where I loop through T and m because I've tried and is doesn't work proper I'm just not sure what to do so any help would be great. also T is in range 1 - 1501
I am not still sure what you really need.
If you do some optimization to find some min or max, you should have a look again might you provide less information to us than needed (for example you say m=0 but that gives answer 0 for any T. Might you want to have range of m and T. It's then another story.
Without scipy if you willing to calculate just a result of a function of two parameters, m and T, you can use linspace for example to set ranges and steps.
import numpy as np
import matplotlib.pyplot as plt
def func(T, m):
z = 8
K = 1.38e-23
J = 1.8e-21
return np.tanh((z*J*m)/(K*T))
xaxis = np.linspace(1, 1501, 1500)
yaxis = np.linspace(0, 10, 10)
result = func(xaxis[:,None], yaxis[None,:])
plt.plot(result)
And you get smth as below, few curves. But I set m in range, might you need another values there. Up to you. Check and go.

Equation return different values for the same variable

I'm trying to create a chart but it looks incorrect.
For the range(0, 1000000) the chart should be starts at 0 and ends at 1 at x-axis, but it has negative values. In the begging it's OK, but after some value, it gets wrong.
I tried to manually calculate specific values and found out that there is a different result for the same value in the equation. Here is an example:
import numpy as np
import matplotlib.pyplot as plt
def graph(formula, x_range):
x = np.array(x_range)
y = eval(formula)
print(y)
plt.plot(x, y)
plt.show()
formula = '1-((2**32-1)/2**32)**(x*(x-1)/2)'
graph(formula, range(80300, 80301))
x = 80300
print(eval(formula))
There is a different result for the same value, here is the console output:
[-0.28319476]
0.5279390283223464
I have no idea why there is a different result for the same formula and the value. The correct is 0.5279390283223464.
To make your code work correctly use bigger datatype i.e (dtype="float64"), edit your code to:
x = np.array(x_range, dtype="float64")
or if you want the 2 results to match in precision add [0]
x = np.array(x_range, dtype="float64")[0]
x = np.array(x_range, dtype="float32")[0]
to understand why, read below:
if you change formula in your code to simple one for example (formula = "x + 100") you will get correct results
what does this mean?
it means that your formula which is '1-((232-1)/232)**(x*(x-1)/2)' cause an overflow in numpy "numpy built in C not python"
i tried the following code to narrow problem possibilities:
formula = '1-((2**32-1)/2**32)**(x*(x-1)/2)'
x = 80300
print(eval(formula))
x = np.array(range(80300, 80301))[0]
print(eval(formula))
output from sublime Text>>>
0.5279390283223464
RuntimeWarning: overflow encountered in long_scalars
import numpy as np
-0.28319476138546906
which support my point of view

Plot an equation with matplotlib and numpy

I want to plot an equation where the x axis represents time t and the y axis represents a variable n. Now the formula for n is n =((np.log(t)*10**6)/np.log(2)) + 1 and the maximum time on my graph is the time since big bang theory in seconds which is 4.35 x 10**17 seconds.
I tried this:
import matplotlib.pyplot as plt
import numpy as np
def graph(formula, x_range):
y = np.array(x_range)
x = eval(formula)
plt.plot(x,y)
plt.show()
graph(((np.log(x)*10**6)/np.log(2)) + 1, range(0, 4.35*10**17 ))
which doesn't seem to work. Any ideas on how I can achieve this?
There are several problems here:
The range is supposed to be defined over integers;
The number of items the range would generate is too large, you have to take huge steps;
The formula takes x as a variable, but you seem to define a np.array(x_range) in y; and more importantly
you use eval(..), but eval(..) usually a string or another object that can be parsed;
you do not give graph(..) a formula as first element: before Python calls graph(..) it first evaluates the operands.
In my opinion, the best way to achieve this is using a lambda-expression:
import matplotlib.pyplot as plt
import numpy as np
def graph(formula, x_range):
x = np.array(x_range)
#^ use x as range variable
y = formula(x)
#^ ^call the lambda expression with x
#| use y as function result
plt.plot(x,y)
plt.show()
graph(lambda x : ((np.log(x)*10**6)/np.log(2)) + 1, range(0, 435*10**15,10**12))
# ^use a lambda expression ^range over integers
# take huge steps
This generates the following image:
EDIT:
based on your comment you want time on the y-axis and the function on the x-axis, this can simply be achieved by assigning to the other variables like:
import matplotlib.pyplot as plt
import numpy as np
def graph(formula, x_range):
y = np.array(x_range)
x = formula(y)
plt.plot(x,y)
plt.show()
graph(lambda x : ((np.log(x)*10**6)/np.log(2)) + 1, range(0,435*10**15,10**12))
Note that you do not need to change the name of the variable in the lambda-expression: indeed when you call the lambda expression, the local x will simply be the y of the caller.

Categories

Resources