Color of the cylinder in python - matplotlib

How to colour the base on y = 0.3 by the same color as the middle part of the cylinder have, please?
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d import proj3d
def data_for_cylinder_along_z(center_x,center_y,radius,height_z):
z = np.linspace(0, height_z, 200)
theta = np.linspace(0, 2*np.pi, 200)
theta_grid, z_grid=np.meshgrid(theta, z)
x_grid = radius*np.cos(theta_grid) + center_x
y_grid = radius*np.sin(theta_grid) + center_y
return x_grid,y_grid,z_grid
fig = plt.figure(figsize=[6,5])
ax = fig.add_subplot(111, projection='3d')
ax.azim = -39
ax.elev = 15
Xc,Zc,Yc = data_for_cylinder_along_z(0,0,0.05,0.3)
ax.plot_surface(Xc, Yc, Zc, alpha=0.4, color = 'grey')
plt.show()

Related

adjust text position according to bar width

I would like to adjust the bar value text position below each bar top with barwidth/5 offset.
text_y -= bar.get_width()/5 # <- not work
Full code:
#!/usr/bin/env python3
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.patheffects as PathEffects
import math
import numpy as np
def save_fig(fig,pngname):
fig.savefig(pngname, dpi=fig.dpi, bbox_inches="tight")
print("[[%s]]"%pngname)
return
def plot_bar(df):
xname = df.columns[0]
fig, ax = plt.subplots(figsize=(10, 5))
x = np.arange(len(df[xname]))
n = len(df.columns[1:])
bar_width = 0.95/n
fontsize = 20
colors = ['#5891ad','#004561','#ff6f31','#1c7685','#0f45a8','#4cdc8b','#0097a7']
dy = -bar_width/10
bars = []
# add bars
for i,colname in enumerate(df.columns[1:]):
bar = ax.bar(x+i*bar_width, df[colname], width=bar_width,color=colors[i])
bars.append(bar)
# add text on bars
for bar in ax.patches:
bar_value = bar.get_height()
text = f'{bar_value:,}'
text_x = bar.get_x() + bar.get_width() / 2
text_y = bar.get_y() + bar_value
text_y -= bar.get_width()/5 # <- not work
bar_color = bar.get_facecolor()
t = ax.text(text_x, text_y, text, ha='center', va='top', color=bar_color,
size=fontsize)
t.set_path_effects([PathEffects.withStroke(linewidth=bar_width*15, foreground='w')])
ax.set_xticks(x + 1/ 2 - bar_width/2)
ax.set_xticklabels(df[xname])
ax.legend()
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
#ax.spines['left'].set_visible(False)
#ax.spines['bottom'].set_color('#DDDDDD')
ax.tick_params(bottom=False, left=False)
ax.set_axisbelow(True)
ax.yaxis.grid(True, color='#EEEEEE')
ax.xaxis.grid(False)
ax.set_xlabel('x', labelpad=15)
ax.set_ylabel('y', labelpad=15)
ax.set_title('title', pad=15)
fig.tight_layout()
plt.show()
return
data = [['a',3,2,1],
['b',2,3,1],
['c',3,1,3],
['d',5,1,3],
]
df = pd.DataFrame(data,columns=['f1','f2','f3','f4'])
plot_bar(df)

Adding patch distorts alignment

I am working with the following image:
from matplotlib import cbook
import matplotlib.patches as mpatches
from matplotlib.axes._base import _TransformedBoundsLocator
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import numpy as np
# a numpy array of 15x15
Z = cbook.get_sample_data("axes_grid/bivariate_normal.npy", np_load=True)
gs = GridSpec(2, 3)
fig = plt.figure(figsize=(3*3,2*3))
ax1 = fig.add_subplot(gs[:2, :2])
ax2 = fig.add_subplot(gs[1, 2])
Z2 = np.zeros((150, 150))
ny, nx = Z.shape
Z2[30:30+ny, 30:30+nx] = Z
ax1.imshow(Z2)
ax1.set_aspect("equal")
ax2.set_aspect("equal")
plt.tight_layout()
plt.show()
output:
As shown in the image, the x-axis of both plots are aligned. However, when I am adding a patch to the first plot the alignment becomes distorted:
Z = cbook.get_sample_data("axes_grid/bivariate_normal.npy", np_load=True)
gs = GridSpec(2, 3)
fig = plt.figure(figsize=(3*3,2*3))
ax1 = fig.add_subplot(gs[:2, :2])
ax2 = fig.add_subplot(gs[1, 2])
Z2 = np.zeros((150, 150))
ny, nx = Z.shape
Z2[30:30+ny, 30:30+nx] = Z
ax1.imshow(Z2)
x, y, width, height = 30, 30, 15, 15
ex, ey = (0,1)
xy_data = x + ex * width, y + ey * height
p = mpatches.ConnectionPatch(
xyA=(0,1), coordsA=ax2.transAxes,
xyB=xy_data, coordsB=ax1.transData)
ax1.add_patch(p)
ax1.set_aspect("equal")
ax2.set_aspect("equal")
plt.tight_layout()
plt.show()
output:
Why is this? How can I add a patch whilst retaining the original layout?

