简体   繁体   English

如何在matplotlib中画一条线,使画线的边缘(而不是中心)跟随绘制的数据?

[英]How can draw a line in matplotlib so that the edge (not the center) of the drawn line follows the plotted data?

I'm working on a figure to show traffic levels on a highway map. 我正在研究一个数字,以在高速公路地图上显示交通水平。 The idea is that for each highway segment, I would plot two lines - one for direction. 想法是,对于每个高速公路路段,我都会绘制两条线-一条用于方向。 The thickness of each line would correspond to the traffic volume in that direction. 每条线的粗细将对应于该方向上的交通量。 I need to plot the lines so that the left edge (relative to driving direction) of the drawn line follows the shape of the highway segment. 我需要绘制线条,以使绘制的线条的左边缘(相对于行驶方向)遵循高速公路路段的形状。 I would like to specify the shape in data coordinates, but I would like to specify the thickness of the line in points. 我想在数据坐标中指定形状,但我想以点为单位指定线的粗细。

My data is like this: 我的数据是这样的:

[[((5,10),(-7,2),(8,9)),(210,320)],
 [((8,4),(9,1),(8,1),(11,4)),(2000,1900)],
 [((12,14),(17,14)),(550,650)]]

where, for example, ((5,10),(-7,2),(8,9)) is a sequence of x,y values giving the shape of a highway segment, and (210,320) is traffic volumes in the forward and reverse direction, respectively 其中,例如(((5,10),(-7,2),(8,9))是x,y值的序列,给出了高速公路路段的形状,而(210,320)是正向和反向

Looks matter: the result should be pretty. 看起来很重要:结果应该很漂亮。

I figured out a solution using matplotlib.transforms.Transform and shapely.geometry.LineString.parallel_offset . 我想出了一个使用matplotlib.transforms.Transformshapely.geometry.LineString.parallel_offset的解决方案。

Note that shapely's parallel_offset method can sometimes return a MultiLineString , which is not handled by this code. 请注意,shapely的parallel_offset方法有时可以返回MultiLineString ,此代码未处理。 I've changed the second shape so it does not cross over itself to avoid this problem. 我已经更改了第二个形状,因此它不会交叉以免发生此问题。 I think this problem would happen rarely happen in my application. 我认为这个问题在我的应用程序中很少发生。

Another note: the documentation for matplotlib.transforms.Transform seems to imply that the array returned by the transform method must be the same shape as the array passed as an argument, but adding additional points to plot in the transform method seems to work here. 另一个注意事项:matplotlib.transforms.Transform的文档似乎暗示transform方法返回的数组必须与作为参数传递的数组具有相同的形状,但是在transform方法中添加其他要绘制的点似乎可行。

#matplotlib version 1.1.0
#shapely version 1.2.14
#Python 2.7.3

import matplotlib.pyplot as plt
import shapely.geometry
import numpy
import matplotlib.transforms


def get_my_transform(offset_points, fig):
    offset_inches = offset_points / 72.0
    offset_dots = offset_inches * fig.dpi

    class my_transform(matplotlib.transforms.Transform):        

        input_dims = 2
        output_dims = 2
        is_separable = False
        has_inverse = False

        def transform(self, values):
            l = shapely.geometry.LineString(values)
            l = l.parallel_offset(offset_dots,'right')
            return numpy.array(l.xy).T

    return my_transform()


def plot_to_right(ax, x,y,linewidth, **args):

    t = ax.transData + get_my_transform(linewidth/2.0,ax.figure)

    ax.plot(x,y, transform = t,
            linewidth = linewidth,
            solid_capstyle = 'butt',
            **args)


data = [[((5,10),(-7,2),(8,9)),(210,320)],
 [((8,4),(9,1),(8,1),(1,4)),(2000,1900)],
 [((12,14),(17,16)),(550,650)]]


fig = plt.figure()
ax = fig.add_subplot(111)


for shape, volumes in data:

    x,y = zip(*shape)
    plot_to_right(ax, x,y, volumes[0]/100., c = 'blue')
    plot_to_right(ax, x[-1::-1],y[-1::-1], volumes[1]/100., c = 'green')
    ax.plot(x,y, c = 'grey', linewidth = 1)


plt.show()
plt.close()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM