How can I smooth ConvexHull like an ellipse? - python

I am trying to plot an encircling area in a scatter plot with Matplotlib, and I want to smooth a Convex Hull like an ellipse. Could anyone give me some suggestions?
Here is my code
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from matplotlib import patches
midwest = pd.read_csv('https://raw.githubusercontent.com/gitony0101/X4DS/main/data/midwest_filter.csv')
midwest_encircle_data = midwest.query("state=='IN'")
_, ax = plt.subplots(figsize=(10, 8))
g = sns.scatterplot(x='area',
y='poptotal',
data=midwest,
hue='state',
palette='tab10',
size='popdensity',
ax=ax)
def encircle(x, y, ax=None, **kw):
ax = ax or plt.gca()
p = np.stack([x, y], axis=1)
hull = ConvexHull(p)
poly = patches.Polygon(xy=p[hull.vertices, :], closed=True, **kw)
ax.add_patch(poly)
g.set(xlim=(0.0, 0.1),
ylim=(0, 90000),
xlabel='Area',
ylabel='Population',
title='Bubble Plot with Encircling')
x = midwest_encircle_data['area']
y = midwest_encircle_data['poptotal']
encircle(x, y, ec='k', fc='gold', alpha=0.1, ax=ax)
encircle(x, y, ec='firebrick', fc='none', linewidth=1.5, ax=ax)
plt.show()

Related

How to plot a Gaussian Distribution on y-axis?

I hope everyone's healthy and keeping safe.
I currently have the following plot. I want to ultimately plot a Gaussian distribution like this at x=0, y=0. The orange lines are basically the 95% confidence interval.:
Should I try swapping the axis and plotting? Is there a better way to do it? I am currently plotting in matplotlib and python. Are there better libraries to plot? Please let me know.
Thank you!
I have the following code:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF, ConstantKernel
noise = 1.0
X = np.arange(0, 1, 0.01).reshape(-1, 1)
kernel = ConstantKernel(10**2) * RBF(length_scale=0.35)
gp = GaussianProcessRegressor(kernel=kernel, alpha=noise**2, optimizer=None)
gp_mean, gp_std = gp.predict(X, return_std=True)
# Create the figure and the axes
fig, ax = plt.subplots()
ax.plot(X, gp_mean, 'k-', label='Zero-Mean GP')
ax.fill_between(X.ravel(), gp_mean + 1.96*gp_std, gp_mean - 1.96*gp_std, alpha=0.30, label='95% confidence interval')
ax.grid()
ax.legend(prop={'size': 12})
ax.set_xlim([-0.02, 1.0])
ax.set_ylim([-30.0, 30.0])
ax.tick_params(axis='both', labelsize=14)
ax.set_xlabel(r'$x$', fontsize=14)
plt.show()
You could draw the pdf of a gaussian normal on the y-axis as follows:
import numpy as np
from scipy import stats
from matplotlib import pyplot as plt
gp_mean = 0
gp_std = 12
gaussian = stats.norm(gp_mean, gp_std)
fig, ax = plt.subplots()
ys = np.linspace(*gaussian.ppf([0.001, 0.999]), 200)
ax.plot(gaussian.pdf(ys), ys, color='deepskyblue', label='gaussian normal')
ax.axhspan(*gaussian.ppf([0.05, 0.95]), color='chocolate', alpha=0.2, label='95% confidence interval')
ax.plot(0, gp_mean, marker='o', color='crimson', label='mean')
ax.set_xlim(0, 0.5)
ax.legend(prop={'size': 12})
plt.show()
PS: To also draw the pdf and mean at x = 0.5, you can add:
ax.plot(0.5 + gaussian.pdf(ys), ys, color='deepskyblue')
ax.plot(0.5, gp_mean, marker='o', color='crimson')
ax.set_xlim(0, 1)

How to add dynamic contour plot

I wrote some code in juypter to visualize the Bivariate normal distribution. I want to modify the code so that I can visualize the contour plot(isodensity, say the x-y surface) at the same time. What should I add?
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib as mpl
%matplotlib
if __name__ == '__main__':
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
d = np.random.randn(10000000, 2)
N = 30
density, edges = np.histogramdd(d, bins=[30, 30])
print("样本总数: ", np.sum(density))
density = density/density.max()
x = y = np.arange(N)
t = np.meshgrid(x,y)
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(t[0], t[1], density, c='r', s=15*density, marker='o', depthshade=True)
ax.plot_surface(t[0], t[1], density, cmap='rainbow', rstride=1, cstride=1, alpha=0.9, lw=1)
cset = ax.contourf(x, y, density,
zdir ='z',
offset = np.min(density),
)
ax.set_xlabel("x轴")
ax.set_ylabel("y轴")
ax.set_zlabel("z轴")
plt.title("二元高斯分布")
# plt.tight_layout(0.1)
plt.show()

