Home | 简体中文 | 繁体中文 | 杂文 | Github | 知乎专栏 | Facebook | Linkedin | Youtube | 打赏(Donations) | About
知乎专栏

20.8. Netkiller SVG 图形库

下载地址: https://pypi.org/project/netkiller-chart

20.8.1. 安装

		
pip install netkiller-chart		
		
		

20.8.2. SVG 图形库

20.8.2.1. 基本用法

			
import os
import sys

try:
    from netkiller.svg.ScalableVectorGraphics import Svg
    from netkiller.svg.elements import Text, Line, Circle, Rectangle, Image, Path, Ellipse

except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    # print('-' * 20)
    svg = Svg(600, 600)
    # svg.link("style.css")
    svg.title("Test")
    svg.desc("https://www.netkiller.cn")
    # svg.append(Title("Hello world"))
    svg.symbol("shape1", Circle(25, 25, 25, "gery"))
    svg.append(Text(100, 200, "Hello world", klass="test"))
    svg.append(Line(100, 5, 100, 300, stroke="#006600"))
    svg.append(Circle(100, 200, 100, "red", fill="none"))
    svg.append(Rectangle(100, 200, 100, 100, "blue", fill="green"))
    svg.append(Rectangle(200, 200, 100, 100, style="stroke:#009900; fill: #00cc00"))
    svg.append(Image(300, 300, 100, 100, href="https://www.netkiller.cn/graphics/by-nc-sa.png"))
    svg.use(10, 10, "shape1")
    svg.use(100, 50, "shape1", style="stroke: #00ff00; fill: none;")
    svg.group(Text(10, 100, "Hello world", klass="test"))
    svg.append(Path('M100,100 L150,100 L150,150 Z'))
    svg.append(Path().D().M(10, 10).L(10, 15).L(20, 26).H(11).V(30).Z())
    svg.append(Line(100, 200, 300, 300, stroke="#006600"))
    svg.append(Ellipse(30, 30, 30, 15, style="stroke:#006600; fill:#00cc00"))

    svg.save('test.svg')


if __name__ == "__main__":
    # print('-' * 20)
    main()

			
			

20.8.2.2. 文本

			
svg.append(Text(100, 200, "Hello world", klass="test"))			
			
			

文本路径

			
import os
import sys


try:
    from netkiller.svg.ScalableVectorGraphics import Svg
    from netkiller.svg.elements import Text, Path, TextPath

except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    svg = Svg(viewBox="0 0 100 100")
    svg.title("Svg 图形库")
    svg.desc("https://www.netkiller.cn")
    svg.defs(Path(id="MyPath",
                  fill="none",
                  stroke="red",
                  d="M10,90 Q90,90 90,45 Q90,10 50,10 Q10,10 10,40 Q10,70 45,70 Q70,70 75,50"))
    text = Text()
    svg.append(text.append(TextPath(href="MyPath", text="Quick brown fox jumps over the lazy dog.")))
    svg.save('textpath.svg')


if __name__ == "__main__":
    main()
			
			
			

20.8.2.3. 画线

直线

		
svg.append(Line(100, 5, 100, 300, stroke="#006600"))		
		
			

折线

		
import os
import sys

try:
    from netkiller.svg.ScalableVectorGraphics import Svg
    from netkiller.svg.elements import Polyline, Polygon

except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    svg = Svg(800, 600)
    # svg.link("style.css")
    svg.title("Test")
    svg.desc("https://www.netkiller.cn")
    svg.append(Polyline("20,100 40,60 70,80 100,20", fill="none", stroke="black"))
    svg.append(Polyline((60, 30), (30, 15), style="stroke:#006600; fill:#00cc00"))
    svg.append(Polyline("0,0  30,0  15,30", style="stroke:#006600;"))
    svg.append(Polygon("10,0  60,0  35,50", style="stroke: #ff0000;stroke-width: 5;fill: #ff6666;"))
    svg.append(Polygon("60,20 100,40 100,80 60,100 20,80 20,40",
                       style="stroke: #0000ff;stroke-width: 5;stroke-opacity: 0.5;fill: none;"))

    svg.append(Polygon("50,5   100,5  125,30  125,80 100,105 50,105  25,80  25, 30",
                       style="stroke:#660000; fill:#cc3333; stroke-width: 3;"))
    svg.append(Polygon("100,10 40,180 190,60 10,60 160,180",
                       style="fill:lime;stroke:purple;stroke-width:5;fill-rule:nonzero;"))

    svg.save('polyline.svg')


if __name__ == "__main__":
    main()
		
		
			

20.8.2.4. 矩形

		
	svg.append(Rectangle(100, 200, 100, 100, "blue", fill="green"))
    svg.append(Rectangle(200, 200, 100, 100, style="stroke:#009900; fill: #00cc00"))		
		
			

20.8.2.5. 多边形

多边形

		
import os
import sys

