문제

I want to have a circle in a plot made with pyplot, but I need to use a log scale on the x axis.

I do:

ax = plt.axes()

point1 = plt.Circle((x,y), x, color='r',clip_on=False, 
                    transform = ax.transAxes, alpha = .5)

plt.xscale('log')

current_fig = plt.gcf()

current_fig.gca().add_artist(point1)

As you see, I want the radius of the circle to be equal to the x coordinate.

My problem is that if I use, like written here, transAxes, then I get the circle to be actually a circle (otherwise it is stretched on the x and looks like an ellipse cut in half), but the x coordinate is 0. If, on the other hand, I use transData instead of transAxes, then I get the correct value for the x coordinate, but the circle is stretched again and cut in half.

I don't really mind the stretching but I don't like the cutting, I want it to be at least a full ellipse.

Any idea how to obtain what I want?

도움이 되었습니까?

해결책

Probably the easiest way to do this would be to just use a plot marker instead of a Circle. For example:

ax.plot(x,y,marker='o',ms=x*5,mfc=(1.,0.,0.,0.5),mec='None')

This will give you a circle that will always look 'circular' and will be centred on the correct x,y coordinate, although its size will bear no relationship to the x and y scales. If you just care about the centre position then you can mess around with ms= until it looks right.

A more general way to do this would be to construct a new composite transformation for the circle - you should take a look at this tutorial on transformations. Basically, the transformation from figure to data space is constructed like this:

transData = transScale + (transLimits + transAxes)

where transScale handles any nonlinear (e.g. logarithmic) scaling of the data, transLimits maps the x- and y-limits of the data into the unit space of the axes, and transAxes maps the corners of the axes bounding box into display space.

You want to keep the circle looking like a circle/ellipse (i.e. not distort it according to the logarithmic scaling of the x-axis), but you still want to translate it to the correct centre location in data coordinates. In order to do that, you can construct a scaled translation, then combine it with transLimits and transAxes:

from matplotlib.transforms import ScaledTranslation

ax = plt.axes(xscale='log')
x,y = 10,0
ax.set_ylim(-11,11)
ax.set_xlim(1E-11,1E11)

# use the axis scale tform to figure out how far to translate 
circ_offset = ScaledTranslation(x,y,ax.transScale)

# construct the composite tform
circ_tform = circ_offset + ax.transLimits + ax.transAxes

# create the circle centred on the origin, apply the composite tform
circ = plt.Circle((0,0),x,color='r',alpha=0.5,transform=circ_tform)
ax.add_artist(circ)
plt.show()

Obviously the scaling in the x-axis is going to be a bit weird and arbitrary - you'll need to play around with how you construct the transformation in order to get exactly what you want.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top