I am trying to make a fill between two datasets of different length using Matplotlib in Python.
Datasets are as follows
x1 = [0.00137221, 0.01372213, 0.02607204, 0.03910806, 0.05351629,
0.07066895, 0.08713551, 0.10634648, 0.12761578, 0.14888508,
0.17221269, 0.19691252, 0.2271012 , 0.25797599, 0.28747856,
0.31766724, 0.34373928, 0.36569468, 0.38559177]
y1 = [1.03307393, 1.04661479, 1.05875486, 1.07182879, 1.08723735,
1.10544747, 1.11945525, 1.13299611, 1.14607004, 1.15540856,
1.15680934, 1.15680934, 1.15354086, 1.14513619, 1.13346303,
1.12085603, 1.10964981, 1.09891051, 1.08677043]
x2 = [0.00960549, 0.03773585, 0.06929674, 0.11595197, 0.15574614,
0.18113208, 0.20994854, 0.2380789 , 0.27101201]
y2 = [1.00645914, 1.02233463, 1.03821012, 1.05315175, 1.05688716,
1.05595331, 1.04894942, 1.04054475, 1.01579767]
I followed the procedure suggested here:
fill between two lines lacking common x values
xfill = np.linspace(0,0.4,10)
y1fill = np.interp(xfill, x1,y1)
y2fill = np.interp(xfill, x2,y2)
plt.plot(x1,y1)
plt.plot(x2,y2)
plt.fill_between(xfill, y1fill,y2fill,color = "lightgray")
When I apply the suggested code, I am getting wrong fill_between:
Using pgfplots in LaTeX I am getting somewhat that I want
You can add an extra start/end point with the terminal values of the outside line:
x_start = min(x1[0], x2[0])
x_end = max(x1[-1], x2[-1])
y_start = y1[0] if x_start == x1[0] else y2[0]
y_end = y1[-1] if x_end == x1[-1] else y2[-1]
xfill = np.linspace(x_start, x_end, 100)
y1fill = np.interp(xfill, np.r_[x_start, x1, x_end], np.r_[y_start, y1, y_end])
y2fill = np.interp(xfill, np.r_[x_start, x2, x_end], np.r_[y_start, y2, y_end])
plt.plot(x1,y1)
plt.plot(x2,y2)
plt.fill_between(xfill, y1fill, y2fill, color="lightgray")
Output:
As a function:
def fill_between_ends(x1, x2, y1, y2, **kwargs):
x_start = min(x1[0], x2[0])
x_end = max(x1[-1], x2[-1])
y_start = y1[0] if x_start == x1[0] else y2[0]
y_end = y1[-1] if x_end == x1[-1] else y2[-1]
xfill = np.linspace(x_start, x_end,100)
y1fill = np.interp(xfill, np.r_[x_start, x1, x_end], np.r_[y_start, y1, y_end])
y2fill = np.interp(xfill, np.r_[x_start, x2, x_end], np.r_[y_start, y2, y_end])
plt.fill_between(xfill, y1fill, y2fill, **kwargs)
plt.plot(x1,y1)
plt.plot(x2,y2)
fill_between_ends(x1, x2, y1, y2, color="lightgray")
Related
I have set-up a polynomial equation with 4 factors inside, that I want to solve using scipy.optimize.minimize.
However, I might want to solve only a certain set of the 4 factors at any one time. For example,
-> given Y(x1, x2, x3, x4) = Function(x1, x2, x3, x4) = 0.0 (to get the roots)
Sometimes, I want to get all [x1, x2, x3, x4], but sometimes, I want to just solve-for/calibrate [x2, x3] etc, or any iteration of the set [x1, x2, x3, x4].
Is there a way to do this elegantly?
def fit_beta(fwd_ = 0.01, shift_ = 0.0, time_ = 1.0, beta = 1.0, k_ = np.array([]), vols_ = np.array([]), params = np.array([1, 1, 1, 1])):
def calib_(x):
curve_ = []
for strike_ in k_:
vol_ = vol_log(strike_, fwd_, time_, x[0], x[1], x[2], x[3])
curve_.append(vol_)
return np.sum((np.array(curve_) - np.array(vols_))**2)
x0 = np.array([0.01, 0.5, 0.00, 0.10]) # initial guess
bounds = [(0.0001, None), (0.0001, 0.9999), (-0.9999, 0.9999), (0.0001, None)]
res = minimize(calib_, x0, method='L-BFGS-B', bounds=bounds)
x1_, x2_, x3_, x4_ = res.x
return [x1_, x2_, x3_, x4_]
I have this coupled mass system code that runs good and prints results. But I have trouble plotting the graphs for positions and velocities since I am unable to extract values from arrays. I would appreciate some help!
import numpy as np
%matplotlib inline
import matplotlib.pyplot as pl
from scipy.integrate import odeint
def vectorfield(w, t, p):
x1, y1, x2, y2 = w
m1, m2, k1, k2, kc = p
# Create f = (x1',y1',x2',y2'):
f = [y1, (-x1*(k1+kc) + x2*kc)/m1, y2, (x1*kc - x2*(k2+kc)) / m2]
return f
# Parameter values
# Masses:
m1 = 1.0
m2 = 1.0
# Spring constants
k1 = 4.0
k2 = 1.0
kc = 0.1
# Initial conditions
# x1 and x2 are the initial displacements; y1 and y2 are the initial velocities
x1 = -2.0
y1 = 5.0
x2 = 2.0
y2 = 10.0
# ODE solver parameters
abserr = 1.0e-8
relerr = 1.0e-6
stoptime = 100.0
numpoints = 250
t = [stoptime * float(i) / (numpoints - 1) for i in range(numpoints)]
# Pack up the parameters and initial conditions:
p = [m1, m2, k1, k2, kc]
w0 = [x1, y1, x2, y2]
# Call the ODE solver.
wsol = odeint(vectorfield, w0, t, args=(p,), atol=abserr, rtol=relerr)
# Print solution
for t1, w1 in zip(t, wsol):
AZ = [t1, w1[0], w1[1], w1[2], w1[3]]
print(AZ)
I have tried searching the web but wasnt unable to find a fitting solution to plot this. I tried
with open('coupled_masses.dat', 'w') as f:
for t1, w1 in zip(t, wsol):
print(f, t1, w1[0], w1[1], w1[2], w1[3])
import matplotlib.pyplot as plt;
from matplotlib.font_manager import FontProperties;
# get saved values from saved file
t, x1, y1, x2, y2 = np.loadtxt('coupled_masses.dat', unpack=True);
but it doesnt work
Is this what you want? Using list comprehension here and then convert to numpy array.
from scipy.integrate import odeint
def vectorfield(w, t, p):
x1, y1, x2, y2 = w
m1, m2, k1, k2, kc = p
# Create f = (x1',y1',x2',y2'):
f = [y1, (-x1*(k1+kc) + x2*kc)/m1, y2, (x1*kc - x2*(k2+kc)) / m2]
return f
# Parameter values
# Masses:
m1 = 1.0
m2 = 1.0
# Spring constants
k1 = 4.0
k2 = 1.0
kc = 0.1
# Initial conditions
# x1 and x2 are the initial displacements; y1 and y2 are the initial velocities
x1 = -2.0
y1 = 5.0
x2 = 2.0
y2 = 10.0
# ODE solver parameters
abserr = 1.0e-8
relerr = 1.0e-6
stoptime = 100.0
numpoints = 250
t = [stoptime * float(i) / (numpoints - 1) for i in range(numpoints)]
# Pack up the parameters and initial conditions:
p = [m1, m2, k1, k2, kc]
w0 = [x1, y1, x2, y2]
# Call the ODE solver.
wsol = odeint(vectorfield, w0, t, args=(p,), atol=abserr, rtol=relerr)
# Print solution
data = np.array([[t1, w1[0], w1[1], w1[2], w1[3]] for t1, w1 in zip(t, wsol)])
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7.2, 7.2/2))
ax1.plot(data[:, 0], data[:, 1])
ax2.plot(data[:, 0], data[:, 3])
UNEXPOSED = '~'
POKEMON = "☺"
FLAG = "♥"
EXPOSED = "0"
possible_adjacent_amount = ["0", "1", "2" "3", "4", "5", "6", "7", "8"]
def draw_board(self, board):
self.delete()
index = 0
print(board)
for row in range(self._grid_size):
for column in range(self._grid_size):
x1 = column*self._cell_size
y1 = row * self._cell_size
x2 = x1 + self._cell_size
y2 = y1 + self._cell_size
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
#bounding_box = ((int (x1), int (y1)), (int (x2), int (y2)))
centre_pixel = (x1 + (x2 - x1) // 2, y1 + (y2 - y1) // 2)
self.pos_to_pixel[(row, column)] = centre_pixel
#tp = self.create_text((100, 100), text='1')
print(board[index])
if board[index] ==UNEXPOSED:
self.create_rectangle (x1, y1, x2, y2, fill="dark green", tags="rect")
if board[index] in possible_adjacent_amount :
# TODO why doesn't this work...?
self.create_text(self.position_to_pixel ((row, column)), text = board[index])
self.create_rectangle (x1, y1, x2, y2, fill="light green", tags="rect")
if board[index] == FLAG:
self.create_rectangle (x1, y1, x2, y2, fill="red", tags="rect")
if board[index] == POKEMON:
self.create_text ((centre_pixel), text=board[index])
self.create_rectangle (x1, y1, x2, y2, fill="yellow", tags="rect")
index += 1
The board input will be something like 0~~~1~~12~~3
The idea is that it will take the board index and then create text at the center pixel of the board index that will be the numbers which in this case would be 0, 1, 1, 2, 3
You if you want the numbers to be drawn on the rectangles you need to create the text after you create the rectangles otherwise you will create text behind the rectangles.
In the Python implementation of the Xiaolin Wu's line algorithm, a function is defined while being nested in another function. Part of the code:
def draw_line(img, p1, p2, color):
"""Draws an anti-aliased line in img from p1 to p2 with the given color."""
x1, y1 = p1
x2, y2 = p2
dx, dy = x2-x1, y2-y1
steep = abs(dx) < abs(dy)
p = lambda px, py: ((px,py), (py,px))[steep]
if steep:
x1, y1, x2, y2, dx, dy = y1, x1, y2, x2, dy, dx
if x2 < x1:
x1, x2, y1, y2 = x2, x1, y2, y1
grad = dy/dx
intery = y1 + _rfpart(x1) * grad
def draw_endpoint(pt):
x, y = pt
xend = round(x)
yend = y + grad * (xend - x)
xgap = _rfpart(x + 0.5)
px, py = int(xend), int(yend)
putpixel(img, p(px, py), color, _rfpart(yend) * xgap)
putpixel(img, p(px, py+1), color, _fpart(yend) * xgap)
return px
How does this work? Why didn't the programmer just define the code somewhere else and then call it in this function? If this function where to be called in a loop to draw multiple lines, wouldn't it be more efficient to just, as I said, define the nested function somewhere else?
try this:
class Humans():
def health(self, weight, height, age):
self.weight = weight
self.height = height
self.age = age
def health_health(self):
print(f'''This human is {self.age} years old; weighs {self.weight},
and has a height of {self.height}''')
Harar = Humans()
Harar.health(1,2,3)
Harar.health_health()
The reason why is because you are calling the function from the class definition, as opposed to the initialized object. You can do two things to fix this:
Call the function from the object that has been initialized:
class Foo:
def bar(x):
print(x)
a = Foo()
a.bar(10)
Or, define the function as a staticmethod:
class Foo:
#staticmethod
def bar(x):
print(x)
Foo.bar(10)
Both will output:
10
I'm new to python and learned a ton over the past 2 weeks. I have just started learning and experimenting with matplotlib.pylot. In my code, I have 3 seperate simple graphs on the same plot, in the third graph there are 2 lines. I am trying to have a green fill_between when y2 > y3, and red fill_between when y3 > y2. I have taken a look at other code, and they look identical to mine, but for some reason it doesn't work.
Any help?
There are a few commented lines, they are just experimentation.
import matplotlib.pyplot as plt
import random
from matplotlib import style
style.use('fivethirtyeight')
def create_points(nPoints):
xs = []
ys = []
for i in range(nPoints):
rand = random.randrange(0,3*nPoints)
xs.append(i)
ys.append(rand)
return xs, ys
x,y = create_points(200)
x1,y1 = create_points(200)
x2, y2 = create_points(200)
x3, y3 = create_points(200)
fig = plt.figure()
ax1 = plt.subplot2grid((6,1), (0,0), rowspan = 1, colspan = 1)
plt.title('Subplot2grid Method')
plt.ylabel('Plot 1')
ax2 = plt.subplot2grid((6,1), (1,0), rowspan = 4, colspan = 1, sharex = ax1)
plt.ylabel('Plot 2')
ax2_xtwin = ax2.twinx()
ax3 = plt.subplot2grid((6,1), (5,0), rowspan = 1, colspan = 1, sharex = ax1)
plt.xlabel('x')
plt.ylabel('Plot 3')
ax2_xtwin.fill_between(x,0,y, facecolor = '#0079a3', alpha = 0.4)
#ax2v.axes.yaxis.set_ticklables([])
ax2_xtwin.grid(False)
ax2_xtwin.set_ylim(0, 1.5*max(y))
ax3.plot(x2, y2, x2, y3, linewidth = 1, label = 'x2y2 plot', color = 'k')
#ax3.plot(x3, y3, linewidth = 1, label = 'x3y3 plot', color = 'firebrick')
ax3.fill_between(x2, y2, y3, where = (y2 >= y3), facecolor = 'darkgreen',
edgecolor = 'g', alpha = 0.5, interpolate = True)
ax3.fill_between(x2, y2, y3, where = (y2 <= y3), facecolor = 'firebrick',
edgecolor = 'r', alpha = 0.5, interpolate = True)
#Print Points
ax1.plot(x, y, linewidth = 1, label = 'xy plot', color = 'gold')
ax2.plot(x1, y1, linewidth = 1, label = 'x1y1 plot', color = 'sandybrown')
#ax3.plot(x2, y2, linewidth = 1, label = 'x2y2 plot', color = 'darkgreen')
#ax3.plot(x3, y3, linewidth = 1, label = 'x3y3 plot', color = 'firebrick')
plt.subplots_adjust(left = 0.15, bottom = 0.1, right = 0.9, top = 0.9,
wspace = 0.2, hspace = 0)
plt.show()
Edit:
Sorry I miss-understood your question.
If you delete color='k' in ax3.plot and mask the y2 after the first fill_between it works fine.
Change to...
ax3.plot(x2, y2, x2, y3, linewidth = 1, label = 'x2y2 plot')
ax3.fill_between(x2, y2, y3, where = (y2 >= y3), color = "g",
edgecolor = 'g', alpha = 0.5, interpolate = True)
y2 = np.ma.masked_greater(y2, y3)
ax3.fill_between(x2, y2, y3, where = (y2 <= y3), color="r",
edgecolor = 'r', alpha = 0.5, interpolate = True)
I'm not sure why but the facecolor didn't work on my side, so I changed to color.
Hope this helps.