# module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ".")
# sys.path.insert(1, module)
src = os.path.join(os.path.dirname(os.path.dirname(os.getcwd())), 'src')
sys.path.insert(1, src)
# print(src)
# print(module)

try:
    from netkiller.svg.ScalableVectorGraphics import Svg
    from netkiller.svg.elements import Polyline, Polygon

except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    svg = Svg(800, 600)
    # svg.link("style.css")
    svg.title("多边形")
    svg.desc("https://www.netkiller.cn")
    svg.append(Polyline("20,100 40,60 70,80 100,20", fill="none", stroke="black"))
    svg.append(Polyline((60, 30), (30, 15), style="stroke:#006600; fill:#00cc00"))
    svg.append(Polyline("0,0  30,0  15,30", style="stroke:#006600;"))
    svg.append(Polygon("10,0  60,0  35,50", style="stroke: #ff0000;stroke-width: 5;fill: #ff6666;"))
    svg.append(Polygon("60,20 100,40 100,80 60,100 20,80 20,40",
                       style="stroke: #0000ff;stroke-width: 5;stroke-opacity: 0.5;fill: none;"))

    svg.append(Polygon("50,5   100,5  125,30  125,80 100,105 50,105  25,80  25, 30",
                       style="stroke:#660000; fill:#cc3333; stroke-width: 3;"))
    svg.append(Polygon("100,10 40,180 190,60 10,60 160,180",
                       style="fill:lime;stroke:purple;stroke-width:5;fill-rule:nonzero;"))

    svg.save('polygon.svg')


if __name__ == "__main__":
    main()
		
		
			

20.8.2.6. 圆形

		
svg.append(Circle(100, 200, 100, "red", fill="none"))		
		
			

20.8.2.7. 椭圆形

		
import os
import sys

try:
    from netkiller.svg.ScalableVectorGraphics import Svg
    from netkiller.svg.elements import Text, Line, Circle, Rectangle, Image, Path, Ellipse

except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    svg = Svg(800, 600)
    # svg.link("style.css")
    svg.title("Test")
    svg.desc("https://www.netkiller.cn")
    svg.append(Ellipse(60, 30, 30, 15, style="stroke:#006600; fill:#00cc00"))
    svg.append(Ellipse(60, 80, 50, 30, style="stroke: #ff0000;stroke-width: 5;fill: none;"))

    svg.append(Ellipse(130, 160, 50, 30, style="stroke: #ff0000;stroke-width: 5;stroke-dasharray: 10 5;fill: none;"))
    svg.append(Ellipse(60, 160, 50, 30, style="stroke: #ff0000;stroke-width: 5;fill: #ff6666;"))

    svg.append(Ellipse(60, 250, 50, 30, style="stroke: #0000ff;stroke-width: 5;stroke-opacity: 0.5;fill: none;"))
    svg.append(Ellipse(160, 250, 50, 30, style="stroke: none; fill: #0000ff;fill-opacity: 0.5;"))

    svg.save('ellipse.svg')


if __name__ == "__main__":
    main()
		
		
			

20.8.2.8. 脚本

		
import os
import sys

# module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ".")
# sys.path.insert(1, module)
src = os.path.join(os.path.dirname(os.path.dirname(os.getcwd())), 'src')
sys.path.insert(1, src)
# print(src)
# print(module)

try:
    from netkiller.svg.ScalableVectorGraphics import Svg
    from netkiller.svg.elements import Text, Line, Circle, Rectangle, Image, Path, Ellipse

except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    svg = Svg(viewBox="0 0 10 10",
              height="120px",
              width="120px")
    # svg.link("style.css")
    svg.title("Svg 图形库")
    svg.desc("https://www.netkiller.cn")
    svg.append(Circle(cx="5", cy="5", r="4"))

    svg.script("""
    function getColor() {
      const R = Math.round(Math.random() * 255)
        .toString(16)
        .padStart(2, "0");

      const G = Math.round(Math.random() * 255)
        .toString(16)
        .padStart(2, "0");

      const B = Math.round(Math.random() * 255)
        .toString(16)
        .padStart(2, "0");

      return `#${R}${G}${B}`;
    }

    document.querySelector("circle").addEventListener("click", (e) => {
      e.target.style.fill = getColor();
    });
    """)

    svg.save('script.svg')


if __name__ == "__main__":
    main()
		
		
			

20.8.2.9. 多语言国际化

		
import os
import sys

try:
    from netkiller.svg.ScalableVectorGraphics import Svg
    from netkiller.svg.elements import Text, Line, Circle, Switch

