问题
How can I draw a “braced” line between two arbitrary points with Pyx?
It would look something like this:
Brace example http://tof.canardpc.com/view/d16770a8-0fc6-4e9d-b43c-a11eaa09304d
回答1:
You can draw pretty braces using sigmoidals. I don't have Pyx installed so I'll just plot these using matplotlib (pylab here). Here beta
controls the sharpness of the curves in the braces.
import numpy as nx
import pylab as px
def half_brace(x, beta):
x0, x1 = x[0], x[-1]
y = 1/(1.+nx.exp(-1*beta*(x-x0))) + 1/(1.+nx.exp(-1*beta*(x-x1)))
return y
xmax, xstep = 20, .01
xaxis = nx.arange(0, xmax/2, xstep)
y0 = half_brace(xaxis, 10.)
y = nx.concatenate((y0, y0[::-1]))
px.plot(nx.arange(0, xmax, xstep), y)
px.show()
I plotted this along the x-axis to save screen space, but to get braces along the y-axis just swap x and y. Finally, Pyx has plenty of path drawing functionality built-in which coould also work for your needs.
回答2:
tom10 provides a good solution, but could use some improvement.
The key is creates a brace over the range [0,1],[0,1] and then scale it.
This version also lets you tweak the shape a bit. For bonus points, it uses the second derivative to figure out how densely to space the points.
mid
sets the balance between the lower and upper parts.beta1
and beta2
control how sharp the curves (lower and upper) are.
You can change the height
(or just multiply y by a scalar).
Making it vertical instead of horizontal just involves swapping x and y.initial_divisions
and resolution_factor
govern how the x values are chosen, but should generally be ignorable.
import numpy as NP
def range_brace(x_min, x_max, mid=0.75,
beta1=50.0, beta2=100.0, height=1,
initial_divisions=11, resolution_factor=1.5):
# determine x0 adaptively values using second derivitive
# could be replaced with less snazzy:
# x0 = NP.arange(0, 0.5, .001)
x0 = NP.array(())
tmpx = NP.linspace(0, 0.5, initial_divisions)
tmp = beta1**2 * (NP.exp(beta1*tmpx)) * (1-NP.exp(beta1*tmpx)) / NP.power((1+NP.exp(beta1*tmpx)),3)
tmp += beta2**2 * (NP.exp(beta2*(tmpx-0.5))) * (1-NP.exp(beta2*(tmpx-0.5))) / NP.power((1+NP.exp(beta2*(tmpx-0.5))),3)
for i in range(0, len(tmpx)-1):
t = int(NP.ceil(resolution_factor*max(NP.abs(tmp[i:i+2]))/float(initial_divisions)))
x0 = NP.append(x0, NP.linspace(tmpx[i],tmpx[i+1],t))
x0 = NP.sort(NP.unique(x0)) # sort and remove dups
# half brace using sum of two logistic functions
y0 = mid*2*((1/(1.+NP.exp(-1*beta1*x0)))-0.5)
y0 += (1-mid)*2*(1/(1.+NP.exp(-1*beta2*(x0-0.5))))
# concat and scale x
x = NP.concatenate((x0, 1-x0[::-1])) * float((x_max-x_min)) + x_min
y = NP.concatenate((y0, y0[::-1])) * float(height)
return (x,y)
Usage is simple:
import pylab as plt
fig = plt.figure()
ax = fig.add_subplot(111)
x,y = range_brace(0, 100)
ax.plot(x, y,'-')
plt.show()
PS: Don't forget that you can pass clip_on=False
to plot
and put it outside of the axis.
来源:https://stackoverflow.com/questions/1289681/drawing-braces-with-pyx