【问题标题】:draw horizontal bars on the same line在同一条线上绘制水平条
【发布时间】:2016-10-19 16:41:15
【问题描述】:

我必须画一个甘特资源类型的图表。 思路是在同一行(对应一个资源)上画几个水平条,每个长度用开始日期和日期表示

这是预期的结果:

我们总共有大约 200 种资源,最多。每个要显示 50 个任务,因此性能很重要。

有什么想法吗?

此外,任务应该可以用鼠标拖动。 一个解决方案(Fat GUI (pyQt, wxwidget, tkinter, ...) 或基于 Web 的 Flask、web2py 等)是可以的

【问题讨论】:

  • 基于 Web 的版本最终将使用 javascript 编写。至于 python 的 gui 库,我会推荐一个 Qt 绑定库或 tkinter。除此之外,我没有太多其他东西要给你,因为你没有向我们展示你尝试了什么或你遇到了什么问题
  • 我见过 python-gantt 和 matplotlib。问题是我不知道如何告诉 matplotlib(或其他工具)在同一条线上绘制一条线,即给出一个水平条的开始和结束位置。这几次为同一行。我在这里卡住了。因为我所看到和尝试过的所有示例,都将条形图绘制在彼此下方或绘制了堆叠的条形图,这显然是错误的,因为条形之间必须有一定的距离。
  • 要求我们推荐或查找书籍、工具、软件库、教程或其他非现场资源的问题对于 Stack Overflow 来说是题外话,因为它们往往会吸引固执己见答案和垃圾邮件。取而代之的是describe the problem 以及迄今为止为解决该问题所做的工作。
  • 您所描述的(动态拖动条形)在 matplotlib 中是*可能的,但它只是在画布上绘制矩形并为它们提供 event driven 重新定位函数而不是真正的条形图。 mpl 或任何其他 gui 库中的复杂性可能相似

标签: python bar-chart


【解决方案1】:

实际上,我会欺骗并直接从Matplotlib Documentation 向您发布一些内容。这应该让您开始使用 mpl 中的可拖动对象。你必须想出自己的动态对象创建代码......

感谢 mpl 的伙计们:

# draggable rectangle with the animation blit techniques; see
# http://www.scipy.org/Cookbook/Matplotlib/Animations
import numpy as np
import matplotlib.pyplot as plt

class DraggableRectangle:
    lock = None  # only one can be animated at a time
    def __init__(self, rect):
        self.rect = rect
        self.press = None
        self.background = None

    def connect(self):
        'connect to all the events we need'
        self.cidpress = self.rect.figure.canvas.mpl_connect(
            'button_press_event', self.on_press)
        self.cidrelease = self.rect.figure.canvas.mpl_connect(
            'button_release_event', self.on_release)
        self.cidmotion = self.rect.figure.canvas.mpl_connect(
            'motion_notify_event', self.on_motion)

    def on_press(self, event):
        'on button press we will see if the mouse is over us and store some data'
        if event.inaxes != self.rect.axes: return
        if DraggableRectangle.lock is not None: return
        contains, attrd = self.rect.contains(event)
        if not contains: return
        print('event contains', self.rect.xy)
        x0, y0 = self.rect.xy
        self.press = x0, y0, event.xdata, event.ydata
        DraggableRectangle.lock = self

        # draw everything but the selected rectangle and store the pixel buffer
        canvas = self.rect.figure.canvas
        axes = self.rect.axes
        self.rect.set_animated(True)
        canvas.draw()
        self.background = canvas.copy_from_bbox(self.rect.axes.bbox)

        # now redraw just the rectangle
        axes.draw_artist(self.rect)

        # and blit just the redrawn area
        canvas.blit(axes.bbox)

    def on_motion(self, event):
        'on motion we will move the rect if the mouse is over us'
        if DraggableRectangle.lock is not self:
            return
        if event.inaxes != self.rect.axes: return
        x0, y0, xpress, ypress = self.press
        dx = event.xdata - xpress
        dy = event.ydata - ypress
        self.rect.set_x(x0+dx)
        self.rect.set_y(y0+dy)

        canvas = self.rect.figure.canvas
        axes = self.rect.axes
        # restore the background region
        canvas.restore_region(self.background)

        # redraw just the current rectangle
        axes.draw_artist(self.rect)

        # blit just the redrawn area
        canvas.blit(axes.bbox)

    def on_release(self, event):
        'on release we reset the press data'
        if DraggableRectangle.lock is not self:
            return

        self.press = None
        DraggableRectangle.lock = None

        # turn off the rect animation property and reset the background
        self.rect.set_animated(False)
        self.background = None

        # redraw the full figure
        self.rect.figure.canvas.draw()

    def disconnect(self):
        'disconnect all the stored connection ids'
        self.rect.figure.canvas.mpl_disconnect(self.cidpress)
        self.rect.figure.canvas.mpl_disconnect(self.cidrelease)
        self.rect.figure.canvas.mpl_disconnect(self.cidmotion)

fig = plt.figure()
ax = fig.add_subplot(111)
rects = ax.bar(range(10), 20*np.random.rand(10))
drs = []
for rect in rects:
    dr = DraggableRectangle(rect)
    dr.connect()
    drs.append(dr)

plt.show()

【讨论】:

  • 这不是在同一行显示条形图。但是我从亚伦那里得到了解决方案,从你那里得到了处理。太好了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-19
  • 2017-03-29
  • 2012-05-20
  • 2020-02-25
  • 1970-01-01
  • 2013-04-29
相关资源
最近更新 更多