except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    svg = Svg(viewBox="0 -20 100 50")
    svg.title("Svg 图形库")
    svg.desc("https://www.netkiller.cn")
    switch = Switch(Text("@"))
    switch.append(Text("مرحبا", systemLanguage="ar")).append(Text("Hallo!", systemLanguage="de,nl")).append(
        Text("Howdy!", systemLanguage="en-us")).append(Text("Wotcha! ", systemLanguage="en-gb")).append(
        Text("G'day!", systemLanguage="en-au")).append(Text("Hello!", systemLanguage="en")).append(
        Text("Hola!", systemLanguage="es")).append(Text("Bonjour!", systemLanguage="fr")).append(
        Text("こんにちは", systemLanguage="ja")).append(Text("zПривет! ", systemLanguage="ru")).append(
        Text("你好! ", systemLanguage="zh"))
    svg.append(switch)
    svg.save('switch.svg')


if __name__ == "__main__":
    main()
		
		
			

20.8.2.10. 蒙版

		
import os
import sys

# module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ".")
# sys.path.insert(1, module)
src = os.path.join(os.path.dirname(os.path.dirname(os.getcwd())), 'src')
sys.path.insert(1, src)
# print(src)
# print(module)

try:
    from netkiller.svg import Svg
    # from netkiller.svg.ScalableVectorGraphics import Svg
    from netkiller.svg.defs import Mask
    from netkiller.svg.elements import Text, Path, Rectangle

except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    svg = Svg(800, 600, viewBox="0 0 200 80", version="1.1")
    # svg.link("style.css")
    svg.title("Netkiller SVG Library")
    svg.desc("https://www.netkiller.cn")
    # mask = Mask(id="mask1", x="0", y="0", width="100", height="100")
    # mask.append(Rectangle(x="0", y="0", width="100", height="100", style="stroke:none; fill: #ffffff"))
    # svg.defs(mask)
    # svg.append(
    #     Rectangle(x="1", y="1", width="200", height="200", style="stroke: none; fill: #0000ff; mask: url(#mask1)"))

    mask = Mask(id="myMask", maskUnits="userSpaceOnUse",
                x="0", y="0", width="200", height="80")
    mask.append(Rectangle(x="0", y="0", width="100", height="80", fill="white"))
    svg.defs(mask)
    svg.defs(
        Text(id="Text", x="100", y="48", text="Black & White", font_size="26", font_weight="bold",
             text_anchor="middle"))
    svg.append(
        Rectangle(x="100", y="10", width="95", height="60"))
    svg.use(id="Text", fill="white")
    svg.use(id="Text", fill="black", mask="url(#myMask)")
    svg.save('mask.svg')


if __name__ == "__main__":
    main()
		
		
			

20.8.2.11. 滤镜

		
import os
import sys

# module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ".")
# sys.path.insert(1, module)
src = os.path.join(os.path.dirname(os.path.dirname(os.getcwd())), 'src')
sys.path.insert(1, src)
# print(src)
# print(module)

try:
    from netkiller.svg.ScalableVectorGraphics import Svg
    from netkiller.svg.elements import Circle
    from netkiller.svg.filter import Filter, feGaussianBlur


except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    svg = Svg(800, 600)
    # svg.link("style.css")
    svg.title("Test")
    svg.desc("https://www.netkiller.cn")
    filter = Filter(id="blurMe")
    filter.append(feGaussianBlur(inn="SourceGraphic", stdDeviation="5"))
    svg.defs(filter)

    svg.append(Circle(cx="170", cy="60", r="50", fill="green", filter="url(#blurMe)"))

    svg.save('filter.svg')


if __name__ == "__main__":
    main()
		
		
			
应用于文本
			
import os
import sys

# module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ".")
# sys.path.insert(1, module)
src = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.getcwd()))), 'src')
sys.path.insert(1, src)
# print(src)
# print(module)

try:
    from netkiller.svg.ScalableVectorGraphics import Svg
    from netkiller.svg.elements import Text, Group
    from netkiller.svg.filter import Filter, feOffset, feGaussianBlur, feColorMatrix, feComposite


except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    svg = Svg(800, 600)
    # svg.link("style.css")
    svg.title("Netkiller Python 手札")
    svg.desc("https://www.netkiller.cn")
    filter = Filter(id="text1")
    filter.append(feGaussianBlur(inn="SourceGraphic", stdDeviation="2", result="blur"))
    filter.append(
        feColorMatrix(inn="blur", mode="matrix", values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 19 -9", result="text1"))
    filter.append(feComposite(inn="SourceGraphic", in2="text1", operator="atop"))

    svg.defs(filter)
    g = Group(filter="url(#text1)")
    g.append(Text("Hello world", 100, 200, font_size=40, stroke="none", fill="red"))
    svg.append(g)

    svg.save('text.svg')


if __name__ == "__main__":
    main()
			
			
				
玻璃效果
			
import os
import sys

# module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ".")
# sys.path.insert(1, module)
src = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.getcwd()))), 'src')
sys.path.insert(1, src)
# print(src)
# print(module)

try:
    from netkiller.svg.ScalableVectorGraphics import Svg
    from netkiller.svg.elements import Rectangle, Group, Text
    from netkiller.svg.filter import Filter, feOffset, feGaussianBlur, feComposite, feColorMatrix, feBlend