pyplot 3d z axis-log plot

In order to create a 3d plot using plot_surface and wireframe I wrote this (looking here around)
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import rc
from matplotlib.ticker import MultipleLocator
import matplotlib.ticker as mticker
import numpy as np
from matplotlib.ticker import FormatStrFormatter
def log_tick_formatter(val, pos=None):
return f"10$^{{{int(val)}}}$"
data=np.genfromtxt('jpdfomegal2_90.dat')
x_len= len(np.unique(data[:, 0]))
y_len= len(np.unique(data[:, 1]))
X = data[:, 0].reshape(x_len, y_len)
Y = data[:, 1].reshape(x_len, y_len)
Z = data[:, 2].reshape(x_len, y_len)
#identify lowest non-negative Z value Zmin>0
Zmin = np.where(Z > 0, Z, np.inf).min()
Zmax = Z.max()
#and substitute zero with a slightly lower value than Zmin
Z[Z==0] = 0.9 * Zmin
#log transformation because the conversion in 3D
#does not work well in matplotlib
Zlog = np.log10(Z)
rc('font',family='palatino')
rc('font',size=18)
fig = plt.figure(figsize=(12,8))
#ax = fig.add_subplot(projection='3d')
ax = Axes3D(fig)
ax.set_xlim3d(0,15)
ax.set_zlim3d(np.floor(np.log10(Zmin))-1, np.ceil(np.log10(10)))
ax.zaxis.set_major_formatter(mticker.FuncFormatter(log_tick_formatter))
ax.zaxis.set_major_locator(mticker.MaxNLocator(integer=True))
rc('font',family='palatino')
rc('font',size=18)
tmp_planes = ax.zaxis._PLANES
ax.zaxis._PLANES = ( tmp_planes[2], tmp_planes[3],
tmp_planes[0], tmp_planes[1],
tmp_planes[4], tmp_planes[5])
ax.set_xlabel('$\omega^2 /<\omega^2>$')
ax.xaxis.labelpad = 10
ax.yaxis.labelpad = 10
ax.set_ylabel('cos$(\omega,\lambda^2)$')
ax.zaxis.set_rotate_label(False) # disable automatic rotation
ax.zaxis.labelpad = 10
ax.set_zlabel('')
ax.view_init(elev=17, azim=-60)
ax.grid(False)
ax.xaxis.pane.set_edgecolor('black')
ax.yaxis.pane.set_edgecolor('black')
ax.zaxis.pane.set_edgecolor('black')
ax.xaxis.pane.fill = False
ax.yaxis.pane.fill = False
ax.zaxis.pane.fill = False
ax.xaxis.set_major_locator(MultipleLocator(2))
ax.yaxis.set_major_locator(MultipleLocator(0.2))
ax.zaxis.set_major_locator(MultipleLocator(1))
#not sure this axis scaling routine is really necessary
scale_x = 1
scale_y = 1
scale_z = 0.8
ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([scale_x, scale_y, scale_z, 1]))
ax.contour(X, Y, np.log10(Z), 4, lw=0.1, colors="k", linestyles="--", offset=np.floor(np.log10(Zmin))-1)#-7)
surf = ax.plot_surface(X, Y, np.log10(Z), cmap="binary", lw=0.1,alpha=0.5)
ax.plot_wireframe(X, Y, np.log10(Z),linewidth=1,color='k')
ax.contour(X, Y, np.log10(Z), 4, lw=0.1, colors="k", linestyles="solid")
fig.colorbar(surf, shrink=0.5, aspect=20)
plt.tight_layout()
plt.savefig('jpdf_lambda2_90.png', bbox_inches='tight')
plt.show()
the problem is related to the "minorticks" along zaxis .. I obtain this :
but I would have this format and ticks in the axis
Does somebody clarify how to obtain it and as well I did not find a way to use the log scale in pyplot 3d
There's an open bug on log-scaling in 3D plots, and it looks like there won't be a fix any time soon.
You can use a matplotlib.ticker.FixedLocator to add the z-axis minor ticks, as shown below.
I didn't have your data, so I've plotted an arbitrary surface.
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import rc
from matplotlib.ticker import MultipleLocator, FixedLocator
import matplotlib.ticker as mticker
import numpy as np
from matplotlib.ticker import FormatStrFormatter
def log_tick_formatter(val, pos=None):
return f"10$^{{{int(val)}}}$"
x = np.linspace(1,15,15)
y = np.linspace(0,1,15)
X, Y = np.meshgrid(x, y)
Z = 1 + X**2 * Y**2
#identify lowest non-negative Z value Zmin>0
Zmin = np.where(Z > 0, Z, np.inf).min()
Zmax = Z.max()
#and substitute zero with a slightly lower value than Zmin
Z[Z==0] = 0.9 * Zmin
rc('font',family='palatino')
rc('font',size=18)
fig = plt.figure(figsize=(12,8))
ax = Axes3D(fig, auto_add_to_figure=False)
fig.add_axes(ax)
ax.set_xlim3d(0,15)
ax.set_zlim3d(np.floor(np.log10(Zmin))-1, np.ceil(np.log10(Zmax)))
ax.zaxis.set_major_formatter(mticker.FuncFormatter(log_tick_formatter))
tmp_planes = ax.zaxis._PLANES
ax.zaxis._PLANES = ( tmp_planes[2], tmp_planes[3],
tmp_planes[0], tmp_planes[1],
tmp_planes[4], tmp_planes[5])
ax.set_xlabel('$\omega^2 /<\omega^2>$')
ax.xaxis.labelpad = 10
ax.yaxis.labelpad = 10
ax.set_ylabel('cos$(\omega,\lambda^2)$')
ax.zaxis.set_rotate_label(False) # disable automatic rotation
ax.zaxis.labelpad = 10
ax.set_zlabel('')
ax.view_init(elev=17, azim=-60)
ax.grid(False)
ax.xaxis.pane.set_edgecolor('black')
ax.yaxis.pane.set_edgecolor('black')
ax.zaxis.pane.set_edgecolor('black')
ax.xaxis.pane.fill = False
ax.yaxis.pane.fill = False
ax.zaxis.pane.fill = False
ax.xaxis.set_major_locator(MultipleLocator(2))
ax.yaxis.set_major_locator(MultipleLocator(0.2))
ax.zaxis.set_major_locator(MultipleLocator(1))
# Z minor ticks
zminorticks = []
zaxmin, zaxmax = ax.get_zlim()
for zorder in np.arange(np.floor(zaxmin),
np.ceil(zaxmax)):
zminorticks.extend(np.log10(np.linspace(2,9,8)) + zorder)
ax.zaxis.set_minor_locator(FixedLocator(zminorticks))
#not sure this axis scaling routine is really necessary
scale_x = 1
scale_y = 1
scale_z = 0.8
ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([scale_x, scale_y, scale_z, 1]))
ax.contour(X, Y, np.log10(Z), 4, colors="k", linestyles="--", offset=np.floor(np.log10(Zmin))-1)#-7)
surf = ax.plot_surface(X, Y, np.log10(Z), cmap="binary", lw=0.1,alpha=0.5)
ax.plot_wireframe(X, Y, np.log10(Z),linewidth=1,color='k')
ax.contour(X, Y, np.log10(Z), 4, colors="k", linestyles="solid")
fig.colorbar(surf, shrink=0.5, aspect=20)
# get a warning that Axes3D is incompatible with tight_layout()
# plt.tight_layout()
# for saving
# fig.savefig('log3d.png')
plt.show()

