I have this small plotting program.
But when I run it I notice the labels on the X axis are incorrect.
They go from 0 to 5000 while actually I have the interval [-1.5, 1.5]
1... How can I fix that?
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-1.5, 1.5, 5000)
y1 = np.tan(x) * np.arctan(x)
y2 = x * x
plt.plot(y1)
plt.plot(y2)
plt.show()
2... Also, if I change the linspace to call
x = np.linspace(-mt.pi/2.0 + 1/(10**6), mt.pi/2.0 - 1/(10**6), 5000)
I get an even stranger and really incorrect plot.
Something gets messed up completely.
Why? I want to plot these 2 functions in the range (-pi/2, pi/2)
How do I do this?
Try:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-1.5, 1.5, 5000)
y1 = np.tan(x) * np.arctan(x)
y2 = x * x
plt.plot(x,y1)
plt.plot(x,y2)
plt.show()
Now x axis values are is between -1.5 and 1.5.
Regarding strange plot in second case just notice that:
np.tan(-1.5)
-14.101419947171719
and:
np.tan(-mt.pi/2.0)
-1.633123935319537e+16
which is much much bigger.
Related
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
eps = 0.8
X = np.linspace(-1, 1, 100)
Y = np.linspace(-1, 1, 100)
X, Y = np.meshgrid(X, Y)
Z = np.exp(-X**2-Y**2)
data_zero_x = np.array([])
data_zero_y = np.array([])
for i in range(len(X)):
for j in range(len(Y)):
if Z[i][j] > eps:
data_zero_x = np.append(data_zero_x, X[i])
data_zero_y = np.append(data_zero_y, Y[j])
plt.scatter(data_zero_x, data_zero_y)
plt.show()
Hey there!
I would expect this code to produce circular points around the origin since this is where the function Z is above eps=0.8. Instead, I get a rectangular picture out of it. Any ideas what I'm doing wrong here? Also, if there is a better way to code something like this I am all ears.
Try this:
import matplotlib.pyplot as plt
import numpy as np
eps = 0.8
X = np.linspace(-1, 1, 100)
Y = np.linspace(-1, 1, 100)
X, Y = np.meshgrid(X, Y)
Z = np.exp(-X**2-Y**2)
mask = Z > eps
plt.scatter(X[mask], Y[mask])
plt.show()
Since you are working with a numpy array, there is no need to loop over the complete array and check your condition (> 0.8) for each element. Numpy arrays have overloaded the comparison operators such that when you compare the whole array, it implicitly loops over each element and returns another array with True and False for each element in the original array. You can then use this array as a mask to select elements from other arrays as I did in the code above.
Also, you don't need the line fig = plt.figure() when you are working with plt.scatter. You only need that you if want to work with the object oriented approach, where you create the figure and the axes explicitly and call the plot methods of the axes objects.
Let's say I want to plot two solid lines that cross each other and I want to plot line2 dashed only if it is above line 1. The lines are on the same x-grid. What is the best/simplest way to achieve this? I could split the data of line2 into two corresponding arrays before I plot, but I was wondering if there is a more direct way with some kind of conditional linestyle formatting?
Minimal Example:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0,5,0.1)
y1 = 24-5*x
y2 = x**2
plt.plot(x,y1)
plt.plot(x,y2)#dashed if y2 > y1?!
plt.show()
There were related questions for more complex scenarios, but I am looking for the easiest solution for this standard case. Is there a way to do this directly inside plt.plot()?
You could try something like this:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0,5,0.1)
y1 = 24-5*x
y2 = x**2
xs2=x[y2>y1]
xs1=x[y2<=y1]
plt.plot(x,y1)
plt.plot(xs1,y2[y2<=y1])
plt.plot(xs2,y2[y2>y1],'--')#dashed if y2 > y1?!
plt.show()
#Sameeresque solved it nicely.
This was my take:
import numpy as np
import matplotlib.pyplot as plt
def intersection(list_1, list_2):
shortest = list_1 if len(list_1) < len(list_2) else list_2
indexes = []
for i in range(len(shortest)):
if list_1[i] == list_2[i]:
indexes.append(i)
return indexes
plt.style.use("fivethirtyeight")
x = np.arange(0, 5, 0.1)
y1 = 24 - 5*x
y2 = x**2
intersection_point = intersection(y1, y2)[0] # In your case they only intersect once
plt.plot(x, y1)
x_1 = x[:intersection_point+1]
x_2 = x[intersection_point:]
y2_1 = y2[:intersection_point+1]
y2_2 = y2[intersection_point:]
plt.plot(x_1, y2_1)
plt.plot(x_2, y2_2, linestyle="dashed")
plt.show()
Same princile as #Sammeresque, but I think his solution is simpler.
I have written a code that reads in my data file and plots it and then fits it and finds the peaks however I have 6 peaks and the code is only currently fitting 2 of the peaks and isn't returning any data on them by code is as follows:
from scipy.optimize import curve_fit
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import find_peaks
data = np.genfromtxt("C:\\Users\\lenovo laptop\\practice_data_ll16ame1.dat", skip_header = 15)
x = data[: , 0]
y = data[: , 1]
plt.plot(x,y)
plt.show()
def func(x, *params):
y = np.zeros_like(x)
for i in range(0, len(params), 3):
ctr = params[i]
amp = params[i+1]
wid = params[i+2]
y = y + amp * np.exp( -((x - ctr)/wid)**2)
return y
guess = [0, 60000, 80, 1000, 60000, 80]
for i in range(12):
guess += [60+80*i, 46000, 25]
popt, pcov = curve_fit(func, x, y, p0=guess)
fit = func(x, *popt)
plt.plot(x, y)
plt.plot(x, fit , 'r-')
plt.show()
When I looked at the plot of your custom function, it was clear that the majority of points were in a more-or-less horizontal line, so the function wouldn't fit well to your peaks. Because there is no noise and the peaks are so prominent, you just need to pass the y values and a threshold to the find_peaks function.
By implementing find_peaks instead of your custom function, you get the following code:
from scipy.optimize import curve_fit
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import find_peaks
data = np.genfromtxt("C:\\Users\\lenovo laptop\\practice_data_ll16ame1.dat", skip_header = 15)
x = data[: , 0]
y = data[: , 1]
points = find_peaks(y, height = 100)
plt.plot(x, y)
for i in points[0]:
plt.scatter(x[i], y[i])
plt.show()
Find_peaks returns a tuple consisting of two things:
1. The index of the peaks ( points[0] in the code above)
2. The height of each peak (points[1])
The code yields the following plot, which I believe is what you want:
I have a dataframe (size: 1008,100). the values of cells are within 0.1 and 1. I would like to visualize it in a surface plot but i cannot really figure out what the x,y and z values are gonna be. I'd like to position the surface plot like the rows(1008) is the aligned with the x axis and the columns(100) is aligned with the y axis.
Any help is much appreciated.
thanks
The x and y you are looking for can be created with meshgrid. A good way to start is to find an example on the matplotlib gallery and make changes from there. As an example:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# create a data frame with 1008x100 values between 0.1 and 1.0
xs = np.arange(0, 1008)
ys = np.arange(0,100)
zs = np.square(xs[:, np.newaxis]) * np.square(ys[np.newaxis, :])
max_value = np.max(zs)
min_value = np.min(zs)
zs = (zs - min_value) / (max_value - min_value) * 0.9 + 0.1
data = pd.DataFrame(zs)
# create X and Y with np.meshgrid and the 2D data frame
# (reusing the scratch variable xs and ys)
xs = np.arange(data.shape[0]) # [0,1,....,1007]
ys = np.arange(data.shape[1]) # [0,1,...,99]
X, Y = np.meshgrid(xs, ys)
# create a surface plot
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, data.T)
( note: i needed to transpose the data with .T, don't know why, sometime it is needed...)
I am creating a plot with matplotlib
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 5, 0.1);
y = np.sin(x)
plt.plot(x, y)
Can I flip the plot, making the y-axis inverted and all positive values negative and vice versa?
I know I can multiply by -1 and use invert_yaxis but I wonder if there is a function for flipping it without changing the values.
Try the following function:
plt.gca().invert_yaxis()
Inverting y limits from (-1.1,1.1) to (1.1,-1.1) with plt.ylim will do the trick...
x = np.linspace(0, 2*np.pi, 63)
y = np.sin(x)
plt.plot(x, y)
plt.ylim(1.1,-1.1)
Note that (1.1,-1.1) are just 10% above and below y.max() and y.min() values, preventing the y line from touching the graph box. Note also that x =np.arange(0, 5, .1) does not cover a complete sinusoidal period, 2 pi radians... x = np.linspace(0, 2*np.pi, 63) solves this little issue with same len(x) provided by np.arange(0, 5, .1).