except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    svg = Svg(800, 600)
    # svg.link("style.css")
    svg.title("Netkiller Python 手札")
    svg.desc("https://www.netkiller.cn")
    filter = Filter(id="glass", filterUnits="userSpaceOnUse", color_interpolation_filters="sRGB")
    filter.append(feColorMatrix(inn="SourceAlpha", type="matrix", values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
                                result="hardAlpha"))

    filter.append(feOffset(dx="4", dy="4"))
    filter.append(feGaussianBlur(stdDeviation="2"))
    filter.append(feColorMatrix(type="matrix", values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"))
    filter.append(feBlend(mode="normal", inn="SourceGraphic", in2="effect1_dropShadow_130_286", result="shape"))

    # 内
    filter.append(feOffset(dx="4", dy="4"))
    filter.append(feGaussianBlur(stdDeviation="2"))
    filter.append(feComposite(in2="hardAlpha", operator="arithmetic", k2="-1", k3="1"))
    filter.append(feColorMatrix(type="matrix", values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"))
    filter.append(feBlend(mode="normal", in2="shape", result="effect2_innerShadow_130_286"))

    filterText = Filter(id="text", filterUnits="userSpaceOnUse", color_interpolation_filters="sRGB").append(
        feColorMatrix(inn="SourceAlpha", type="matrix", values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0",
                      result="hardAlpha")
    ).append(
        feOffset(dx="4", dy="4")
    ).append(
        feGaussianBlur(stdDeviation="2")
    ).append(
        feComposite(in2="hardAlpha", operator="out")
    ).append(
        feColorMatrix(type="matrix", values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0")).append(
        feBlend(mode="normal", inn="SourceGraphic", in2="effect1_dropShadow_103_1497", result="shape")
    )

    svg.defs(filter, filterText)

    g = Group(filter="url(#glass)")
    g.append(Rectangle(x="1", y="1", width="600", height="60", stroke="none", fill="#D9D9D9"))
    g.append(Text("Netkiller Python 手札", 10, 40, font_size=30, stroke="none", fill="red", filter="url(#text)"))
    svg.append(g)
    svg.append(
        Rectangle(x="1", y="180", width="400", height="60", stroke="white", fill="#E23368", filter="url(#glass)"))
    svg.append(Rectangle(x="1",
                         y="90",
                         width="400",
                         height="70",
                         stroke="none",
                         fill="green",
                         filter="url(#glass)"))

    g = Group(filter="url(#glass)")
    g.append(Rectangle(x="10", y="250", width="600", height="30", stroke="none", fill="white"))
    g.append(
        Rectangle(x="15", y="255", width="400", height="20", stroke="none", fill="#E23368"))
    svg.append(g)

    svg.save('glass.svg')


if __name__ == "__main__":
    main()
			
			
				
偏移操作
			
import os
import sys

# module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ".")
# sys.path.insert(1, module)
src = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.getcwd()))), 'src')
sys.path.insert(1, src)
# print(src)
# print(module)

try:
    from netkiller.svg.ScalableVectorGraphics import Svg
    from netkiller.svg.elements import Rectangle
    from netkiller.svg.filter import Filter, feOffset


except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    svg = Svg(800, 600)
    # svg.link("style.css")
    svg.title("Test")
    svg.desc("https://www.netkiller.cn")
    filter = Filter(id="offset", width="180", height="180")
    filter.append(feOffset(inn="SourceGraphic", dx="60", dy="60"))

    svg.defs(filter)
    svg.append(Rectangle(x="0", y="0", width="100", height="100", stroke="black", fill="green"))
    svg.append(Rectangle(x="0",
                         y="0",
                         width="100",
                         height="100",
                         stroke="black",
                         fill="green",
                         filter="url(#offset)"))

    svg.save('feOffset.svg')


if __name__ == "__main__":
    main()
			
			
				

20.8.2.12. 色彩渐变

		
import os
import sys

# module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ".")
# sys.path.insert(1, module)
src = os.path.join(os.path.dirname(os.path.dirname(os.getcwd())), 'src')
sys.path.insert(1, src)
# print(src)
# print(module)

try:
    from netkiller.svg.ScalableVectorGraphics import Svg
    from netkiller.svg.elements import Text, Line, Circle, Rectangle, Image, Path, Ellipse
    from netkiller.svg.gradient import linearGradient, radialGradient, stop
except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    svg = Svg(viewBox="0 0 40 40",
              height="120px",
              width="120px")

    svg.title("Svg 图形库")
    svg.desc("https://www.netkiller.cn")

    linear = linearGradient(id="linearGradient", gradientTransform="rotate(90)")
    linear.append(stop(offset="5%", stop_color="gold"))
    linear.append(stop(offset="95%", stop_color="red"))

    radial = radialGradient(id="radialGradient")
    radial.append(stop(offset="10%", stop_color="gold"))
    radial.append(stop(offset="95%", stop_color="red"))

    svg.defs(linear, radial)
    svg.comment("using my linear gradient")
    svg.append(Circle(cx="5", cy="5", r="4", fill="url('#linearGradient')"))
    svg.comment("using my radial gradient")
    svg.append(Circle(cx="5", cy="20", r="4", fill="url('#radialGradient')"))

    svg.save('gradient.svg')


if __name__ == "__main__":
    main()
		
		
			

20.8.3. Gantt 甘特图

20.8.3.1. Markdown 生成 Gantt 甘特图

			
import os
import sys

module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ".")
sys.path.insert(1, module)