How to draw something like simple sun in matplotlib?

How to make a circle and lines outwards, please? Shape like:
I have a circle, but I do not know how to continue with lines.
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig, ax1 = plt.subplots(figsize=(10,10))
circle = patches.Circle((0.45, 0.5), radius=0.13, transform=ax1.transData, clip_on=False, zorder=10, linewidth=2,
edgecolor='black', facecolor=(0, 0, 0, .0125))
ax1.patches.append(circle)
plt.show()
Sine and cosine of 16 angles can be used to create the lines:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
fig, ax1 = plt.subplots(figsize=(10, 10))
rad_circ = 0.13
rad_line_start = 0.17
rad_line_end = 0.21
xc, yc = 0.45, 0.5
circle = patches.Circle((xc, yc), radius=rad_circ, transform=ax1.transData, clip_on=False, zorder=10, linewidth=2,
edgecolor='black', facecolor='gold')
ax1.patches.append(circle)
theta = np.linspace(0, 2 * np.pi, 16, endpoint=False)
for th in theta:
ax1.plot([xc + rad_line_start * np.cos(th), xc + rad_line_end * np.cos(th)],
[yc + rad_line_start * np.sin(th), yc + rad_line_end * np.sin(th)],
color='gold', lw=10)
ax1.set_aspect('equal')
ax1.axis('off')
plt.show()
PS: To create all the line segments as a "line collection":
from matplotlib.collections import LineCollection
# ...
line_interval = np.array([[rad_line_start], [rad_line_end]])
segments = np.array([xc + np.cos(theta) * line_interval,
yc + np.sin(theta) * line_interval]).T
lc = LineCollection(segments, colors='gold', lw=10)
ax1.add_collection(lc)

