I am trying to compute the intersection points between a line and a closed curve (stored in a file)
I tried to adapt this
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
from scipy.optimize import bisect
import numpy as np
import csv
from scipy.interpolate import interp1d
from scipy.optimize import bisect
#reading curve from file
r = ...
z = ...
# vertical line
x = 1.885, 1.885
y = [-3,3]
z_ves = interp1d(r_ves, z_ves, fill_value="extrapolate")
plt.figure(num=None, figsize=(10, 6), dpi=100, facecolor='w', edgecolor='k')
plt.plot(r_ves, z_ves(r_ves))
plt.axvline(x=1.885,ymin=-3,ymax=3)
# #use interp1d to get interpolated points
y = interp1d(x, y, fill_value="extrapolate")
# stress = interp1d(strain, stress)
# #set starting points
x1 = max(x[0], r_ves[0])
x2 = min(x[-1], r_ves[-1])
max_err = .01
# #create function
f = lambda x : z_ves(x) - y(x)
#find x1 where f(x1) = 0
x1 = bisect(f, x1, x2, xtol = .001)
y1 = z_ves(x1)
#
plt.figure(num=None, figsize=(10, 6), dpi=100, facecolor='w', edgecolor='k')
plt.plot(r_ves, z_ves(r_ves))
plt.plot(x, y(x))
plt.scatter(x1, y1)
plt.show()
I get a Runtime Warning as I think the line is vertical.
RuntimeWarning: invalid value encountered in multiply
y_new = slope*(x_new - x_lo)[:, None] + y_lo
I know there are two intersections (see picture)
how do I get the intersections?
Function y should interpolate the vertical line, but you already know its equation: x=1.885. Therefore, plugging given x value into the equation of the curve should give you the equation you need to solve to get y-coordinates of the points of intersection. z_ves(1.885) should give you the desired result point of intersection.
I solved with using shapely
from shapely.geometry import LineString,Polygon
LOS1 = LineString([(1.885,-5), (1.885,3)])
VesselCoordTuple=list(zip(r_ves, z_ves))
polygonVesselBound = Polygon(VesselCoordTuple)
x1 = polygonVesselBound.intersection(LOS1)
r1 = x1.xy[0][0]
z1 = x1.xy[1][0]
r2 = x1.xy[0][1]
z2 = x1.xy[1][1]
plt.figure(1, figsize=SIZE, dpi=90) #1, figsize=(10, 4), dpi=180)
plt.plot(r_ves, z_ves)
plt.plot(x1.xy[0][0],x1.xy[1][0], color='r',linestyle=' ',marker='x',markersize=5)
plt.plot(x1.xy[0][1],x1.xy[1][1], color='r',linestyle=' ',marker='x',markersize=5)
Related
I want to plot some equation in Matplotlib. But it has different result from Wolframalpha.
This is the equation:
y = 10yt + y^2t + 20
The plot result in wolframalpha is:
But when I want to plot it in the matplotlib with these code
# Creating vectors X and Y
x = np.linspace(-2, 2, 100)
# Assuming α is 10
y = ((10*y*x)+((y**2)*x)+20)
# Create the plot
fig = plt.figure(figsize = (10, 5))
plt.plot(x, y)
The result is:
Any suggestion to modify to code so it has similar plot result as wolframalpha? Thank you
As #Him has suggested in the comments, y = ((10*y*x)+((y**2)*x)+20) won't describe a relationship, so much as make an assignment, so the fact that y appears on both sides of the equation makes this difficult.
It's not trivial to express y cleanly in terms of x, but it's relatively easy to express x in terms of y, and then graph that relationship, like so:
import numpy as np
import matplotlib.pyplot as plt
y = np.linspace(-40, 40, 2000)
x = (y-20)*(((10*y)+(y**2))**-1)
fig, ax = plt.subplots()
ax.plot(x, y, linestyle = 'None', marker = '.')
ax.set_xlim(left = -4, right = 4)
ax.grid()
ax.set_xlabel('x')
ax.set_ylabel('y')
Which produces the following result:
If you tried to plot this with a line instead of points, you'll get a big discontinuity as the asymptotic limbs try to join up
So you'd have to define the same function and evaluate it in three different ranges and plot them all so you don't get any crossovers.
import numpy as np
import matplotlib.pyplot as plt
y1 = np.linspace(-40, -10, 2000)
y2 = np.linspace(-10, 0, 2000)
y3 = np.linspace(0, 40, 2000)
x = lambda y: (y-20)*(((10*y)+(y**2))**-1)
y = np.hstack([y1, y2, y3])
fig, ax = plt.subplots()
ax.plot(x(y), y, linestyle = '-', color = 'b')
ax.set_xlim(left = -4, right = 4)
ax.grid()
ax.set_xlabel('x')
ax.set_ylabel('y')
Which produces this result, that you were after:
I have a dataset that looks similar to the one simulated in the code below. There are two sets of observations, one for those at X=0 and another for those at X>0.
import numpy as np
import seaborn as sns; sns.set()
import matplotlib.pyplot as plt
X1 = np.random.normal(0, 1, 100)
X1 = X1 - np.min(X1)
Y1 = X1 + np.random.normal(0, 1, 100)
X0 = np.zeros(100)
Y0 = np.random.normal(0, 1.2, 100) + 2
X = np.concatenate((X1, X0))
Y = np.concatenate((Y1, Y0))
sns.distplot(Y0, color="orange")
plt.show()
sns.scatterplot(X, Y, hue = (X == 0), legend=False)
plt.show()
There are two plots: a histogram with KDE and a scatterplot.
I want to take the histogram with KDE, rotate it, and orient it appropriately with respect to the scatter plot. I would also like to add a trend line for each respective set of observations.
The ideal result would look something like this:
How do you do this in python, either using seaborn or matplotlib?
This can be done by combining plt.subplots with shared y-axis to keep the scale and sns plots. For trend line you need some additional computation, but you can use np for quick fitting. Here is an example how to achieve your goal, and here is jupyter notebook to play with.
import numpy as np
import seaborn as sns; sns.set()
import matplotlib.pyplot as plt
# Prepare some data
np.random.seed(2020)
mean_Y1 = 0
std_Y1 = 1
size_Y1 = 100
X1 = np.random.normal(mean_Y1, std_Y1, size_Y1)
X1 = X1 - np.min(X1)
Y1 = X1 + np.random.normal(mean_Y1, std_Y1, size_Y1)
# this for computing trend line
Z = np.polyfit(X1, Y1, 1)
Y_ = np.poly1d(Z)(X1)
mean_Y0 = 2
std_Y0 = 1.2
size_Y0 = 100
X0 = np.zeros(100)
Y0 = np.random.normal(mean_Y0, std_Y0, size_Y0)
X = np.concatenate((X1, X0))
Y = np.concatenate((Y1, Y0))
# Now time for plotting
fig, axs = plt.subplots(1, 2,
sharey=True,
figsize=(10, 5),
gridspec_kw={'width_ratios': (1, 2)}
)
# control space between plots
fig.subplots_adjust(wspace=0.1)
# set the ticks for y-axis:
axs[0].yaxis.set_tick_params(left=False, labelleft=False, labelright=True)
# if you wish you can rotate xticks on the histogram with:
axs[0].xaxis.set_tick_params(rotation=90)
# plot histogram
dist = sns.distplot(Y0, color="orange", vertical=True, ax=axs[0])
# now we need to get the coordinate of the peak, we need this for mean line
line_data = dist.get_lines()[0].get_data()
max_Y0 = np.max(line_data[0])
# plotting the mean line
axs[0].plot([0, max_Y0], [mean_Y0, mean_Y0], '--', c='orange')
# inverting xaxis
axs[0].invert_xaxis()
# Plotting scatterpot
sns.scatterplot(X, Y, hue = (X == 0), legend=False, ax=axs[1])
# Plotting trend line
sns.lineplot(X1, Y_, ax=axs[1])
# Plotting mean again
axs[1].plot([0, max(X1)], [mean_Y0, mean_Y0], '--', c='orange')
plt.show()
Out:
I wanted to perform arithmetic operations on dates so i converted these dates
idx_1 = 2017-06-07 00:00:00
idx_2 = 2017-07-27 00:00:00
to floats using,
x1 = time.mktime(idx_1.timetuple()) # returns float of dates
>>> 1496773800.0
x2 = time.mktime(idx_2.timetuple())
>>> 1501093800.0
y1 = 155.98
y2 = 147.07
Am using the following code to plot:
import datetime as dt
import time
import numpy as np
import matplotlib.pyplot as plt
x = [x1, x2]
y = [y1, y2]
Difference = x2 - x1 #this helps to end the plotted line at specific point
coefficients = np.polyfit(x, y, 1)
polynomial = np.poly1d(coefficients)
# the np.linspace lets you set number of data points, line length.
x_axis = np.linspace(x1, x2 + Difference, 3) # linspace(start, end, num)
y_axis = polynomial(x_axis)
plt.plot(x_axis, y_axis)
plt.plot(x[0], y[0], 'go')
plt.plot(x[1], y[1], 'go')
plt.show()
Which plots:
How to make matplotlib to plot the actual dates on x axis instead of floats?
Any kind of Help is Greatly Appreciated.
Starting with datetime objects you may use matplotlib's date2num and num2date functions to convert to and from numerical values. The advantage is that the numerical data is then understood by matplotlib.dates locators and formatters.
import datetime
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates
idx_1 = datetime.datetime(2017,06,07,0,0,0)
idx_2 = datetime.datetime(2017,07,27,0,0,0)
idx = [idx_1, idx_2]
y1 = 155.98
y2 = 147.07
x = matplotlib.dates.date2num(idx)
y = [y1, y2]
Difference = x[1] - x[0] #this helps to end the plotted line at specific point
coefficients = np.polyfit(x, y, 1)
polynomial = np.poly1d(coefficients)
# the np.linspace lets you set number of data points, line length.
x_axis = np.linspace(x[0], x[1] + Difference, 3) # linspace(start, end, num)
y_axis = polynomial(x_axis)
plt.plot(x_axis, y_axis)
plt.plot(x[0], y[0], 'go')
plt.plot(x[1], y[1], 'go')
loc= matplotlib.dates.AutoDateLocator()
plt.gca().xaxis.set_major_locator(loc)
plt.gca().xaxis.set_major_formatter(matplotlib.dates.AutoDateFormatter(loc))
plt.gcf().autofmt_xdate()
plt.show()
The following formula is used to classify points from a 2-dimensional space:
f(x1,x2) = np.sign(x1^2+x2^2-.6)
All points are in space X = [-1,1] x [-1,1] with a uniform probability of picking each x.
Now I would like to visualize the circle that equals:
0 = x1^2+x2^2-.6
The values of x1 should be on the x-axis and values of x2 on the y-axis.
It must be possible but I have difficulty transforming the equation to a plot.
You can use a contour plot, as follows (based on the examples at http://matplotlib.org/examples/pylab_examples/contour_demo.html):
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-1.0, 1.0, 100)
y = np.linspace(-1.0, 1.0, 100)
X, Y = np.meshgrid(x,y)
F = X**2 + Y**2 - 0.6
plt.contour(X,Y,F,[0])
plt.show()
This yields the following graph
Lastly, some general statements:
x^2 does not mean what you think it does in python, you have to use x**2.
x1 and x2 are terribly misleading (to me), especially if you state that x2 has to be on the y-axis.
(Thanks to Dux) You can add plt.gca().set_aspect('equal') to make the figure actually look circular, by making the axis equal.
The solution of #BasJansen certainly gets you there, it's either very inefficient (if you use many grid points) or inaccurate (if you use only few grid points).
You can easily draw the circle directly. Given 0 = x1**2 + x**2 - 0.6 it follows that x2 = sqrt(0.6 - x1**2) (as Dux stated).
But what you really want to do is to transform your cartesian coordinates to polar ones.
x1 = r*cos(theta)
x2 = r*sin(theta)
if you use these substitions in the circle equation you will see that r=sqrt(0.6).
So now you can use that for your plot:
import numpy as np
import matplotlib.pyplot as plt
# theta goes from 0 to 2pi
theta = np.linspace(0, 2*np.pi, 100)
# the radius of the circle
r = np.sqrt(0.6)
# compute x1 and x2
x1 = r*np.cos(theta)
x2 = r*np.sin(theta)
# create the figure
fig, ax = plt.subplots(1)
ax.plot(x1, x2)
ax.set_aspect(1)
plt.show()
Result:
How about drawing x-values and calculating the corresponding y-values?
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-1, 1, 100, endpoint=True)
y = np.sqrt(-x**2. + 0.6)
plt.plot(x, y)
plt.plot(x, -y)
produces
This can obviously be made much nicer, but this is only for demonstration...
# x**2 + y**2 = r**2
r = 6
x = np.linspace(-r,r,1000)
y = np.sqrt(-x**2+r**2)
plt.plot(x, y,'b')
plt.plot(x,-y,'b')
plt.gca().set_aspect('equal')
plt.show()
produces:
Plotting a circle using complex numbers
The idea: multiplying a point by complex exponential () rotates the point on a circle
import numpy as np
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.pyplot as plt
num_pts=20 # number of points on the circle
ps = np.arange(num_pts+1)
# j = np.sqrt(-1)
pts = np.exp(2j*np.pi/num_pts *(ps))
fig, ax = plt.subplots(1)
ax.plot(pts.real, pts.imag , '-o')
ax.set_aspect(1)
plt.show()
I want to plot a donut and my script is
import numpy as np
import matplotlib.pyplot as plt
pi,sin,cos = np.pi,np.sin,np.cos
r1 = 1
r2 = 2
theta = np.linspace(0,2*pi,36)
x1 = r1*cos(theta)
y1 = r1*sin(theta)
x2 = r2*cos(theta)
y2 = r2*sin(theta)
How to get a donut with red filled area ?
You can traverse the boundaries of the area in closed curve, and use fill method to fill the area inside this closed area:
import numpy as np
import matplotlib.pyplot as plt
n, radii = 50, [.7, .95]
theta = np.linspace(0, 2*np.pi, n, endpoint=True)
xs = np.outer(radii, np.cos(theta))
ys = np.outer(radii, np.sin(theta))
# in order to have a closed area, the circles
# should be traversed in opposite directions
xs[1,:] = xs[1,::-1]
ys[1,:] = ys[1,::-1]
ax = plt.subplot(111, aspect='equal')
ax.fill(np.ravel(xs), np.ravel(ys), edgecolor='#348ABD')
plt.show()
This can easily be applied to any shape, for example, a pentagon inside or outside of a circle:
You can do this by plotting the top and bottom halves separately:
import numpy as np
import matplotlib.pyplot as plt
inner = 5.
outer = 10.
x = np.linspace(-outer, outer, 1000, endpoint=True)
yO = outer*np.sin(np.arccos(x/outer)) # x-axis values -> outer circle
yI = inner*np.sin(np.arccos(x/inner)) # x-axis values -> inner circle (with nan's beyond circle)
yI[np.isnan(yI)] = 0. # yI now looks like a boulder hat, meeting yO at the outer points
ax = plt.subplot(111)
ax.fill_between(x, yI, yO, color="red")
ax.fill_between(x, -yO, -yI, color="red")
plt.show()
Or you can use polar coordinates, though whether this is beneficial depends on the broader context:
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(0., 2.*np.pi, 80, endpoint=True)
ax = plt.subplot(111, polar=True)
ax.fill_between(theta, 5., 10., color="red")
plt.show()
It's a bit of a hack but the following works:
import numpy as np
import matplotlib.pyplot as plt
pi,sin,cos = np.pi,np.sin,np.cos
r1 = 1
r2 = 2
theta = np.linspace(0,2*pi,36)
x1 = r1*cos(theta)
y1 = r1*sin(theta)
x2 = r2*cos(theta)
y2 = r2*sin(theta)
fig, ax = plt.subplots()
ax.fill_between(x2, -y2, y2, color='red')
ax.fill_between(x1, y1, -y1, color='white')
plt.show()
It plots the whole area of your donut in red and then plots the central "hole" in white.
The answer given by tom10 is ten ;)
But if you want to define the circle (donut) origin is simple, just add the position x,y in the x, yI, yO and -yO and -yI, like this:
...
pos = [4,2]
ax.fill_between(x+pos[0], yI+pos[1], yO+pos[1], color=color)
ax.fill_between(x+pos[0], -yO+pos[1], -yI+pos[1], color=color)
...
REF Example: https://pastebin.com/8Ew4Vthb