try:
    from src.netkiller.gantt import Gantt, Data
    from src.netkiller.markdown import Markdown

except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    text = """
    # Table
    | id | name | start | finish | resource | progress | predecessor | milestone | parent |
    |------|------|--------|
    | 1 | 测试麦克风 | 2025-07-01 | 2025-07-02 | 工程师 |
    | 2 | 设备送检 | 2025-07-03 | 2025-07-04   | 设计师 |
    | 3 | 完成包装 | 2025-07-05 | 2025-07-10   | 设计师 |
    | 4 | 竞品评估 | 2025-07-02 | 2025-07-04   | 设计师 |
    | 5 | 分析报告 | 2025-07-08 | 2025-07-15   | 设计师 |
    | 6 | 集成测试 | 2025-07-01 | 2025-07-06   | 设计师 |
    
    https://www.netkiller.cn/python/
        """

    # markdown = Markdown(text1)
    # items = markdown.table2dict()
    # print(items)
    # tmp = Data()
    # no = 1
    # for item in items:
    #     print(item)
    #     # tmp.add(item["id"], item["name"], item["start"], item["finish"], item["resource"],
    #     #         item["predecessor"], item["milestone"], item["parent"])
    #     tmp.add(no, item["name"], item["start"], item["finish"], item["resource"],
    #             None, None, None)
    #     no += 1
    # data = tmp.data
    # print(data)

    text1 = """
    # Table
    | id | name | start | finish | resource | predecessor | milestone | parent |
    |------|------|--------|
    | 1 | 测试麦克风 | 2025-07-01 | 2025-07-02 | 工程师 | 1 | False | 0 |
    | 2 | 设备送检 | 2025-07-03 | 2025-07-04   | 设计师 | 1 | False | 0 |
    | 3 | 完成包装 | 2025-07-05 | 2025-07-10   | 设计师 | 1 | False | 0 |
    | 4 | 竞品评估 | 2025-07-02 | 2025-07-04   | 设计师 | 1 | False | 0 |
    | 5 | 分析报告 | 2025-07-08 | 2025-07-15   | 设计师 | 1 | False | 0 |
    | 6 | 集成测试 | 2025-07-01 | 2025-07-06   | 设计师 | 1 | False | 0 |

    https://www.netkiller.cn/python/
    """

    # markdown = Markdown(text1)
    # data = markdown.gantt()
    # print(data)

    text2 = """
    ## 工作计划
    | 序号 | 任务名称 | 执行人 | 开始日期 | 结束日期 | 工时 |
    | :-----| :---- | :----: | :----: | :----: | :----: |
    | 1 | 1居家办公试行方案细则 | 发言人4 | 2025-08-06 | 2025-08-07 | 1.5天 |
    | 2 | 虚拟白板系统操作指南 | 技术部张磊 | 2025-08-07 | 2025-08-09 | 2天 |
    | 3 | 每日站会制度设计 | 周经理 | 2025-08-06 | 2025-08-06 | 0.5天 |
    | 4 | 行政支持清单 | 行政部门 | 2025-08-06 | 2025-08-07 | 1天 |
    | 5 | 效率对比分析表 | 数据分析组 | 2025-08-08 | 2025-08-09 | 1.5天 |
    | 6 | 成本核算模型 | 财务部 | 2025-08-09 | 2025-08-10 | 1天 |
    | 7 | 满意度问卷 | HR部门 | 2025-08-11 | 2025-08-12 | 1天 |
    | 8 | 焦点小组计划 | 市场部 | 2025-08-12 | 2025-08-13 | 0.5天 |
    """

    text3 = """
## 工作计划
| 序号 | 任务名称 | 执行人 | 开始日期 | 结束日期 | 工时 |
| :-----| :---- | :----: | :----: | :----: | :----: |
| 1 | 制定居家办公试行方案的具体实施细则 | 周经理 | 2025-09-04 | 2025 | 2.5天/人 |
| 2 | 行政部门统计居家办公数据 | 行政部门 | 2025-09-04 | 2025-09-08 | 1.5天/人 |
| 3 | 评估居家办公对员工身心健康的影响 | 人力资源部 | 2025-09-08 | 2025-09-12 | 3天/人 |
| 4 | 优化虚拟白板系统的使用体验 | IT部门 | 2025-09-15 | 2025-09-19 | 2天/人 |    
    """

    markdown = Markdown(text3)
    items = markdown.table2dict()
    # print(items)
    tmp = Data()
    no = 1
    for item in items:
        # print(item)
        # tmp.add(item["id"], item["name"], item["start"], item["finish"], item["resource"],
        #         item["predecessor"], item["milestone"], item["parent"])
        tmp.add(item["序号"], item["任务名称"], item["开始日期"], item["结束日期"], item["执行人"],
                0, None, None, None)
        no += 1
    data = tmp.data
    # print(data)
    try:

        gantt = Gantt(data)
        # gantt.hideTable()
        gantt.author("Neo Chen")
        # gantt.setWorkweeks(workweeks, options.oddeven)
        gantt.title("Test")
        gantt.legend(False)
        gantt.save("markdown.svg")
    except KeyboardInterrupt as e:
        print(e)
    except Exception as e:
        print(e)


