How to fill area between two sets of data connected by line? - python

I have two sets of data that are shown like lines in graph. How to fill with color area between them?
import matplotlib.pyplot as plt
curve1, = plt.plot(xdata, ydata)
curve2, = plt.plot(xdata, ydata)
I tried:
x = np.arange(0,12,0.01)
plt.fill_between(x, curve1, curve2, color='yellow')
Thank you

You have to use the ydata as arguments for your fill_between, not the curves.
Either use ydata directly, or get them from your curve1/2 objects like ydata=curve1.get_ydata().
Here is an example adapted from the docs:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-5, 5, 0.01)
y1 = -5*x*x + x + 10
y2 = 5*x*x + x
c1, = plt.plot(x, y1, color='black')
c2, = plt.plot(x, y2, color='black')
# If you want/have to get the data form the plots
# x = c1.get_xdata()
# y1 = c1.get_ydata()
# y2 = c2.get_ydata()
plt.fill_between(x, y1, y2, where=y2 >y1, facecolor='yellow', alpha=0.5)
plt.fill_between(x, y1, y2, where=y2 <=y1, facecolor='red', alpha=0.5)
plt.title('Fill Between')
plt.show()
In the end you get:

Related

Shade the surface and contour parts

I want to shade the surface and the contours of a specific function based on some constraint in the domain of the function. So far I have the following and I want to improve it.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import LinearLocator, FormatStrFormatter
plt.figure(figsize=(8, 6))
plt.axes(projection="3d")
xdata = np.linspace(-3, 3, 20000)
ydata = np.linspace(-3, 3, 20000)
X, Y = np.meshgrid(xdata, ydata)
Z1 = X ** 2 + Y ** 2
Z2 = Z1.copy()
Z3 = Z1.copy()
Z1[np.multiply(X, Y) > 3] = np.nan
Z2[np.multiply(X, Y) <= 3] = np.nan
Z3[np.multiply(X, Y) == 3] = np.nan
ax3d = plt.axes(projection='3d')
ax3d.plot_surface(X, Y, Z1, cmap='Greys', antialiased=True, vmin=-np.nanmin(Z1), vmax=np.nanmax(Z1))
ax3d.plot_surface(X, Y, Z2, cmap='YlGnBu', antialiased=True, vmin=-np.nanmin(Z2), vmax=np.nanmax(Z2))
ax3d.contourf(X, Y, Z1, zdir='z', offset=0, cmap='Greys')
ax3d.contourf(X, Y, Z2, zdir='z', offset=0, cmap='Greys')
ax3d.set_title('Surface Plot in Matplotlib')
ax3d.set_xlabel('X')
ax3d.set_ylabel('Y')
ax3d.set_zlabel('Z')
plt.show()
Could you please someone help to solve the following problems:
The surface is over-imposed by the contour surface.
There are some gaps in the surface.
The contours of the two constraints are not continuous.
Is it possible to plot a line in the border of the two surfaces and contours?
Any help is highly appreciated.
The code below makes the following changes:
creating a custom colormap combining the two existing colormaps
using a TwoSlopeNorm to have the separation at z=3
setting antialiased=False (otherwise matplotlib creates a plot of antialiased lines instead of polygons)
xdata and ydata with 300 steps
using rstride=1, cstride=1 so every x and every y will be considered; this makes the surface smoother (but takes more time)
calling plt.axes(...) only once to prevent a dummy subplot
calling contourf before plot_surface; due to the painter's algorithm, matplotlib only minimally supports 3D overlaps
import matplotlib.pyplot as plt
from matplotlib.colors import TwoSlopeNorm, ListedColormap
import numpy as np
xdata = np.linspace(-3, 3, 300)
ydata = np.linspace(-3, 3, 300)
X, Y = np.meshgrid(xdata, ydata)
Z1 = X ** 2 + Y ** 2
cmap1 = plt.get_cmap('Greys')
cmap2 = plt.get_cmap('YlGnBu')
cmap = ListedColormap(np.r_[cmap1(np.linspace(0, 1, 128)), cmap2(np.linspace(0, 1, 128))])
norm = TwoSlopeNorm(vmin=np.nanmin(Z1), vmax=np.nanmax(Z1), vcenter=3)
plt.figure(figsize=(8, 6))
ax3d = plt.axes(projection='3d')
ax3d.contourf(X, Y, Z1, zdir='z', offset=0, cmap=cmap, norm=norm)
ax3d.plot_surface(X, Y, Z1, cmap=cmap, antialiased=False, norm=norm, rstride=1, cstride=1)
ax3d.set_title('Surface Plot in Matplotlib')
ax3d.set_xlabel('X')
ax3d.set_ylabel('Y')
ax3d.set_zlabel('Z')
plt.show()
xdata = np.linspace(-3, 3, 1000)
ydata = np.linspace(-3, 3, 1000)
X, Y = np.meshgrid(xdata, ydata)
Z1 = X ** 2 + Y ** 2
Z2 = Z1.copy()
Z3 = Z1.copy()
Z2[np.multiply(X, Y) <= 3] = np.nan
Z3[np.multiply(X, Y) == 3] = np.nan
plt.figure(figsize=(8, 6))
ax3d = plt.axes(projection='3d')
ax3d.contourf(X, Y, Z1, zdir='z', offset=0, cmap='Greys')
ax3d.contourf(X, Y, Z2, zdir='z', offset=0, cmap='YlGnBu')
ax3d.plot_surface(X, Y, Z1, cmap='Greys', antialiased=True, vmin=-np.nanmin(Z1), vmax=np.nanmax(Z1), alpha=.5)
ax3d.plot_surface(X, Y, Z2, cmap='YlGnBu', antialiased=True, vmin=-np.nanmin(Z2), vmax=np.nanmax(Z2), alpha=.5)
ax3d.set_title('Surface Plot in Matplotlib')
ax3d.set_xlabel('X')
ax3d.set_ylabel('Y')
ax3d.set_zlabel('Z')
plt.show()

