Tes*_*est 5 python svg pydot pandas
我有个问题。我想创建一个带有热图的流程。查看每个步骤花费了多长时间。我创建了该流程并为各个步骤PyDot
创建了一个。dataframe
如何为我的流程创建热图?
计算还应包括每一步的时间。因此,您可以计算边缘时间,例如task1_start - start
/task2_start - task1_end
并且您可以计算节点时间,例如task1_end - task1_start
/ task2_end - task2_start
。
我的 MVP 只改变边框的颜色。但我想创建一个真正的热图。
过程
import pydot
from IPython.display import SVG
graph = pydot.Dot(graph_type='digraph')
task_node1 = pydot.Node("Task1", shape="box",)
task_node2 = pydot.Node("Task2", shape="box",)
graph.add_node(task_node1)
graph.add_node(task_node2)
task1_to_task2_edge = pydot.Edge("Task1", "Task2",)
graph.add_edge(task1_to_task2_edge)
graph.write_svg("diagram.svg")
SVG('diagram.svg')
Run Code Online (Sandbox Code Playgroud)
数据框
id step timestamp
0 1 task1_start 2023-01-01
1 1 task1_End 2023-01-05
2 1 task2_start 2023-01-10
3 1 task2_end 2023-01-12
4 2 task1_start 2023-01-01
5 2 task1_End 2023-01-05
6 2 task2_start 2023-01-10
7 2 task2_end 2023-01-12
Run Code Online (Sandbox Code Playgroud)
MVP
import pandas as pd
d = {'id': [1, 1, 1, 1,
2, 2, 2, 2,],
'step': ['task1_start', 'task1_End', 'task2_start', 'task2_end',
'task1_start', 'task1_End', 'task2_start', 'task2_end',],
'timestamp': ['2023-01-01', '2023-01-05', '2023-01-10', '2023-01-12',
'2023-01-01', '2023-01-05', '2023-01-10', '2023-01-12',]}
df = pd.DataFrame(data=d,)
df['timestamp'] = pd.to_datetime(df['timestamp'])
g = df.groupby('id')
out = (df
.assign(duration=df['timestamp'].sub(g['timestamp'].shift()),
step=lambda d: (df['step']+'/'+g['step'].shift()).str.replace(
r'([^_]+)[^/]*/([^_]+)[^/]*',
lambda m: m.group(1) if m.group(1)==m.group(2) else f"{m.group(2)}_to_{m.group(1)}",
regex=True)
)
[['id', 'step', 'duration']].dropna(subset=['duration'])
)
df = out
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
colors = mcolors.LinearSegmentedColormap.from_list(
'LightBlueGreenYellowRed', ['#B0E0E6', '#87CEEB', '#00FF00', '#ADFF2F', '#FFFF00', '#FFD700', '#FFA500', '#FF4500', '#FF0000', '#FF6347', '#FF7F50', '#FFA07A', '#FFC0CB', '#FFB6C1', '#FF69B4', '#DB7093', '#FF1493', '#C71585', '#FF00FF']
)
def get_color(value, vmin, vmax):
norm = (value - vmin) / (vmax - vmin)
cmap = colors(norm)
return mcolors.to_hex(cmap)
vmin = df['duration'].min()
vmax = df['duration'].max()
df['color'] = df['duration'].apply(lambda x: get_color(x, vmin, vmax))
def get_color(id):
if (df['step'] == id).any():
color = df.loc[df['step'] == id, 'color'].values[0]
if pd.isnull(color):
return '#808080'
else:
return color
else:
return '#808080'
import pydot
from IPython.display import SVG
graph = pydot.Dot(graph_type='digraph')
task_node1 = pydot.Node("Task1", shape="box", color = get_color('task1'))
task_node2 = pydot.Node("Task2", shape="box", color = get_color('task2'))
graph.add_node(task_node1)
graph.add_node(task_node2)
task1_to_task2_edge = pydot.Edge("Task1", "Task2", color = get_color('task1_to_task2'))
graph.add_edge(task1_to_task2_edge)
graph.write_svg("diagram.svg")
SVG('diagram.svg')
Run Code Online (Sandbox Code Playgroud)
要绘制热图,请使用 SVG 导出并向节点添加类名称以标记它们的热度。然后,您可以将该 SVG 组包含两次,并使用过滤器提供类似热图的内容,方法是使用填充颜色并模糊的背景,并将正常的黑白版本作为前景。
<svg height="110" width="110" xmlns="http://www.w3.org/2000/svg">
<style>
.foreground *{
fill: none;
stroke: black;
}
.foreground text{
fill: black;
stroke: none;
}
.background *{
stroke: none;
}
.background text { display: none; }
.background .heat-1 { fill: #00ff00; }
.background *.heat-2 { fill: #ff0000; }
</style>
<defs>
<filter id="f1" x="0" y="0">
<feGaussianBlur in="SourceGraphic" stdDeviation="15" />
</filter>
</defs>
<g transform="scale(1 1) rotate(0) translate(4 112)">
<g class='background' filter='url(#f1)'>
<g id="graph0" class="graph">
<!-- a -->
<g id="node1" class="node heat-1">
<title>a</title>
<ellipse cx="27" cy="-90" rx="27" ry="18" />
<text text-anchor="middle" x="27" y="-86.3" font-family="Times,serif"
font-size="14.00">a</text>
</g>
<!-- b -->
<g id="node2" class="node heat-2">
<title>b</title>
<ellipse cx="27" cy="-18" rx="27" ry="18" />
<text text-anchor="middle" x="27" y="-14.3" font-family="Times,serif"
font-size="14.00">b</text>
</g>
<!-- a->b -->
<g id="edge1" class="edge">
<title>a->b</title>
<path d="M27,-71.7C27,-63.98 27,-54.71 27,-46.11" />
<polygon fill="black" stroke="black"
points="30.5,-46.1 27,-36.1 23.5,-46.1 30.5,-46.1" />
</g>
</g>
</g>
<g class='foreground'>
<g id="graph0" class="graph" >
<!-- a -->
<g id="node1" class="node heat-1">
<title>a</title>
<ellipse cx="27" cy="-90" rx="27" ry="18" />
<text text-anchor="middle" x="27" y="-86.3" font-family="Times,serif"
font-size="14.00">a</text>
</g>
<!-- b -->
<g id="node2" class="node heat-2">
<title>b</title>
<ellipse cx="27" cy="-18" rx="27" ry="18" />
<text text-anchor="middle" x="27" y="-14.3" font-family="Times,serif"
font-size="14.00">b</text>
</g>
<!-- a->b -->
<g id="edge1" class="edge">
<title>a->b</title>
<path d="M27,-71.7C27,-63.98 27,-54.71 27,-46.11" />
<polygon fill="black" stroke="black"
points="30.5,-46.1 27,-36.1 23.5,-46.1 30.5,-46.1" />
</g>
</g>
</g>
</g>
</svg>
Run Code Online (Sandbox Code Playgroud)
如果您可以只使用对图形组的引用两次而不是将其包含两次,那就太好了,但是如果使用而不是内联,我无法获得 CSS 表达式来以不同的方式对待该组。
归档时间: |
|
查看次数: |
206 次 |
最近记录: |