【发布时间】:2021-08-12 22:37:51
【问题描述】:
我正在尝试使用 python 到 graphviz 的接口来可视化有限马尔可夫链的转移概率矩阵。我希望马尔可夫链的状态成为图中的节点,并且我希望图的边缘的宽度与状态之间转换的条件概率成比例。 IE。我希望为权重大的边缘绘制粗边,为权重小的边缘绘制细边。
在 (directed weighted graph from pandas dataframe) 的讨论 与我想要的类似,但它将转换概率信息呈现为文本标签而不是边缘宽度,这将导致无用且难以阅读的图表。
我很高兴考虑使用 graphviz 以外的工具来完成这项任务。
这是我正在尝试构建的类:
import graphviz
import matplotlib.pyplot as plt
import numpy as np
class MarkovViz:
"""
Visualize the transition probability matrix of a Markov chain as a directed
graph, where the width of an edge is proportional to the transition
probability between two states.
"""
def __init__(self, transition_probability_matrix=None):
self._graph = None
if transition_probability_matrix is not None:
self.build_from_matrix(transition_probability_matrix)
def build_from_matrix(self, trans, labels=None):
"""
Args:
trans: A pd.DataFrame or 2D np.array. A square matrix containing the
conditional probabability of a transition from the level
represented by the row to the level represented by the column.
Each row sums to 1.
labels: A list-like sequence of labels to use for the rows and
columns of 'trans'. If trans is a pd.DataFrame or similar then
this entry can be None and labels will be taken from the column
names of 'trans'.
Effects:
self._graph is created as a directed graph, and populated with nodes
and edges, with edge weights taken from 'trans'.
"""
if labels is None and hasattr(trans, "columns"):
labels = list(trans.columns)
index = list(trans.index)
if labels != index:
raise Exception("Mismatch between index and columns of "
"the transition probability matrix.")
trans = trans.values
trans = np.array(trans)
self._graph = graphviz.Digraph("MyGraph")
dim = trans.shape[0]
if trans.shape[1] != dim:
raise Exception("Matrix must be symmetric")
for i in range(dim):
for j in range(dim):
if trans[i, j] > 0:
self._graph.edge(labels[i], labels[j], weight=trans[i, j])
def plot(self, ax: plt.Axes):
self._graph.view()
我会使用看起来像这样的数据框来初始化示例对象
foo bar baz
foo 0.5 0.5 0
bar 0.0 0.0 1
baz 1.0 0.0 0
我遇到了以下错误
File "<stdin>", line 1, in <module>
File "/.../markov/markovviz.py", line 16, in __init__
self.build_from_matrix(transition_probability_matrix)
File "/.../markov/markovviz.py", line 53, in build_from_matrix
self._graph.edge(labels[i], labels[j], weight=trans[i, j])
File "/.../graphviz/dot.py", line 153, in edge
attr_list = self._attr_list(label, attrs, _attributes)
File "/.../graphviz/lang.py", line 139, in attr_list
content = a_list(label, kwargs, attributes)
File "/.../graphviz/lang.py", line 112, in a_list
for k, v in tools.mapping_items(kwargs) if v is not None]
File "/.../graphviz/lang.py", line 112, in <listcomp>
for k, v in tools.mapping_items(kwargs) if v is not None]
File ".../graphviz/lang.py", line 73, in quote
if is_html_string(identifier) and not isinstance(identifier, NoHtml):
TypeError: cannot use a string pattern on a bytes-like object
这对我说,边缘唯一允许的属性是字符串或字节。我的问题:
- 甚至可以在 python 界面中显示我正在尝试构建的图形到 graphviz 吗?
- 如果是这样,我如何将数字权重与边缘关联起来?
- 将权重附加到边缘后,如何绘制图形?
【问题讨论】:
-
您已经截断了回溯。如果我们知道您的代码中的哪一行产生了该错误,将会有所帮助。
-
@larsks,谢谢。我已经更新了帖子以显示完整的回溯。
-
出现此错误时,
labels[i]、labels[j]和trans[i, j]的值是多少?理想情况下,显示每个repr()。 -
(Pdb) labels[i] 'foo' (Pdb) labels[j] 'foo' (Pdb) trans[i, j] 0.5 -
这符合我昨天的假设,表明下面的答案是正确的。
标签: python graphviz pygraphviz