if __name__ == "__main__":
    main()
			
			
			

例子二

			
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
##############################################
# Home	: https://www.netkiller.cn
# Author: Neo <netkiller@msn.com>
# Data: 2025-08-04
##############################################
import os
import sys

module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ".")
sys.path.insert(1, module)
src = os.path.join(os.path.dirname(os.path.dirname(os.getcwd())), 'src')
sys.path.insert(2, src)
print()
# print(module)

try:
    from netkiller.gantt import Gantt
    from netkiller.markdown import Markdown

except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    text = """
    # Table
    | id | name | start | finish | resource | progress | predecessor | milestone | parent |
    |------|------|--------|
    | 1 | 测试麦克风 | 2025-07-01 | 2025-07-02 | 工程师 | 1 | 0 | False | 0 |
    | 2 | 设备送检 | 2025-07-03 | 2025-07-04   | 设计师 | 1 | 1 | False | 0 |
    | 3 | 完成包装 | 2025-07-05 | 2025-07-10   | 设计师 | 1 | 1 | False | 0 |
    | 4 | 竞品评估 | 2025-07-02 | 2025-07-04   | 设计师 | 1 | 0 | True | 0 |
    | 5 | 分析报告 | 2025-07-08 | 2025-07-15   | 设计师 | 1 | 0 | False | 0 |
    | 6 | 集成测试 | 2025-07-01 | 2025-07-06   | 设计师 | 1 | 0 | False | 0 |

    https://www.netkiller.cn/python/
    """

    markdown = Markdown(text)
    data = markdown.gantt()

    print(data)
    try:

        gantt = Gantt(data)
        # gantt.hideTable()
        gantt.author("Neo Chen")
        gantt.setWorkweeks(6, 1)
        gantt.title("Test")
        # gantt.legend(False)
        # gantt.blank(True)
        gantt.save("markdown1.svg")
    except KeyboardInterrupt as e:
        print(e)
    except Exception as e:
        print(e)


if __name__ == "__main__":
    main()
			
			
			

20.8.3.2. 使用 CSV 数据生成 Gantt 甘特图

			
import os
import sys

# module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# sys.path.insert(0, ".")
# sys.path.insert(1, module)
src = os.path.join(os.path.dirname(os.path.dirname(os.getcwd())), 'src')
sys.path.insert(2, src)
# print(src)
# print(module)


try:
    from netkiller.data import Data
    from netkiller.gantt import Gantt

except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    text = """id,name,start,finish,resource,progress,parent,predecessor,milestone
1,任务组,2023-03-01,2023-03-10,admin,1,0,0,FALSE
2,aaa,2023-03-03,2023-03-04,test,0,1,0,FALSE
3,bbb,2023-03-05,2023-03-07,,0,1,2,FALSE
4,ccc,2023-03-08,2023-03-10,test,0,1,3,FALSE
5,ddd,2023-03-08,2023-03-10,,2,1,3,FALSE
6,aaa,2023-03-11,2023-03-20,test,2,0,0,FALSE
7,aaabbb,2023-03-02,2023-03-03,closed,0,1,0,TRUE
8,eeeee,2023-03-10,2023-03-13,,4,0,0,TRUE
9,主任务主任务主任务,2023-03-10,2023-03-19,,0,0,0,FALSE
10,子任务1,2023-03-10,2023-03-11,test,0,9,5,FALSE
11,子任务2,2023-03-12,2023-03-14,test,0,9,10,FALSE
12,子任务3,2023-03-15,2023-03-19,test,0,9,11,FALSE
13,任务3,2023-03-15,2023-03-19,test,0,0,0,FALSE"""

    csv = Data()
    data = csv.csvtext(text)

    print(data)
    try:

        gantt = Gantt(data)
        # gantt.hideTable()
        gantt.author("Neo Chen")
        # gantt.setWorkweeks(6, 1)
        gantt.title("甘特图测试")
        # gantt.legend(False)
        # gantt.blank(True)
        gantt.department("技术研发部")
        gantt.save("csv.svg")
    except KeyboardInterrupt as e:
        print(e)
    except Exception as e:
        print(e)