Slices across Contourf plots at different angles to get 2D line plots

I am trying to generate 2D line plots at different angles or slices of a matplotlib contourf plot.
As an example from the matplotlib contourf demo example below
import numpy as np
import matplotlib.pyplot as plt
origin = 'lower'
delta = 0.025
x = y = np.arange(-3.0, 3.01, delta)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
Z = (Z1 - Z2) * 2
nr, nc = Z.shape
fig1, ax2 = plt.subplots(constrained_layout=True)
CS = ax2.contourf(X, Y, Z, 10, cmap=plt.cm.viridis, origin=origin,extend='both')
ax2.set_title('Random Plot')
ax2.set_xlabel('X Axis')
ax2.set_ylabel('Y Axis')
cbar = fig1.colorbar(CS)
Ideally, I want to generate lines at different angles (30,45,60 degrees) across the map (starting at any arbitrary point till the end of existing array) and then plot the Z variations across that line.
I think a simpler problem in principle would be, lines from (X2,Y2) to (X1,Y1) and plot the Z variation for the given contour (which is already interpolated data).
As an example, original problem would be line from (-3,-3) at angle 45 deg across. Analogous problem would be lets say a line from (-3,-3) to (3,3) and plot the Z variation at different locations on that line.
The source contour plot generated is :
Here is a rather inefficient approach, but it does the job. It recalculates the function on a new grid of which it only needs the diagonal.
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import RectBivariateSpline
delta = 0.025
x = y = np.arange(-3.0, 3.01, delta)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X ** 2 - Y ** 2)
Z2 = np.exp(-(X - 1) ** 2 - (Y - 1) ** 2)
Z = (Z1 - Z2) * 2
nr, nc = Z.shape
x1, y1 = -3, -2
x2, y2 = 3, 2
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(15, 5))
CS = ax1.contourf(X, Y, Z, 10, cmap=plt.cm.viridis, origin='lower', extend='both')
ax1.plot([x1, x2], [y1, y2], color='k', ls='--', lw=3, alpha=0.6)
ax1.set_xlabel('X Axis')
ax1.set_ylabel('Y Axis')
cbar = fig.colorbar(CS, ax=ax1)
spline_func = RectBivariateSpline(x, y, Z)
xline = np.linspace(x1, x2, 200)
yline = np.linspace(y1, y2, 200)
zline = spline_func(xline, yline)
ax2.plot(xline, zline.diagonal())
ax2.set_xlabel('X Axis')
ax2.set_ylabel('Z Axis')
plt.show()

How to plot a slicing plane with a surface with “matplotlib” in python

