Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python matplotlib连接到地物缩放的路径线宽_Python_Python 3.x_Matplotlib - Fatal编程技术网

Python matplotlib连接到地物缩放的路径线宽

Python matplotlib连接到地物缩放的路径线宽,python,python-3.x,matplotlib,Python,Python 3.x,Matplotlib,是否可以将matplotlib路径的线宽与地物缩放/比例级别绑定 我正在绘制一张地图,其中matplotlib路径(带有贝塞尔曲线)在地图上绘制道路。放大后,我想放大路径的宽度 在附加脚本中,多边形近似可以正确缩放,但路径(红线)无法缩放(宽度) 是否可以通过回调将线宽绑定到某些缩放变换和重画 import matplotlib.pyplot as plt from matplotlib.path import Path import matplotlib.patches as patches

是否可以将matplotlib路径的线宽与地物缩放/比例级别绑定

我正在绘制一张地图,其中matplotlib路径(带有贝塞尔曲线)在地图上绘制道路。放大后,我想放大路径的宽度

在附加脚本中,多边形近似可以正确缩放,但路径(红线)无法缩放(宽度)

是否可以通过回调将线宽绑定到某些缩放变换和重画

import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches
import numpy as np

def main():
  ax = plt.subplot(111)
  verts = np.array([ (0., 0.), (0.5, .5), (1., 0.8), (0.8, 0.)])
  codes = np.array([Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.LINETO ])

  # Can this curve have zoomable width
  path = Path(verts, codes)
  patch = patches.PathPatch(path, fc='none', color='r', lw=4, zorder=3)
  ax.add_patch(patch)

  ax.plot(verts[:,0], verts[:,1], 'o--', lw=2, color='k', zorder=2)

  # these will be polygonal approx that will have proper zoom
  v=np.array([]).reshape((-1,2))
  c=[]
  for i in range(len(verts)-1):
    vtmp, ctmp = line2poly(verts[[i,i+1],:],0.03)
    v = np.vstack( (v,vtmp) )
    c = np.concatenate( (c,ctmp) )
  path_zoom = Path(v,c)
  patch_zoom =  patches.PathPatch(path_zoom, fc='r', ec='k', zorder=1, alpha=0.4)
  ax.add_patch(patch_zoom)

  ax.set_xlim(-0.1, 1.1)
  ax.set_ylim(-0.1, 1.1)
  plt.show()

def line2poly(line, width):
  dx,dy = np.hstack(np.diff(line,axis=0)).tolist()
  theta = np.arctan2(dy,dx)
  print(np.hstack(np.diff(line,axis=0)).tolist())
  print(np.degrees(theta))
  s = width/2 * np.sin(theta)
  c = width/2 * np.cos(theta)
  trans = np.array([(-s,c),(s,-c),(s,-c),(-s,c)])

  verts = line[[0,0,1,1],:]+trans
  verts = np.vstack((verts, verts[0,:]))
  codes = np.array([Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY])
  return verts,codes

if __name__=='__main__':
  main()

据我所知,在matplotlib中无法做到这一点,因为直线的笔划宽度不能直接与数据坐标关联。(正如您所提到的,您可以将回调连接到draw事件并完成此操作。但是,这将导致巨大的性能损失。)

但是,一个快速的解决方法是使用
shapely
通过缓冲街道路径来生成多边形

举个简单的例子:

import shapely.geometry
import descartes
import matplotlib.pyplot as plt

lines = ([(0, 0), (1, 0), (0, 1)],
         [(0, 0), (1, 1)],
         [(0.5, 0.5), (1, 0.5)],
         )
lines = shapely.geometry.MultiLineString(lines)
# "0.05" is the _radius_ in data coords, so the width will be 0.1 units.
poly = lines.buffer(0.05)

fig, ax = plt.subplots()
patch = descartes.PolygonPatch(poly, fc='gray', ec='black')
ax.add_artist(patch)

# Rescale things to leave a bit of room around the edges...
ax.margins(0.1)

plt.show()

如果确实希望采用回调路由,可以执行以下操作:

import matplotlib.pyplot as plt

def main():
    lines = ([(0, 0), (1, 0), (0, 1)],
             [(0, 0), (1, 1)],
             [(0.5, 0.5), (1, 0.5)],
             )

    fig, ax = plt.subplots()
    artists = []
    for verts in lines:
        x, y = zip(*verts)
        line, = ax.plot(x, y)
        artists.append(line)

    scalar = StrokeScalar(artists, 0.1)
    ax.callbacks.connect('xlim_changed', scalar)
    ax.callbacks.connect('ylim_changed', scalar)

    # Rescale things to leave a bit of room around the edges...
    ax.margins(0.05)

    plt.show()

class StrokeScalar(object):
    def __init__(self, artists, width):
        self.width = width
        self.artists = artists
        # Assume there's only one axes and one figure, for the moment...
        self.ax = artists[0].axes
        self.fig = self.ax.figure

    def __call__(self, event):
        """Intended to be connected to a draw event callback."""
        for artist in self.artists:
            artist.set_linewidth(self.stroke_width)

    @property
    def stroke_width(self):
        positions = [[0, 0], [self.width, self.width]]
        to_inches = self.fig.dpi_scale_trans.inverted().transform
        pixels = self.ax.transData.transform(positions)
        points = to_inches(pixels) * 72
        return points.ptp(axis=0).mean() # Not quite correct...

main()

plt.quiver
以某种方式做到了这一点,但我不知道如何利用这些信息:Phmmm。。。。plt.quiver不适合我。@askewchan-
quiver
这样做是因为它使用多边形而不是路径(即箭头没有笔划,而是多边形)。啊,谢谢@Joe,这很有意义。有可能以匀称的方式绘制bezier曲线并放大/缓冲它们吗?@waqy-没有,
shapely
将直线视为直线段。你得估计一下。我用基于回调的方法更新了我的答案,只使用matplotlib(除非纵横比设置为1,否则它完全正确)。谢谢。您基于回调的方案非常有效(也适用于曲线和文本)。很高兴它有帮助!在某些情况下,它有一些奇怪之处,我不太明白。此外,在我之前的评论中,我的意思是说“除非纵横比设置为1,否则它并不完全正确”。更光明的是,我提到的“巨大的性能损失”结果是完全无关紧要的。这就是我在尝试之前猜测的结果!