I can get a graph drawn using the plot function.
But I would like to highlight some "special" points by having the projections drawn on the axes and putting text on both the point and the axes.
Something like this:
I tried with this:
import matplotlib.pyplot as plt
[...]
plt.plot(X, Y, label='data') # draw curve, X and Y are arrays
plt.plot(Xp, Yp, c, duration), marker='o') # draw point #(Xp, Yp), Xp and Yp are scalars
plt.vlines(Xp, min(Y), Yp, linestyles='dashed')
plt.hlines(Yp, min(X), Xp, linestyles='dashed')
plt.grid(True)
plt.show()
but what I get is not satisfactory:
What is the right way to get what I want?
I've also considered annotate, but it doesn't seem to do what I need. Correct me if I'm wrong.
You can use annotate with a blended transformation:
import matplotlib.pyplot as plt
plt.plot([1,2], [2,4], label='data')
plt.plot([1.7], [3.4], marker='o')
plt.grid(True)
x,y = 1.7, 3.4
arrowprops={'arrowstyle': '-', 'ls':'--'}
plt.annotate(str(x), xy=(x,y), xytext=(x, 0),
textcoords=plt.gca().get_xaxis_transform(),
arrowprops=arrowprops,
va='top', ha='center')
plt.annotate(str(y), xy=(x,y), xytext=(0, y),
textcoords=plt.gca().get_yaxis_transform(),
arrowprops=arrowprops,
va='center', ha='right')
It's not perfect as the you'll still may want to manually adjust the axis coordinates (e.g. -0.05 instead of 0) to set the labels a bit off the axes.
You need to play around with xlim and ylim a bit.
For me this worked:
import matplotlib.pyplot as plt
import numpy as np
if __name__ == "__main__":
X = np.linspace(-.5, 3, 100)
Y = 15000 - 10 * (X - 2.2) ** 2
Xp = X[-10]
Yp = Y[-10]
plt.plot(X, Y, label='data')
plt.plot(Xp, Yp, marker='o')
plt.vlines(Xp, min(Y), Yp, linestyles='dashed')
plt.hlines(Yp, min(X), Xp, linestyles='dashed')
plt.grid(True)
plt.xlim(min(X), None)
plt.ylim(min(Y), None)
plt.show()
Something like that maybe is the answer that you are searching for. https://stackoverflow.com/a/14434334/14920085
y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123] #text that you want to print at the points
fig, ax = plt.subplots()
ax.scatter(z, y)
ax.set_ylabel('y')
ax.set_xlabel('x')
for i, txt in enumerate(n):
ax.annotate(txt, (z[i], y[i]))
Related
I am trying to make a visualization with logarithmic ticks on all sides of the box.
import numpy as np
import matplotlib.pyplot as plt
x = np.logspace(2, 5, 5)
y = 0.5*x**(-1/2)
y2 = 0.01*x**(-1/2)
y3 = 0.05*x**(-1/3)
fig, ax = plt.subplots()
ax.plot(x, y, 'o-', label="One")
ax.plot(x, y2, '*-', label="Two")
ax.plot(x, y3, '--', label="Three")
ax.set(
xlabel='Input',
xlim=(1e2, 1e5),
xscale='log',
ylabel='Output',
ylim=(1e-5, 1e-1),
yscale='log',
)
ax.tick_params(top=True, right=True) # <-- This didn't work how I expected.
ax.legend(loc='lower left');
I would like the associated minor tick marks on the top and right spine.
Any advice on how to make that happen?
Use the which parameter of Axes.tick_params:
ax.tick_params(which='both', top=True, right=True)
Output:
I made a plot, where I have two curves and some lines connecting them, then I tried to remove all ticks and labels, so that only the plane and the legend are visible but I did not manage to remove all, can someone help me?
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate
fig = plt.figure()
ax = fig.gca(projection='3d')
# Plot curve and lines
x = [0,0.1,1,2,3,3.8,4,3.8,3,2,1,0.11,0]
y = [0,0.5,1,0.2,1,0.5,0,-0.5,-1,-0.7,-1,-0.5,0]
tck, u = interpolate.splprep([x, y], s=0)
unew = np.arange(0, 1.01, 0.01)
out = interpolate.splev(unew, tck)
ax.plot([x[1],x[1]+1],[y[1],y[1]],[0,4], color = 'red', label='vector e')
for (xi,yi) in zip(x[2:len(x)-1],y[2:len(y)-1]):
if (xi,yi) == (4,0):
continue
ax.plot([xi,xi+1],[yi,yi],[0,4], color = 'red')
ax.plot(out[0], out[1], zs=0, zdir='z', color = 'blue', label='curve c')
ax.plot(out[0]+1, out[1], zs=4, zdir='z', color = 'blue')
# Make legend, set axes limits and labels
ax.legend()
ax.set_xlim(-1, 6)
ax.set_ylim(-2, 2)
ax.set_zlim(0, 5)
ax.grid(False)
for line in ax.xaxis.get_ticklines():
line.set_visible(False)
for line in ax.yaxis.get_ticklines():
line.set_visible(False)
for line in ax.zaxis.get_ticklines():
line.set_visible(False)
color_tuple = (1.0, 1.0, 1.0, 0.0)
ax.w_xaxis.line.set_color(color_tuple)
ax.w_yaxis.line.set_color(color_tuple)
ax.w_zaxis.line.set_color(color_tuple)
ax.xaxis.set_ticklabels([])
ax.yaxis.set_ticklabels([])
ax.zaxis.set_ticklabels([])
plt.show()
As a minimal change to remove the ticks, you can add the ax.tick_params(color=color_tuple) before plt.show().
If you do ax.tick_params(color=color_tuple, labelcolor=color_tuple) you would no longer need the set_tick_labels([]) calls.
I plotted a waveform and a horizontal line that splits the waveform to upper part and lower part. Using fill in between the lines technique ax.fill_between, why is the yellow area appears not correct?
Please help. TQ.
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import make_interp_spline as make
xy = [(0,2), (1,3.5), (2,6.25), (3,8.7), (4,7.7),
(5,3), (6,2.5), (7,3.7), (8,4.3), (9,4.5), (10,2)]
X = np.array([x for (x,y) in xy])
Y = np.array([y for (x,y) in xy])
X_new = np.linspace(0,10,1000)
s1 = make(X, Y)
Y_new = s1(X_new)
rms = np.sqrt(np.mean(Y**2))
y_upper = np.maximum(rms, Y_new)
y_lower = np.minimum(rms, Y_new)
fig, ax = plt.subplots(figsize=(8, 8))
#ax.plot(X,Y)
ax.plot(X_new, Y_new, label = 'wave')
ax.hlines(y=rms, xmin=0, xmax=10, linestyles='--')
ax.set_xlim(xmin=0, xmax=10)
ax.set_ylim(ymin=1, ymax=10)
ax.set_xticks([])
ax.set_yticks([])
ax.fill_between(X_new, rms, y_upper, facecolor='blue', alpha=0.5)
ax.fill_between(X_new, X_new, y_lower, facecolor='yellow', alpha=0.5)
plt.show()
Your 'yellow fill' is incorrect. You are filling from a diagonal line.
Try:
ax.fill_between(X_new, [0]*len(X_new), y_lower, facecolor='yellow', alpha=0.5)
Well, seeing the other answer, it depends on what you want to "fill between"... :)
You just had a typo here:
ax.fill_between(X_new, X_new, y_lower, facecolor='yellow', alpha=0.5)
Should be:
ax.fill_between(X_new, rms, y_lower, facecolor='yellow', alpha=0.5)
I am trying to give a different to my grid along the x axis and the y axis.
Though when I call ax.grid it seems to hide the grid instead of configuring it.
import matplotlib.pyplot as plt
import numpy
x = numpy.arange(0, 1, 0.05)
y = numpy.power(x, 2)
fig = plt.figure()
ax = fig.gca()
ax.set_xticks(numpy.arange(0, 1, 0.1))
ax.set_yticks(numpy.arange(0, 1., 0.1))
ax.grid(axis='x', linestyle="-", linewidth=1) # doesn't work
ax.grid(axis='y', linestyle="--", linewidth=1) # doesn't work
plt.scatter(x, y)
plt.grid()
plt.show()
Without the ax.grid calls, the grid appears but the style is not what I want.
Just remove plt.grid works for me:
x = np.arange(0, 1, 0.05)
y = np.power(x, 2)
fig = plt.figure()
ax = fig.gca()
ax.set_xticks(np.arange(0, 1, 0.1))
ax.set_yticks(np.arange(0, 1., 0.1))
ax.grid(axis='x', linestyle="-", linewidth=1) # doesn't work
ax.grid(axis='y', linestyle="--", linewidth=1) # doesn't work
ax.scatter(x, y)
# plt.grid()
plt.show()
Output:
I have some code to plot 3D surfaces in Python using matplotlib:
import math
import numpy as np
import matplotlib.pyplot as plt
from pylab import meshgrid,cm,imshow,contour,clabel,colorbar,axis
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import seaborn as sns
sns.set(style="white")
def surface_map(func, xmin=0, xmax=1, ymin=0, ymax=1, step_size=0.05, maxz=25000):
X, Y = meshgrid(
np.arange(xmin, xmax, step_size),
np.arange(ymin, ymax, step_size))
Z = np.zeros(X.shape)
for i in range(X.shape[0]):
for j in range(X.shape[1]):
Z[i, j] = min(func(X[i, j], Y[i, j]), maxz)
return X, Y, Z
def plot_surface(X, Y, Z, xlabel, ylabel, zlabel, title, point=None, size=25):
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z,
rstride=1, cstride=1, vmin=0, vmax=20*1000,
cmap=cm.RdBu, linewidth=0, antialiased=True)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.set_zlabel(zlabel)
ax.set_title(title)
fig.colorbar(surf, shrink=0.5, aspect=5)
if point:
ax.hold(True)
func, fpr, recall = point
ax.scatter([fpr], [recall], [
func(fpr, recall)
], s=size, c='b', marker='.', zorder=10)
plt.show()
And then I call it like so:
# create mesh
R, FPR, FuncValue = surface_map(my_function, xmin=0, xmax=1, ymin=0, ymax=1, step_size=0.05, maxz=20*1000)
# plot it
plot_surface(R, FPR, FuncValue,
xlabel="Recall",
ylabel="FPR",
zlabel="Function Value",
title="Recall Settings Payout Function",
point=(my_function, 0.5, 0.5))
I'm setting ax.scatter to use large marker sizes and a high zorder, but no point gets drawn on the surface when the plot gets rendered.
What am I missing?
The point you are looking for is there, but hidden "inside" the surface. This is a common problem in matplotlib.
I see two options here:
Make the surface plot semitransparent, i.e. use alpha=.8 or similar.
Use plot instead of scatter.