I wonder how to create two slicing planes with a surface to two 2d figures.
For example, I created a surface as below:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot as plt
import numpy as np
def f(x1, x2):
return 0.5 * x1 + 0.6 * x2 + 0.2 * x1 * x1 + 0.1 * x1 * x2 + 0.3 * x2 * x2 + 4
x = np.linspace(-3, 3, 100)
y = np.linspace(-3, 3, 100)
xx, yy = np.meshgrid(x,y)
z = f(xx, yy)
# set up the figure
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_xlim(-3, 3)
ax.set_ylim(3, -3)
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
# plot the figure
ax.plot_surface(xx, yy, z, cmap="spring", alpha = 0.7)
# add the x=y line to the ground plane
ax.plot([-3, 3], [-3, 3], color='grey', linewidth=1, linestyle='dashed')
# add the x=-y line to the ground plane
ax.plot([3, -3], [-3, 3], color='grey', linewidth=1, linestyle='dashed')
ax.plot(x, x, f(x, x), color='dodgerblue')
ax.plot(x, -x, f(x, -x), color='dodgerblue')
plt.show()
The surface created by the above code looks like this
After this, I want to add two slicing planes, which are x = y and x = -y planes. And plot the cutting lines of the two planes and the surface to two different 2d figures.
For example, one 2d figure of the cutting line of the surface and the x = y plane would be something like the figure in the red box below, but no surface, just the red curve.
Actually, just need to plot them in two 2d figures
# slicing figure 1
fig2, ax2 = plt.subplots()
ax2.plot(x, f(x, y, b1, b2, b3, b4, b5, con))
ax2.set_title("x=y plane")
ax2.set_xlim(-3, 3)
ax2.set_ylim(1, 15)
# slicing figure 2
fig3, ax3 = plt.subplots()
ax3.plot(x, f(x, -y, b1, b2, b3, b4, b5, con))
ax3.set_title("x=-y plane")
ax3.set_xlim(-3, 3)
ax3.set_ylim(1, 15)

Fill area between two curves in python

I am trying to shade the area between two curves that I have plotted.
This is what I plotted.
Using the following code.
plt.scatter(z1,y1, s = 0.5, color = 'blue')
plt.scatter(z2,y2, s = 0.5, color = 'orange')
I tried using plt.fill_between() but for this to work I need to have the same data on the x_axis (would need to do something like plt.fill_between(x,y1,y2)).
Is there any other function that might help with this or am I just using fill_between wrong.
You can try with:
plt.fill(np.append(z1, z2[::-1]), np.append(y1, y2[::-1]), 'lightgrey')
For example:
import numpy as np
import matplotlib.pyplot as plt
x1 = np.array([1,2,3])
y1 = np.array([2,3,4])
x2 = np.array([2,3,4,5,6])
y2 = np.array([1,2,3,4,5])
# plt.plot(x1, y1, 'o')
# plt.plot(x2, y2, 'x')
plt.scatter(x1, y1, s = 0.5, color = 'blue')
plt.scatter(x2, y2, s = 0.5, color = 'orange')
plt.fill(np.append(x1, x2[::-1]), np.append(y1, y2[::-1]), 'lightgrey')
plt.show()
Try this code:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0.0, 2, 0.01)
y1 = np.sin(2 * np.pi * x)
y2 = 1.2 * np.sin(4 * np.pi * x)
fig, (ax1) = plt.subplots(1, sharex=True)
ax1.fill_between(x, 0, y1)
ax1.set_ylabel('between y1 and 0')

matplotlib plot the sum of two lines of different type of arrays

I have two lines plotted on the graph, but they originate from two different shape of arrays, how can I then plot their sum?
e.g. in the Figure below, I have the data of line1 and line2, how can I have "line 1 + line 2"?
import matplotlib.pyplot as plt
plt.figure()
plt.plot([1,2,3],[1,1,1],label='line 1')
plt.plot([1.5,2.5],[2,2],label='line 2')
plt.plot([1,1.5,2,2.5,3],[1,3,3,3,1],label='line 1+lin 2')
plt.legend(loc=1)
plt.show()
You need to interpolate both datasets on a common basis. Then you can simply add them up.
import numpy as np
import matplotlib.pyplot as plt
x1, y1 = [1,2,3],[1,1,1]
x2, y2 = [1.5,2.5],[2,2]
# get a sorted list of all x values
x = np.unique(np.concatenate((x1,x2)))
# interpolate y1 and y2 on the combined x values
yi1 = np.interp(x, x1, y1, left=0, right=0)
yi2 = np.interp(x, x2, y2, left=0, right=0)
plt.plot(x1, y1, label="Line 1")
plt.plot(x2, y2, label="Line 2")
plt.plot(x, yi1 + yi2, label="Line 1 + Line 2")
plt.legend(loc="upper right")
plt.show()

Categories

Resources