import numpy as np
import pandas as pd
import copy
from matplotlib import pyplot as plt
from matplotlib.colors import rgb2hex
import svgwrite
from pm4py.objects.log.importer.xes import importer as xes_importer
class Vis:
padding = 5
square_s = 50
margin_legend = 30
def __init__(self, max_n_color=6, legend=None, mapping_name=None, title=None, width_in_block=20):
"""
Produce SVG visualizations for event logs
:param seqs: event logs represented as list of lists
:param max_n_color: maximum number of colors, only the {max_n_color}
most appearing activities will have their own color
:param legend: For some analysis, it could be useful to have two event logs that
shares the same legend (e.g., when doing clustering); i.e.,
two visualizations will share the same colors and are hence comparable.
This param allow to apply an existing legend to the graph.
The legend is extracted from the graph using self.get_legend().
If none, the legend is built automatically by looking at the
most occuring activities
:param mapping_name: In a web service context, we can save some space if we provide an
index for the activity name instead of the real name;
i.e., [['this is activity 1','activity2']] becomes [[1,2]]
mapping_name allows to map the real name to the index so the
legend will show the real name.
this is how the mapping_name would look like:
{1:'this is activity 1', 2:'this is activity 2'}
:param title: Optional title at the top of the visualization
:param width_in_block: Max number of activities per sequence (default: 20).
If a trace contains more than {width_in_block}, it will
be truncated like [1,2,3,4,5,...,10] (with width_in_block=7)
"""
self.seqs = None
self.max_n_color = int(max_n_color)
self.legend = legend
self.mapping_name = mapping_name
self.title = title
self.width_in_block = width_in_block
self.svg = {}
def _load(self, seqs):
self.seqs = seqs
if not self.legend:
self.legend = self.extract_legend(self.seqs)
else:
self._add_missing_activity_to_legend()
# We create three kind of SVGs
for type in ['seq','legend','seqlegend']:
self.svg[type] = self._build_svg(type)
def load_from_seq(self, seqs):
self._load([[str(y) for y in x] for x in seqs])
def load_from_xes(self, path):
log = xes_importer.apply(path)
self.load_from_pm4py(log)
def load_from_pm4py(self, log_object):
seq = [[e['concept:name'] for e in trace] for trace in log_object]
self.load_from_seq(seq)
def load_from_df(self, df, case_col, activity_col):
seq = df.groupby(case_col)[activity_col].agg(list).tolist()
self.load_from_seq(seq)
def _add_missing_activity_to_legend(self):
'''
When using an existing legend, we should make sure that all
activities from the current event logs are also added to the legend
(with the color 'others')
:return:
'''
last_row = None
highest_ranking = 0
for v in self.legend.values():
if v['ranking']>highest_ranking:
highest_ranking = v['ranking']
last_row = v
for k,v in self.extract_legend(self.seqs).items():
if k not in self.legend:
self.legend[k] = last_row
self.legend[k]['o_name'] = k
def extract_legend(self, seqs):
'''
Assign a color to each activities.
The top {self.max_n_color-1} activities that occurs the most will
have a distinct color while the remaining one will get the label 'others'
:param seqs: event logs as list of lists
:return: a dictionary
'''
# Count activities
y = pd.Series([y for x in seqs for y in x]).value_counts().to_frame()
# Prepare dataframe
y.columns = ['count']
y.index.name = 'name'
y = y.reset_index()
y = y.sort_values(by=['count','name'], ascending=[False, True])
# Assign color
n_color = min(self.max_n_color, y.shape[0])
palette = plt.get_cmap('magma', n_color+1)
colors = [rgb2hex(palette(x)) for x in range(n_color)]
y['color'] = colors[-1]
y.loc[y.iloc[0:n_color].index, 'color'] = colors
# Map potential name
mapping = {x:x for x in y['name'].tolist()}
if self.mapping_name:
for k,v in self.mapping_name.items():
if k in mapping.keys():
mapping[k] = v
y.index = y['name'].tolist()
y['o_name'] = y['name'].copy()
y['name'] = y['name'].map(mapping)
y['ranking'] = np.arange(y.shape[0])
if y.shape[0] > self.max_n_color:
y.loc[y.iloc[n_color-1:].index, 'name'] = '+ {} others...'.format(y.shape[0]-n_color+1)
y.loc[y.iloc[n_color-1:].index, 'color'] = '#eee'
return y.to_dict(orient='index')
def _build_svg(self, type):
'''
Draw the SVG.
:param type: There are three types of SVGs:
1. 'legend': show only the legend
2. 'seq': show only the sequence of activities
3. 'seqlegend': show both (1) and (2)
:return: a svgwrite object
'''
n = 0
if type in ['seq','seqlegend']:
n += len(self.seqs) # For the sequence
if type in ['legend','seqlegend']:
# For the legend
u_name = {x['name'] for x in self.legend.values()}
n += len(u_name)
n += self.title is not None
height = n*(self.padding+self.square_s)
if type == 'seqlegend':
height += self.margin_legend
width = self.width_in_block * self.square_s
font_size = self.square_s*0.7
d = svgwrite.Drawing('test.svg', profile='tiny', size=(width, height))
d.add(d.rect((0, 0), (width, height), fill='#ffffff'))
if type in ['seq','seqlegend']:
if self.title is not None:
d.add(d.text(self.title, insert=(0, 35), fill='black', font_size=font_size,))
for row, trace in enumerate(self.seqs):
for col, activity in enumerate(trace):
top = (((row+(self.title is not None))*self.square_s) + ((row)*self.padding))
if len(trace) > self.width_in_block:
if col == len(trace) - 2:
left = (self.width_in_block - 2)*self.square_s
r = self.square_s/15
d.add(d.circle((left+(self.square_s/2), top+(self.square_s/2)), r, fill='#000000'))
d.add(d.circle((left+(self.square_s/2)-(r*3), top+(self.square_s/2)), r, fill='#000000'))
d.add(d.circle((left+(self.square_s/2)+(r*3), top+(self.square_s/2)), r, fill='#000000'))
continue
if col == len(trace)-1:
left = (self.width_in_block - 1)*self.square_s
d.add(d.rect((left, top), (self.square_s, self.square_s), fill=self.legend[trace[-1]]['color']))
continue
if col > self.width_in_block - 3:
continue
left = col*self.square_s
d.add(d.rect((left, top), (self.square_s, self.square_s), fill=self.legend[activity]
挣扎的蓝藻
- 粉丝: 14w+
- 资源: 15万+
最新资源
- C++源码 运动控制源码 对话式示教编程 编程简单 控制卡 mfc 运动控制参考源码 运动流程可以在线编辑,支持输入输出,回原点,插补运动,等待 程序编辑区域,可以实现对各个命令的编辑,灵活配置
- 光伏储能并网发电模型,根据储能电池SOC的工作区间,光伏有MPPT、恒功率输出两种控制方式,在电池健康工况下光伏处于MPPT模式,在电池处于极限工况下,光伏处于恒功率模式,通过boost连接到公共点
- 基于labview开发的连续声音输入,有限声音输入,生成声音,读取声音文件至图形,同步声音输入输出,声音文件至声音输出,声音输入至文件,声音播放器,可以运行玩耍,结构清晰,动画仿真,适合学习参考
- 松下PLC编程 FP-XH 10轴定位 松下PLC项目实例,两台CPU间通过RS485通讯,10轴定位控制 轴控制程序采用FB,直观可靠,可以重复使用,使用时只需要对fb接口赋值即可,内部已经对系统
- ansys maxwell 开关磁阻电机参数化仿真 转子内外径、定转子极弧系数、气隙长度、绕组匝数等参数化扫描,灵敏度分析、效率优化
- 基于stm32的温湿度采集Proteus仿真(仿真+程序) 仿真图protues 8.9 程序编译器:keil 5 编程语言:C语言 功能描述: 通过STM32采集DHT11温度传感器的数据,将温湿度
- 基于51单片机数字电压表仿真设计-数码管(程序+仿真+原理图+pcb+报告) 原理图:Altium Designer 仿真图proteus 7.8 程序编译器:keil 4 keil 5 编程语言:C
- maxwell永磁同步电机2D到3D快速斜极脚本 支持连续、Z、V以及用户自定义角度分段
- 信捷PLC六轴标准程序,双头旋铆机 程序分层合理,有完整的注释,结构清晰明了 此程序已经实际设备上批量应用,程序成熟可靠 程序是分工位编辑,模块化编辑 对于做信捷PLC朋友有很好的借鉴意义 所
- 三菱Q系列PLC 大型项目程序案例,赵工PLC ABB机器人综合项目程序,有注释,配套触摸屏画面程序,三菱Q系列CPU,配置了DJ71DN91 三菱DeviceNet 智能模块、光纤伺服控制模块 Q
- 西门子200smart 自写PID功能块,西门子200smartPLC本身只支持8路PID而且不支持PID参数变量引接到触摸屏以及上位机,这给实际项目运用以及调试带来不少麻烦 功能块是自写的PID
- 三菱Q06UDV系列PLC,威纶通触摸屏,锂电池项目程序 全自动电芯组盘机 1.Q06UDV主CPU,搭载QJ61BT11N远程cclink模块数字输入输出IO控制,进行电磁阀,气缸感应器,真空发物流
- 最新版C#源码,非开源的 1,开发语言为c#, 非开源 2,以halcon17.12为底层,故运行有可能需要安装halcon17.12,halcon10也可以; 3、VS13以上均可运行;
- 驱动FOC 电机学习FOC控制 高频注入 推理过程和代码实现以及原理图 FOC矢量控制 FOC驱动无刷驱动foc无刷电机驱动方式学习 可用于驱动无刷电机,永磁同步电机 FOC框架、坐标变、SVPWM
- 光伏并网逆变器 包含原理图,pcb,源码以及元器件明细表 如下: 1) 功率接口板原理图和pcb,元器件明细表 2) 主控DSP板原理图(pdf)和PCB.元器件明细表以及代码 3)
- 基于A* Dijkstra Dstar算法的路径规划算法matlab代码,求解常见的路径规划问题 内含算法的注释,模块化编程,新手小白可快速入门 Astar算法,路径规划算法
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