I'm having trouble with my script not showing a plot.
The plot must show the deflection of the beam as a function of the x-coordinate of the entire beam. I don't know if I can make the statements: "x[i]>a[v]" if x is not given...
import numpy as np #Imports NumPy
import matplotlib.pyplot as plt
def beamPlot(beamLength, loadPositions, loadForces, beamSupport):
l=beamLength #Scalar
a=loadPositions #Vector
W=loadForces #Vector
x=np.array(range(0,l))
E=200*10**9 #Constant [N/m^2]
I=0.001 #Constant [m^4]
#Makes an empty vector with the same size as x
y=np.empty_like(x)
for i in range(np.size(x)): #Continues as long as the vector x
for v in range(np.size(a)):
if a[v]==[ ] and W[v]==[ ]:
return np.zeros(np.size(x))
elif beamSupport=="both" and x[i]<a[v]:
y[i]=np.sum(((W[v]*(l-a[v])*x[i])/(6*E*I*l))*(l**2-x[i]**2-(l-a[v])**2))
elif beamSupport=="both" and x[i]>=a[v]:
y[i]=np.sum(W[v]*a[v]*(l-x[i])/(6*E*I*l)*(l**2-(l-x[i])**2-a[v]**2))
elif beamSupport=="cantilever" and x[i]<a[v]:
y[i]=np.sum((W[v]*x[i]**2)/(6*E*I)*(3*a[v]-x[i]))
elif beamSupport=="cantilever" and x[i]>=a[v]:
y[i]=np.sum((W[v]*a[v]**2)/(6*E*I)*(3*x[i]-a[v]))
deflection=y
plt.ylim([0,10000])
plt.xlim([0,l])
plt.title("Beam deflection")
plt.plot(x, deflection)
plt.show()
Your array x is created with a list of integers from range(0,l), which means that the elements in the array are of type int. You create the y array using np.epty_like() which means that it also has elements of type int. Unless you are using huge values for the loads, the float values created by your calculations get rounded to 0 when converted to int, so the plot is a flat line at y=0.
You can fix this by specifying that y should contain float values when it is created by adding dtype=float to:
y=np.empty_like(x, dtype=float)
You should also remove the plt.ylim(0,10000) and instead let matplotlib autoscale your y-axis, since the displacements are probably not going to be this large for any reasonable values of loads (given your stiffness)
Related
I am a medical physics student trying to simulate photon detection - I succeeded (below) but I want to make it better by speeding it up: it currently takes 50 seconds to run and I want it to run in some fraction of that time. I assume someone more knowledgeable in Python could optimize it to complete within less than 10 seconds (without reducing num_photons_detected values). Thank you very much for trying out this little optimization challenge.
from random import seed
from random import random
import random
import matplotlib.pyplot as plt
import numpy as np
rows, cols = (25, 25)
num_photons_detected = [10**3, 10**4, 10**5, 10**6, 10**7]
lesionPercentAboveNoiseLevel = [1, 0.20, 0.10, 0.05]
index_range = np.array([i for i in range(rows)])
for l in range(len(lesionPercentAboveNoiseLevel)):
pixels = np.array([[0.0 for i in range(cols)] for j in range(rows)])
for k in range(len(num_photons_detected)):
random.seed(a=None, version=2)
photons_random_pixel_choice = np.array([random.choice(index_range) for z in range(rows)])
counts = 0
while num_photons_detected[k] > counts:
for i in photons_random_pixel_choice:
photons_random_pixel_choice = np.array([random.choice(index_range) for z in range(rows)]) #further ensures random pixel selection
for j in photons_random_pixel_choice:
pixels[i,j] +=1
counts +=1
plt.imshow(pixels, cmap="gray") #in the resulting images/graphs, x is on the vertical and y on the horizontal
plt.show()
I think that, aside from efficiency issues, a problem with the code is that it does not select the positions of photons truly at random. Instead, it selects rows numbers, and then for each selected row, it picks column numbers where photons will be observed in that row. As a result, if a row number is not selected, there will be no photons in that row at all, and if the same row is selected several times, there will be many photons in it. This is visible in the produced plots which have a clear pattern of lighter and darker rows:
Assuming that this is unintended and that each pixel should have equal chances of being selected, here is a function generating an array of a given size, with a given number of randomly selected pixels:
import numpy as np
def generate_photons(rows, cols, num_photons):
rng = np.random.default_rng()
indices = rng.choice(rows*cols, num_photons)
np.add.at(pix:=np.zeros(rows*cols), indices, 1)
return pix.reshape(rows, cols)
You can use it to produce images with specified parameters. E.g.:
import matplotlib.pyplot as plt
pixels = generate_photons(rows=25, cols=25, num_photons=10**4)
plt.imshow(pixels, cmap="gray")
plt.show()
gives:
photons_random_pixel_choice = np.array([random.choice(index_range) for z in range(rows)])
It seems like the goal here is:
Use a pre-made sequence of integers, 0 to 24 inclusive, to select one of those values.
Repeat that process 25 times in a list comprehension, to get a Python list of 25 random values in that range.
Make a 1-d Numpy array from those results.
This is very much missing the point of using Numpy. If we want integers in a range, then we can directly ask for those. But more importantly, we should let Numpy do the looping as much as possible when using Numpy data structures. This is where it pays to read the documentation:
size: int or tuple of ints, optional
Output shape. If the given shape is, e.g., (m, n, k), then m * n * k samples are drawn. Default is None, in which case a single value is returned.
So, just make it directly: photons_random_pixel_choice = random.integers(rows, size=(rows,)).
I wonder how to best solve the following problem in my script: "ValueError: x and y must have same first dimension, but have shapes (1531,) and (1532,)".
What is the problem here? The problem is that the x and y axis of the plot don't share the exact same number of values (input) to plot. The result is the error message above.
Let us look at the code first:
# Initialize
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
from matplotlib.pyplot import cm
# Numpy.loadtxt – Loads data from a textfile.
# Scipy.signal.welch – Creation of the power-spectrum via welch method. f, Welch creates the ideal frequencies (f, Welch = Power Spectrum or Power Spectral Density)
Subjects = ["Subject1" "Subject2"]
for Subject in Subjects:
Txt = np.loadtxt("/datadir.../{0}/filename...{0}.txt".format(Subject), comments="#", delimiter=None,
converters=None, skiprows=0, usecols=0, unpack=False, ndmin=0, encoding=None, max_rows=None, like=None)
f, Welch = signal.welch(Txt, fs=1.0, window="hann", nperseg=None, noverlap=None, nfft=3062, detrend="constant", return_onesided=True, scaling="density", axis=-1, average="mean")
BypassZero1 = f[f > 0.00000000000001] # Avoids "RuntimeWarning: divide by zero encountered in log"
BypassZero2 = Welch[Welch > 0.00000000000001]
Log_f = np.log(BypassZero1, out=BypassZero1, where=BypassZero1 > 0)
Log_Welch = np.log(BypassZero2, out=BypassZero2, where=BypassZero2 > 0)
plt.plot(Log_f, Log_Welch)
The code lines "BypassZero1" and "BypassZero2" tell Python to only use values above 0.00000000000001 for both "f" and "Welch". Otherwise the problem "RuntimeWarning: divide by zero encountered in log" would occur in the following step where I apply the logarithm for both axes (Log_f and Log_Welch).
This is where the problem occurs for the last plt.plot line of the code. It seems that a different number of numeric values are "left over" for "f" and "Welch" after the previous step of using the Welch method and applying the logarithm for both axes.
I wonder if there is a possibility to deal with the 0.xxx values provided in the .txt file. Currently, only values above 0.00000000000001 for both f and Welch are used. This will lead to the different number of values for x and y, hence resulting in the impossibility of plotting the data.
What could be a solution for this problem?
As you pointed out, the error message indicates that your two arrays are of different length. This is because the mask of the second array should be the same as the mask of the first. Therefore, replacing BypassZero2 = Welch[Welch > 0.00000000000001] with BypassZero2 = Welch[f > 0.00000000000001] should fix the issue.
Basically, x and y coordinates we are plotting must be of same length, so that we can make sure it plots one on one.
Thus, ensure their lengths are equal.
hi trying to plot the graph of the results from a while loop but keeps returning an empty graph and saying there is a value error
#create function f(n)
def f(n):
if (n % 2)==0:
return n/2
else:
return (3*n+1)/2
#loop funtion
q=63
while q != 1:
q=f(q)
#plot the function
import numpy as np
import matplotlib.pyplot as plt
i=np.linspace(0,10,3)
plt.plot(q,i)
plt.show()
It might be helpful to properly indent the code as it's is easier to interpret :)
The reason you got value error was because the dimensions of your x and y values are dissimilar. While for x you were passing a variable of size 1, for y you are passing an array of size 3. Furthermore, when using matplotlib's plot function, it's advised to specify the attributes of the plot function which determine the kind of plot you want (otherwise it can output an empty plot). I have inputted example values in the revised code below.
Hope this helps in achieving your main goal of plotting the function!
import numpy as np
import matplotlib.pyplot as plt
def f(n):
if (n % 2)==0:
return n/2
else:
return (3*n+1)/2
#loop function
q=63
while (q != 1):
q=f(q)
#plot the function
i=np.linspace(0,10,3)
#Here i is an array of type float of size 3, so you need to pick one of the
#values in i to plot with the value of q(which is a float variable of size 1)
plt.plot(q, i[2], color='green', marker='o')
plt.show()
I was plotting a scatter plot to show null values in dataframe. As you can see the plt.scatter() function is not expressive enough. Relation between list(range(0,1200)) and 'a' is not clear unless you see the previous lines. Can the plt.scatter(x,y) be written in a more explicit way where it could be easily understood how x and y is related. Like if somebody only see the plt.scatter(x,y) , they would understand what it is about.
a = []
for i in range(0,1200):
feature_with_na = [feature for feature in df.columns if df[feature].isnull().sum()>i]
a.append(len(feature_with_na))
plt.scatter(list(range(0,1200)), a)
On your x axis you have the number, then on the y-axis you want to plot the number of columns in your DataFrame that have more than that number of null values.
Instead of your loop you can count the number of null values within each column and use numpy.broadcasting, ([:, None]), to compare with an array of your numbers. This allows you to specify an xarr of the numbers, then you use that same array in the comparison.
Sample Data
import pandas as pd
import numpy as np
import matplotlib.pyplot as plot
df = pd.DataFrame(np.random.choice([1,2,3,4,5,np.NaN], (100,10)))
Code
# Range of 'x' values to consider
xarr = np.arange(0, 100)
plt.scatter(xarr, (df.isnull().sum().to_numpy()>xarr[:, None]).sum(axis=1))
ALollz answer is good, but here's a less numpy-heavy alternative if that's your thing:
feature_null_counts = df.isnull().sum()
n_nulls = list(range(100))
features_with_n_nulls = [sum(feature_null_counts > n) for n in n_nulls]
plt.scatter(n_nulls, features_with_n_nulls)
I'm trying to do something that I think should be pretty straight forward but I can't seem to get it to work.
I'm trying to plot 16 byte values measured over time to see how they change. I'm trying to use a scatter plot to do this with:
x axis being the measurement index
y axis being the index of the byte
and the color indicating the value of the byte.
I have the data stored in a numpy array where data[2][14] would give me the value of the 14th byte in the 2nd measurement.
Every time I try to plot this, I'm getting either:
ValueError: x and y must be the same size
IndexError: index 10 is out of bounds for axis 0 with size 10
Here is the sample test I'm using:
import numpy
import numpy.random as nprnd
import matplotlib.pyplot as plt
#generate random measurements
# 10 measurements of 16 byte values
x = numpy.arange(10)
y = numpy.arange(16)
test_data = nprnd.randint(low=0,high=65535, size=(10, 16))
#scatter plot the measurements with
# x - measurement index (0-9 in this case)
# y - byte value index (0-15 in this case)
# c = test_data[x,y]
plt.scatter(x,y,c=test_data[x][y])
plt.show()
I'm sure it is something stupid I'm doing wrong but I can't seem to figure out what.
Thanks for the help.
Try using a meshgrid to define your point locations, and don't forget to index into your NumPy array properly (with [x,y] rather than [x][y]):
x, y = numpy.meshgrid(x,y)
plt.scatter(x,y,c=test_data[x,y])
plt.show()