if __name__ == "__main__":
    main()
			
			
			

20.8.4. 工作负载图

		
import os
import sys

# module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# sys.path.insert(0, ".")
# sys.path.insert(1, module)
src = os.path.join(os.path.dirname(os.path.dirname(os.getcwd())), 'src')
sys.path.insert(2, src)
# print(src)
# print(module)


try:
    import io
    from netkiller.data import Data
    from netkiller.workload import Workload

except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    text = """id,name,start,finish,resource,progress,parent,predecessor,milestone
1,任务组,2023-03-01,2023-03-10,tom,1,0,0,FALSE
2,UI设计,2023-03-03,2023-03-04,neo,0,1,0,FALSE
3,测试环境部署,2023-03-05,2023-03-07,jerry,0,1,2,FALSE
4,后台开发,2023-03-08,2023-03-10,neo,0,1,3,FALSE
5,生产环境部署,2023-03-08,2023-03-10,jerry,2,1,3,FALSE
6,提示词优化,2023-03-15,2023-03-20,neo,2,0,0,FALSE
7,Android适配,2023-03-02,2023-03-03,jam,0,1,0,TRUE
8,安卓接口开发,2023-03-10,2023-03-13,jam,4,0,0,TRUE
9,主任务,2023-03-10,2023-03-17,陈景峰,0,0,0,FALSE
10,子任务1,2023-03-01,2023-03-04,test,0,9,5,FALSE
11,子任务2,2023-03-07,2023-03-09,test,0,9,10,FALSE
12,子任务3,2023-03-16,2023-03-17,test,0,9,11,FALSE
13,任务3,2023-03-15,2023-03-19,test,0,0,0,FALSE
"""
    try:
        text = "id,name,start,finish,resource,progress,parent,predecessor,milestone"
        with io.StringIO(text) as csv:
            workload = Workload()
            data = workload.csv2workload(csv)
            # print(data)
            workload.title("工作负载图")
            workload.department("技术研发部")
            workload.setWorkweeks(6, 1)
            # workload.workload()
            workload.save("workload1.svg")


    except KeyboardInterrupt as e:
        print(e)
    except Exception as e:
        print(e)


if __name__ == "__main__":
    main()
		
		
		

20.8.5. 思维导图

		
import os
import sys

src = os.path.join(os.path.dirname(os.path.dirname(os.getcwd())), 'src')
sys.path.insert(2, src)

from netkiller.markdown import Markdown
from netkiller.mindmap import Mindmap

data = """
# 操作系统
- Operating System
  - Linux
    - Redhat
    - CentOS
    - Rocky Linux
  - Apple OS  
    - macOS
      - nojava
      - catalina
    - iPadSO
    - tvOS 
    - iOS
    - watchOS 
  - Unix
    - Solaris
    - Aix
    - Hp-Ux
    - Sco Unix
"""

markdown = Markdown(data)
jsonData = markdown.mindmap()

mindmap = Mindmap("")
mindmap.save('demo.svg')
		
		
		

xmind 格式

		
from netkiller.markdown import Markdown

from src.netkiller.mindmap import Mindmap


def main():
    data = """# Netkiller Linux 手札
- Linux
  - Redhat
  - CentOS
  - Rocky Linux
  - AlmaLinux
    """

    markdown = Markdown(data)
    jsonData = markdown.mindmap()

    mindmap = Mindmap(jsonData)
    mindmap.xmind('none.xmind', 'test.xmind')


if __name__ == "__main__":
    main()
		
		
		

20.8.6. 石川鱼骨图

		
import os
import sys

# module = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# sys.path.insert(0, ".")
# sys.path.insert(1, module)
src = os.path.join(os.path.dirname(os.path.dirname(os.getcwd())), 'src')
sys.path.insert(2, src)
# print(src)
# print(module)


try:
    import io
    from netkiller.fishbone import Fishbone
    from netkiller.markdown import Markdown

except ImportError as err:
    print("Error: %s" % (err))
    exit()