how can i make my figure made by matplotlib response to a mouse click event?

I read the document of matplotlib and write the following code, it supposed to capture my mouse event and move the grey line position when i clicked. I read this code in jupiter notebook online, it stop to show the coordinate of my cursor as it usually do, What's happend? Can anyone help me?
import pandas as pd
import numpy as np
import matplotlib.colors as mcol
import matplotlib.cm as cm
from scipy import stats
from matplotlib.lines import Line2D
import matplotlib.pyplot as plt
import scipy.spatial as spatial
np.random.seed(12345)
df = pd.DataFrame([np.random.normal(33500,150000,3650),
np.random.normal(41000,90000,3650),
np.random.normal(41000,120000,3650),
np.random.normal(48000,55000,3650)],
index=[1992,1993,1994,1995])
fig, ax = plt.subplots()
year_avg = df.mean(axis = 1)
year_std = df.std(axis = 1)
yerr = year_std / np.sqrt(df.shape[1]) * stats.t.ppf(1-0.05/2, df.shape[1]-1)
bars=ax.bar(range(df.shape[0]), year_avg, yerr = yerr, color = 'lightslategrey')
threshold=42000
line=plt.axhline(y = threshold, color = 'grey', alpha = 0.5)
cm1 = mcol.LinearSegmentedColormap.from_list("CmapName",["yellow", "orange", "red"])
cpick = cm.ScalarMappable(cmap=cm1)
percentages = []
cpick.set_array([])
def setColor(bars, yerr,threshold):
for bar, yerr_ in zip(bars, yerr):
low = bar.get_height() - yerr_
high = bar.get_height() + yerr_
percentage = (high-threshold)/(high-low)
if percentage>1: percentage = 1
if percentage<0: percentage=0
percentages.append(percentage)
cpick.to_rgba(percentages)
bars = ax.bar(range(df.shape[0]), year_avg, yerr = yerr, color = cpick.to_rgba(percentages))
return bars
line=plt.axhline(threshold, color = 'grey', alpha = 0.5)
setColor(bars, yerr,threshold)
plt.colorbar(cpick, orientation='horizontal')
plt.xticks(range(df.shape[0]), df.index)
fig = plt.figure()
plt.show()
def onclick(event):
print('%s click: button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
('double' if event.dblclick else 'single', event.button,
event.x, event.y, event.xdata, event.ydata))
line.set_ydata(event.ydata)
#plt.draw()
cid = fig.canvas.mpl_connect('button_press_event', onclick)