Python matplotlib 中的中心原点
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4694478/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Center origin in matplotlib
提问by Milo Wielondek
I need help customizing my plots. I want the canvas to look approximately like the default 2D-graph template from MacOS's Grapher (see screenshot).
我需要帮助自定义我的情节。我希望画布看起来与 MacOS Grapher 中的默认 2D 图形模板大致相同(请参见屏幕截图)。


To clarify - I need
澄清 - 我需要
- a centered axis
- a grid (preferably with an additional darker grid every 1 unit)
- axislines with arrows
- only one zero at the origo (when I tried my best, I got one zero from the x-axis and a second one from the y-axis.), slightly moved to the left so it's not behind the y-axis
- 一个中心轴
- 一个网格(最好每 1 个单位附加一个较暗的网格)
- 带箭头的轴线
- 在原点只有一个零(当我尽力而为时,我从 x 轴得到了一个零,从 y 轴得到了第二个零。),稍微向左移动,所以它不在 y 轴后面
I really appreciate your help!
我真的很感谢你的帮助!
采纳答案by Joe Kington
This definitely falls under the category of more trouble than it's worth with matplotlib, but here you go. Also, for the basic case, have a look at the centering spines demo in the documentation.
这绝对属于比使用 matplotlib 更麻烦的类别,但是你去吧。此外,对于基本情况,请查看文档中的居中脊柱演示。
You can do this in a few different ways, but for the best visual effect, consider something along the lines of the following. It's far from perfect, but it's reasonably flexible:
您可以通过几种不同的方式执行此操作,但为了获得最佳视觉效果,请考虑以下内容。它远非完美,但它相当灵活:
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.patheffects
import numpy as np
def center_spines(ax=None, centerx=0, centery=0):
"""Centers the axis spines at <centerx, centery> on the axis "ax", and
places arrows at the end of the axis spines."""
if ax is None:
ax = plt.gca()
# Set the axis's spines to be centered at the given point
# (Setting all 4 spines so that the tick marks go in both directions)
ax.spines['left'].set_position(('data', centerx))
ax.spines['bottom'].set_position(('data', centery))
ax.spines['right'].set_position(('data', centerx - 1))
ax.spines['top'].set_position(('data', centery - 1))
# Draw an arrow at the end of the spines
ax.spines['left'].set_path_effects([EndArrow()])
ax.spines['bottom'].set_path_effects([EndArrow()])
# Hide the line (but not ticks) for "extra" spines
for side in ['right', 'top']:
ax.spines[side].set_color('none')
# On both the x and y axes...
for axis, center in zip([ax.xaxis, ax.yaxis], [centerx, centery]):
# Turn on minor and major gridlines and ticks
axis.set_ticks_position('both')
axis.grid(True, 'major', ls='solid', lw=0.5, color='gray')
axis.grid(True, 'minor', ls='solid', lw=0.1, color='gray')
axis.set_minor_locator(mpl.ticker.AutoMinorLocator())
# Hide the ticklabels at <centerx, centery>
formatter = CenteredFormatter()
formatter.center = center
axis.set_major_formatter(formatter)
# Add offset ticklabels at <centerx, centery> using annotation
# (Should probably make these update when the plot is redrawn...)
xlabel, ylabel = map(formatter.format_data, [centerx, centery])
ax.annotate('(%s, %s)' % (xlabel, ylabel), (centerx, centery),
xytext=(-4, -4), textcoords='offset points',
ha='right', va='top')
# Note: I'm implementing the arrows as a path effect rather than a custom
# Spines class. In the long run, a custom Spines class would be a better
# way to go. One of the side effects of this is that the arrows aren't
# reversed when the axes are reversed!
class EndArrow(mpl.patheffects._Base):
"""A matplotlib patheffect to add arrows at the end of a path."""
def __init__(self, headwidth=5, headheight=5, facecolor=(0,0,0), **kwargs):
super(mpl.patheffects._Base, self).__init__()
self.width, self.height = headwidth, headheight
self._gc_args = kwargs
self.facecolor = facecolor
self.trans = mpl.transforms.Affine2D()
self.arrowpath = mpl.path.Path(
np.array([[-0.5, -0.2], [0.0, 0.0], [0.5, -0.2],
[0.0, 1.0], [-0.5, -0.2]]),
np.array([1, 2, 2, 2, 79]))
def draw_path(self, renderer, gc, tpath, affine, rgbFace):
scalex = renderer.points_to_pixels(self.width)
scaley = renderer.points_to_pixels(self.height)
x0, y0 = tpath.vertices[-1]
dx, dy = tpath.vertices[-1] - tpath.vertices[-2]
azi = np.arctan2(dy, dx) - np.pi / 2.0
trans = affine + self.trans.clear(
).scale(scalex, scaley
).rotate(azi
).translate(x0, y0)
gc0 = renderer.new_gc()
gc0.copy_properties(gc)
self._update_gc(gc0, self._gc_args)
if self.facecolor is None:
color = rgbFace
else:
color = self.facecolor
renderer.draw_path(gc0, self.arrowpath, trans, color)
renderer.draw_path(gc, tpath, affine, rgbFace)
gc0.restore()
class CenteredFormatter(mpl.ticker.ScalarFormatter):
"""Acts exactly like the default Scalar Formatter, but yields an empty
label for ticks at "center"."""
center = 0
def __call__(self, value, pos=None):
if value == self.center:
return ''
else:
return mpl.ticker.ScalarFormatter.__call__(self, value, pos)
I deliberately didn't set the x and y major tick intervals to 1, but that's easy to do. ax.xaxis.set_major_locator(MultipleLocator(1))
我故意没有将 x 和 y 主要刻度间隔设置为 1,但这很容易做到。 ax.xaxis.set_major_locator(MultipleLocator(1))
Now you can just call center_spinesto do something like this:
现在你可以打电话center_spines做这样的事情:
x = np.arange(-5, 5)
y = x
line, = plt.plot(x, y)
center_spines()
plt.axis('equal')
plt.show()


回答by ev-br
Centered axes, see an example here (look for "zeroed spines"): http://matplotlib.sourceforge.net/examples/pylab_examples/spine_placement_demo.html
中心轴,请参见此处的示例(查找“归零的脊椎”):http: //matplotlib.sourceforge.net/examples/pylab_examples/spine_placement_demo.html
grid: ax.grid(True)
网格:ax.grid(真)
Get rid of the zero at the origin: see set_ticks(...) here: http://matplotlib.sourceforge.net/api/axis_api.html
摆脱原点的零:请参阅此处的 set_ticks(...):http://matplotlib.sourceforge.net/api/axis_api.html
What else did you look for?
你还找了什么?