def main():
    text = """
# 石川鱼骨图
- 产品目标
  - 竞品分析
  - 品牌形象
  - 产品生命周期
  - 发现了一个名
- 开发目标
  - 编码开发
  - 代码测试
- 运营目标
  - 区域投放
- 运营目标1
  - 区域投放1
  - 区域投放2
  - 区域投放3
  - 区域投放4
  - 区域投放5
- 运营目标1运营
  - 区域投放11
  - 区域投放21    
  - 区域投放31区域投放31
  - 区域投放41
  - 区域投放51
- 区域投放513
  - 竞品分析
  - 品牌形象
  - 产品生命周期
  - 发现了一个名
  - 区域投放3
  - 区域投放4
  - 区域投放5
- 运营目标1运营99
  - 区域投放11
  - 区域投放21
  - 区域投放31  
        """

    text2 = """
    
- 区域投放31区域投放31
  - 产品生命周期产品生命周期产品生命周期产品生命周期
  - 产品生命周期产品生命周期产品生命周期产品生命周期
  - 产品生命周期
- 产品生命周期
  - 发现了一个名
  - 区域投放3
  - 区域投放4生命周期产品
- 生命周期产品生命周生命周期产品生命周期产品
  - 生命周生命周期产品生命周期产品生命周
  - 区域投放5
- 运营目标1运营99
  - 区域投放11
  - 区域投放21
  - 区域投放31    
    """
    #     - 运营目标1运营99
    #     - 区域投放11
    #     - 区域投放21
    #     - 区域投放31
    #     - 区域投放513
    #     - 竞品分析
    #     - 品牌形象
    #
    #
    test3 = """
- 居家办公效率问题
  - 任务量暴涨导致延期
  - 办公室频繁被打断影响专注
  - 通勤时间占用导致加班成本增加
  - 协作工具操作不熟练
  - 缺少工作与生活的时间界限

- 居家办公体验问题
  - 缺少升降桌等办公设备
  - 缺乏零食水果等福利
  - 需要自行解决饮食问题
  - 缺少运动场景
  - 社交交流减少

- 居家办公试行方案执行问题
  - 试行时间周期较短
  - 到岗与居家天数分配可能不合理
  - 申请流程存在滞后性
  - 视频会议系统使用频率过高
  - 行政部门统计工作负荷增加    
    """
    text1 = """
- 如何提高移山效率
  - 工具选择单一
  - 缺乏现代化设备
  - 人力劳动强度大
  - 缺乏团队协作
  - 未考虑环境影响

- 移山工具优化方案
  - 传统工具效率低下
  - 未引入机械作业
  - 工具维护不足
  - 工具使用培训缺乏
  - 工具更新不及时  

    """
    text4 = """
- 工具选择低效
  - 缺乏现代化设备
  - 仅依赖传统工具
  - 未评估工具效率

- 人力成本过高
  - 过分依赖人工操作
  - 未考虑机械化替代方案
  - 劳动力分配不合理

- 工程进度缓慢
  - 工具效率低下
  - 缺乏科学施工规划
  - 未制定明确时间表

- 施工方法单一
  - 局限于传统挖掘方式
  - 未考虑爆破等现代技术
  - 缺乏多方法协同作业    
    """

    text5 = """
- 居家办公影响工作效率
  - 任务量暴涨导致延期
  - 办公室频繁被打断
  - 通勤时间占用导致加班费增加
- 居家办公造成生活作息紊乱
  - 缺乏场景切换导致时间管理混乱
  - 报复性熬夜现象严重
  - 没有固定上下班时间界限
- 居家办公设备条件不足
  - 缺乏专业办公桌椅
  - 长时间通话设备不适
  - 缺少办公室零食补给
- 居家办公影响身心健康
  - 缺乏运动空间和动力
  - 饮食规律被打破
  - 社交活动骤减
- 协作工具使用问题
  - 虚拟白板系统操作不熟练
  - 新工具需要适应期
  - 缺乏现场协作的即时性
- 成本控制问题
  - 加班费支出增加
  - 需要额外设备投入
  - 通勤补贴计算困难
- 工作生活界限模糊
  - 无法区分工作和休息空间
  - 工作时间内易受家庭事务干扰
  - 缺少同事监督机制
- 团队沟通效率下降
  - 视频会议替代现场会议效果欠佳
  - 非正式沟通渠道减少
  - 信息同步存在延迟
- 试行方案执行困难
  - 自主选择机制不明确
  - 申请流程复杂
  - 考勤管理难度增大
- 技术支持不足
  - 系统稳定性待验证
  - IT支持响应速度慢
  - 家庭网络环境差异大
"""
    # markdown = Markdown()
    # data = markdown.fishbone()
    # print(data)
    fishbone = Fishbone()

    fishbone.title("石川鱼骨图")
    fishbone.department("技术研发部")
    # fishbone.border(5)
    fishbone.legend(False)
    # fishbone.markdown(test3)
    # fishbone.save("test3.svg")
    #
    # fishbone.markdown(text2)
    # fishbone.save("test2.svg")
    #
    # fishbone.markdown(text)
    # fishbone.save("test1.svg")
    #
    # fishbone.markdown(text1)
    # fishbone.save("test1.svg")
    #
    # fishbone.markdown(text4)
    # fishbone.save("test4.svg")

    fishbone.markdown(text5)
    fishbone.save("test5.svg")
    # fishbone.debug()
    # print(fishbone.show())


if __name__ == "__main__":
    main()