模拟通过看板的工作流程

kanban-simulator的Python项目详细描述


运行看板系统模拟的助手。

目前没有gui,但在jupyter/ipython笔记本上运行良好,比如 (需要安装ipython[notebook]pandasnumpymatplotlibopenpyxel):

import random
import kanban_simulator.board as kb

# For rendering HTML output in an iPython notebook:
from IPython.display import display, HTML
%matplotlib inline

# For data analysis and plan view:
import pandas as pd
import numpy as np

def to_plan(board, start_date, finished_day, freq='W-MON'):
    """Use Pandas to print a week-by-week plan-like view showing
    what state each card was in each week.
    """

    grid = pd.DataFrame(
        index=[c.name for c in board.donelog.cards],
        columns=pd.date_range(start_date, freq='D', periods=finished_day)
    )

    for card in board.donelog.cards:
        for col, data in card.history.items():
            for day in data['dates']:
                grid.ix[card.name, day-1] = col.name

    return grid.resample(freq, label='left', axis=1).first().fillna("")

# Build a backlog with some epics.
# Stipulate that when the epic enters the "Build" sublane-column, it will
# split into a number of stories.

backlog = kb.Backlog(cards=[
        kb.Epic("Epic one", splits={'Build': random.randint(5, 10)}),
        kb.Epic("Epic two", splits={'Build': random.randint(10, 20)}),
        kb.Epic("Epic three", splits={'Build': 30}),
        kb.Epic("Epic four", splits={'Build': 50}),
        kb.Epic("Epic five", splits={'Build': 50}),
        kb.Epic("Epic six", splits={'Build': 50}),
        kb.Epic("Epic seven", splits={'Build': 50}),
    ])

# Create a lane and clone it so that we have two lanes with the same columns
# It has a lane-wide WIP limit (optional), and a series of columns
# operating on epics. The "Build" column has a sub-lane (or rather,
# might have one or more depending on the number of epics in this column,
# subject to WIP limits), which operates on stories. The epic itself splits
# into stories and becomes a backlog for these stories, as per the number of
# stories above.

lane_template = kb.Lane(
    name="<lane name>",
    wip_limit=3,
    columns=[
        kb.Column(
            name="Discovery",
            touch=lambda: random.randint(5, 10),
            wip_limit=1,
            card_type=kb.Epic
        ),
        kb.QueueColumn(
            name="Ready for Build",
            wip_limit=1,
            card_type=kb.Epic
        ),
        kb.SublaneColumn(
            name="Build",
            lane_template=kb.Lane(
                name="Build",
                columns=[
                    kb.Column(
                        name="Analysis",
                        touch=lambda: random.randint(1, 3),
                        wip_limit=3,
                        card_type=kb.Story
                    ),
                    kb.Column(
                        name="Development",
                        touch=lambda: random.randint(1, 4),
                        wip_limit=3,
                        card_type=kb.Story
                    ),
                    kb.Column(
                        name="Test",
                        touch=lambda: random.randint(1, 2),
                        wip_limit=3,
                        card_type=kb.Story
                    ),
                ],
            ),
            wip_limit=1,
            card_type=kb.Epic
        ),
        kb.Column(
            name="Final testing",
            touch=lambda: random.randint(1, 5),
            wip_limit=1,
            card_type=kb.Epic
        ),
    ]
)

lanes = [
    lane_template.clone(name="Team 1"),
    lane_template.clone(name="Team 2"),
]

# Create the board
board = kb.Board(
    name="Test simulation",
    lanes=lanes,
    backlog=backlog
)

# Show the Kanban board day by day. The board is a state machine,
# so when we iterate through it, the state changes. We use `clone()` to
# get a new copy so we can use the same `board` later.

for day, board_state in board.clone():
    print "Day", day
    board_html = board_state.to_html()

    # iPython notebook specific magic to print HTML
    display(HTML(board_html))

# If we only want the end state, we can just do:
days, board_state = board.clone().run_simulation()
print "It took", days, "days"

# The cards are in the `board_state.donelog.cards` list. They have
# attributes like `age` (total number of days), `dates` (dates the card
# was active), `touch` (number of days actually working on a card, as
# opposed to waiting), and `history` (a breakdown of `age`, `dates` and
# `touch`) by column name.

# We can also run a Monte Carlo simulation:
mc_results = board.run_monte_carlo_simulation(trials=100)

# We can do some data analysis on the finish dates of each
finishes = pd.Series([r[0] for r in mc_results])

print "Monte Carlo, after", len(mc_results), "loops. Quantiles:"
print finishes.quantile([0.5, 0.85, 0.95])

# Histogram of finishes
finishes.plot.hist()

# Board at the 85th percentile, output as a grid plan
day85, board85 = mc_results[int(len(mc_results) * 0.85)]

plan = to_plan(board85, '2016-06-01', day85)
display(HTML(plan.to_html()))

# Save to Excel (requires openpyxl)
plan.to_excel("simulation.xlsx", "Simulation")

更改日志

0.3-2016年6月3日
  • 中断:如果touchsplits值是一个函数,则将使用 作为论据的卡片。
  • 卡拆分现在可以是可调用的或数字(类似于 触摸
  • 新的列类型sharedwipcolumn(),它可以将多个列分组,以便 他们有一个共同的总WIP限制。
  • 修正了第一个车道在制品限制可以忽略的问题 列
0.2-2016年5月24日
  • cardhistory现在是ordereddict
  • 一个backlog现在可以通过card-source拥有一个链式的“父”backlog
0.1-2016年5月24日
  • 初始版本

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
javajavax。艾尔。PropertyNotFoundException:   java为什么通过TCP发送的文件比它本身包含的文件包含更多的数据?   java为什么字符开关/案例不起作用?   php到java连接器,在哪里可以找到好的连接器   需要帮助Java简单规则形状面积计算器和if语句吗   macos如何从newstyle Oracle Java OSX捆绑包结构启动帮助页?   java既然所有的类都扩展对象,而对象是一个类,那么对象如何扩展对象呢?   java从JavaPairdd<String,Tuple2<Integer,Integer>>转换为JavaPairdd<String,Integer>   java微调器值未从一个活动传递到另一个活动   参数化类型的java数组   java不提供类。getCanonicalName是否存在性能问题?   java输入键JTextField   为什么我不能在java中调用nextLine()方法两次?   JTextPane中的java JProgressBar   java如何获取Crudepository实例?   用于提取几个<div>标记的java正则表达式   java如何使用JUnit Testrunner生成html图像   Go中Java静态属性的等价性