Add legend to pyplot.errorbar

import numpy as np
import matplotlib.pyplot as plt
# example data
x = np.arange(0.1, 4, 0.5)
y = np.exp(-x)
yerr = 0.1*np.random.rand(8)
fig, ax = plt.subplots()
ax.errorbar(x, y, linestyle='none', marker='*', yerr=yerr)
plt.show()
Hi, everyone! The goal is to add legend to the chart. y and yerr are labelled as 'mean' and 'std.Dev', respectively.

Matplotlib 3d Plot Colorbar Scale

I have a 3d plot with a colorbar and I would like the colorbar's size to scale with the size of the projection, no matter the orientation I select with ax.view_init.
It would also be great if I could get the aspect ratio of the 3d plot to be equal at the same time as well.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.colors
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.view_init(elev=90, azim=0)
x = np.arange(3)
X,Y = np.meshgrid(x,x)
Z = np.ones_like(X)
V = np.array([[3,2,2],[1,0,3],[2,1,0]])
norm = matplotlib.colors.Normalize(vmin=0, vmax=3)
ax.plot_surface(X, Y, Z, facecolors=plt.cm.jet(norm(V)), shade=False)
m = cm.ScalarMappable(cmap=plt.cm.jet, norm=norm)
m.set_array([])
plt.colorbar(m)
ax.set_xlabel('x')
ax.set_ylabel('y')
plt.show()
Example code stolen shamelessly from this question

Matplotlib 3D scatter plot with color gradient

How can I create a 3D plot with a color gradient for the points? See the example below, which works for a 2D scatter plot.
Edit (thanks to Chris): What I'm expecting to see from the 3D plot is a color gradient of the points ranging from red to green as in the 2D scatter plot.
What I see in the 3D scatter plot are only red points.
Solution: for some reasons (related to the gradient example I copied elsewhere) I set xrange to len-1, which messes everything in the 3D plot.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Create Map
cm = plt.get_cmap("RdYlGn")
x = np.random.rand(30)
y = np.random.rand(30)
z = np.random.rand(30)
#col = [cm(float(i)/(29)) for i in xrange(29)] # BAD!!!
col = [cm(float(i)/(30)) for i in xrange(30)]
# 2D Plot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(x, y, s=10, c=col, marker='o')
# 3D Plot
fig = plt.figure()
ax3D = fig.add_subplot(111, projection='3d')
ax3D.scatter(x, y, z, s=10, c=col, marker='o')
plt.show()
Here is an example for 3d scatter with gradient colors:
import matplotlib.cm as cmx
from mpl_toolkits.mplot3d import Axes3D
def scatter3d(x,y,z, cs, colorsMap='jet'):
cm = plt.get_cmap(colorsMap)
cNorm = matplotlib.colors.Normalize(vmin=min(cs), vmax=max(cs))
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=cm)
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(x, y, z, c=scalarMap.to_rgba(cs))
scalarMap.set_array(cs)
fig.colorbar(scalarMap)
plt.show()
Of course, you can choose the scale to range between different values, like 0 and 1.
Following works: I can't figure out why yours doesn't. You should be able to set color as a sequence of RGBA floats, or just sequence of floats.
# Create Map
cm = plt.get_cmap("RdYlGn")
x = np.random.rand(30)
y = np.random.rand(30)
z = np.random.rand(30)
col = np.arange(30)
# 2D Plot
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(x, y, s=10, c=col, marker='o')
# 3D Plot
fig = plt.figure()
ax3D = fig.add_subplot(111, projection='3d')
p3d = ax3D.scatter(x, y, z, s=30, c=col, marker='o')
plt.show()
However, in help of scatter, I see the following, it may be related.
A :class:`matplotlib.colors.Colormap` instance or registered
name. If *None*, defaults to rc ``image.cmap``. *cmap* is
only used if *c* is an array of floats.

Categories