在我之前的一次问题,宏伟的杰克帮助我生成与在 MATLAB 中的二维矩阵上使用 imagesc 相同的热图。
结果看起来很棒,但现在我想修改它的行为以创建 Hinton 图。Hinton 图是一种可视化神经网络中权重的大小和方向的酷方法。它不使用颜色图来决定每个“像素”的颜色(例如,黑色为 -1,白色为 1,介于两者之间的任何颜色都是灰色),而是分别使用颜色 x 和 y 表示负值和正值,并通过方形标记的大小来可视化大小。下面是来自Python 解释(该代码可能会启发某些人)。
理想情况下,可以将所有这些都隐藏在一种风格中。
作为奖励,如果能够读取以矩阵的自然表示形式存储数据的文件就太好了:
2.76658 -0.07990 0.10551 -2.94131 0.00840 0.23832 -2.56759 0.04593
-0.21476 2.37350 -2.30670 0.11634 -2.36124 2.62034 -0.32261 2.36860
0.01118 -2.42926 2.42470 0.08698 2.45065 -2.39544 -0.16931 -2.32933
-3.04568 -0.15376 0.03051 2.74830 -0.07237 0.02359 2.96758 0.05812
-0.12791 -2.50370 2.63524 0.15000 2.26310 -2.39198 -0.05032 -2.41050
-0.07663 2.40350 -2.45346 -0.00479 -2.62160 2.29896 -0.11746 2.49031
-2.90385 -0.11742 -0.15037 2.88956 0.01517 -0.06700 2.96463 -0.10442
-0.17761 2.01661 -2.23660 -0.07113 -2.39688 2.19306 0.07902 2.37361
或者,如果这不可行,则采用如下传统的 xy 数据格式:
0 0 2.766580
1 0 -0.079900
2 0 0.105510
3 0 -2.941310
4 0 0.008400
5 0 0.238320
6 0 -2.567590
7 0 0.045930
0 1 -0.214760
1 1 2.373500
2 1 -2.306700
3 1 0.116340
4 1 -2.361240
5 1 2.620340
6 1 -0.322610
7 1 2.368600
0 2 0.011180
1 2 -2.429260
2 2 2.424700
3 2 0.086980
4 2 2.450650
5 2 -2.395440
6 2 -0.169310
7 2 -2.329330
0 3 -3.045680
1 3 -0.153760
2 3 0.030510
3 3 2.748300
4 3 -0.072370
5 3 0.023590
6 3 2.967580
7 3 0.058120
0 4 -0.127910
1 4 -2.503700
2 4 2.635240
3 4 0.150000
4 4 2.263100
5 4 -2.391980
6 4 -0.050320
7 4 -2.410500
0 5 -0.076630
1 5 2.403500
2 5 -2.453460
3 5 -0.004790
4 5 -2.621600
5 5 2.298960
6 5 -0.117460
7 5 2.490310
0 6 -2.903850
1 6 -0.117420
2 6 -0.150370
3 6 2.889560
4 6 0.015170
5 6 -0.067000
6 6 2.964630
7 6 -0.104420
0 7 -0.177610
1 7 2.016610
2 7 -2.236600
3 7 -0.071130
4 7 -2.396880
5 7 2.193060
6 7 0.079020
7 7 2.373610
您可以使用如下 Python 脚本从第一种数据格式生成第二种数据格式:
import numpy as np
rawdata = np.loadtxt('data.dat')
coords = np.meshgrid(np.arange(np.shape(rawdata)[0]),
np.arange(np.shape(rawdata)[1]))
data = np.vstack([coords[0].flatten(), coords[1].flatten(), rawdata.flatten()]).T
np.savetxt('weights-example.dat', data, fmt="%i %i %f")
TikZ
这可能对大师们的要求有点过分,pgfplots
因为我并没有真正努力去解决这个问题,但是,唉,我甚至不能完全理解杰克的代码是如何工作的。如果有人愿意帮忙,我想杰克的回答我应该从我之前的问题开始。
答案1
这是在 PGFPlots 中执行此操作的一种方法。我使用x,y,value
数据而不是矩阵,因为使用 PGFPlots 处理数据更容易。
我已定义fenton
可添加到axis
选项中的样式。使用您的测试文件和以下代码...
\begin{axis}[fenton]
\addplot table [meta index=2] {weights-example.dat};
\end{axis}
... 你会得到
fenton/positive style={...}
可以使用和来设置正值和负值的样式fenton/negative style={...}
。
完整代码如下:
\documentclass[border=5mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.9}
\makeatletter
\pgfplotsset{
fenton/positive/.style={fill=white, draw=none},
fenton/positive style/.style={/pgfplots/fenton/positive/.append style={#1}},
fenton/negative/.style={fill=black, draw=none},
fenton/negative style/.style={/pgfplots/fenton/negative/.append style={#1}},
fenton/.style={
axis background/.style={fill=gray},
only marks, no markers,
scatter,
axis equal image,
axis on top,
major tick length=0pt,
enlarge x limits={abs=0.5},
enlarge y limits={abs=0.5},
point meta=explicit,
scatter/@pre marker code/.code={
\pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}
\pgfmathsetmacro\normalisedsize{
sqrt(
abs(
\pgfplotspointmeta / max(
abs(\pgfplots@metamin),
abs(\pgfplots@metamax)
)
)
)
}
\pgfmathfloatifflags{\pgfplotspointmeta}{+}{
\pgfplotsset{fenton/current value/.style=/pgfplots/fenton/positive}
}{
\pgfplotsset{fenton/current value/.style=/pgfplots/fenton/negative}
}
\path [/pgfplots/fenton/current value] ([scale=\normalisedsize]axis direction cs:-0.5,-0.5) rectangle ([scale=\normalisedsize]axis direction cs:0.5,0.5);
},
scatter/@post marker code/.code={}
}
}
\makeatother
\begin{document}
\begin{tikzpicture}
\begin{axis}[fenton]
\addplot table [meta index=2] {weights-example.dat};
\end{axis}
\end{tikzpicture}
\end{document}
答案2
我认为这样做可以。本来可以用纯方法完成tex
,但今天我懒了,所以需要lualatex
。文件读取方法是不是稳健。另外,我只使用了黑色或白色(中间没有阴影)。
\documentclass[tikz,border=.1cm]{standalone}
\usepackage{filecontents}
\begin{filecontents*}{data.dat}
2.76658 -0.07990 0.10551 -2.94131 0.00840 0.23832 -2.56759 0.04593
-0.21476 2.37350 -2.30670 0.11634 -2.36124 2.62034 -0.32261 2.36860
0.01118 -2.42926 2.42470 0.08698 2.45065 -2.39544 -0.16931 -2.32933
-3.04568 -0.15376 0.03051 2.74830 -0.07237 0.02359 2.96758 0.05812
-0.12791 -2.50370 2.63524 0.15000 2.26310 -2.39198 -0.05032 -2.41050
-0.07663 2.40350 -2.45346 -0.00479 -2.62160 2.29896 -0.11746 2.49031
-2.90385 -0.11742 -0.15037 2.88956 0.01517 -0.06700 2.96463 -0.10442
-0.17761 2.01661 -2.23660 -0.07113 -2.39688 2.19306 0.07902 2.37361
\end{filecontents*}
{\catcode`\%=11\gdef\pc{%}}
\begin{document}
\directlua{%
Matrix = {}
Matrix.__index = Matrix
function Matrix.new()
local obj = {nrow=0, ncol=0, max=-math.huge, min=math.huge, data={}}
setmetatable(obj, Matrix)
return obj
end
function Matrix.fromFile(f)
local obj, file, line, row, v, c
obj = Matrix.new()
file = io.open(f)
if file then
for line in file:lines() do
row = {}
c = 0
for v in string.gmatch(line, "\pc S+") do
v = tonumber(v)
if v > obj.max then obj.max = v end
if v < obj.min then obj.min = v end
table.insert(row, v)
c = c + 1
end
table.insert(obj.data, row)
obj.nrow = obj.nrow + 1
if c > obj.ncol then
obj.ncol = obj.ncol + 1
end
end
end
return obj
end
function Matrix:get(i, j)
if self.data[i][j] then
return self.data[i][j]
else
return 0
end
end
function Matrix:set(i, j, v)
if self.data[i] == nil then
table.insert(self.data, i, {})
end
table.insert(self.data[i], j, v)
if i > self.nrow then self.nrow = i end
if j > self.ncol then self.ncol = j end
end
function Matrix:normalize()
local i, j, v
for i = 1,self.ncol do
for j = 1,self.nrow do
self.data[i][j] = 2*(self.data[i][j] - self.min) / (self.max - self.min) - 1
end
end
self.max = 1
self.min = -1
end
}
\def\getlua#1{\directlua{tex.print("" .. #1)}}
\directlua{
M = Matrix.fromFile("data.dat")
M:normalize()
}
\newcommand\hinton[2][]{%
\begin{tikzpicture}[#1]
\fill [black!15] (0,0) rectangle ++(\getlua{#2.ncol}+1, \getlua{#2.nrow}+1);
\foreach \i in {1,...,\getlua{#2.ncol}}{
\foreach \j [evaluate={\v=\getlua{#2:get(\i, \j)}; \c=(\v<0 ? 100 : 0); \s=\v; }] in {1,...,\getlua{#2.nrow}}{
\fill [black!\c!white] (\i, \j) ++(-\s/2,-\s/2) rectangle ++(\s,\s);
}}
\end{tikzpicture}}
\hinton{M}
\directlua{%
N = Matrix.new()
local i, j
for i = 1,25 do
for j = 1,25 do
N:set(i, j, math.random()*2-1)
end
end
}
\hinton[x=5pt, y=5pt]{N}
\end{document}
答案3
正如评论中提到的,您可以将图形导出matplotlib
到pgf
代码中,然后用 latex 编译它。我添加了一小段代码来生成一些虚假数据,并用 替换P.show()
以P.savefig('hinton_code.pgf')
将图表写入文件:
import numpy as N
import pylab as P
def _blob(x,y,area,colour):
hs = N.sqrt(area) / 2
xcorners = N.array([x - hs, x + hs, x + hs, x - hs])
ycorners = N.array([y - hs, y - hs, y + hs, y + hs])
P.fill(xcorners, ycorners, colour, edgecolor=colour)
def hinton(W, maxWeight=None):
reenable = False
if P.isinteractive():
P.ioff()
P.clf()
height, width = W.shape
if not maxWeight:
maxWeight = 2**N.ceil(N.log(N.max(N.abs(W)))/N.log(2))
P.fill(N.array([0,width,width,0]),N.array([0,0,height,height]), 'gray')
P.axis('off')
P.axis('equal')
for x in xrange(width):
for y in xrange(height):
_x = x+1
_y = y+1
w = W[y,x]
if w > 0:
_blob(_x - 0.5, height - _y + 0.5, min(1,w/maxWeight),'white')
elif w < 0:
_blob(_x - 0.5, height - _y + 0.5, min(1,-w/maxWeight), 'k')
if reenable:
P.ion()
P.savefig('hinton_code.pgf')
if __name__ == "__main__":
W = N.random.rand(15, 15) - 0.5*N.ones((15,15))
hinton(W)
创建文档就很简单了
\documentclass{article}
\usepackage{pgf}
\begin{document}
\input{hinton_code.pgf}
\end{document}
此外,我希望在 Python 中读取数据文件比在 TeX 中容易得多。
答案4
这是一个仅使用 TikZ 的非常简单的解决方案:
\documentclass[tikz]{standalone}
\usetikzlibrary{fit,backgrounds}
\def\mymatrix{%
{2.76658, -0.07990, 0.10551, -2.94131, 0.00840, 0.23832, -2.56759, 0.04593},
{-0.21476, 2.37350, -2.30670, 0.11634, -2.36124, 2.62034, -0.32261, 2.36860},
{0.01118, -2.42926, 2.42470, 0.08698, 2.45065, -2.39544, -0.16931, -2.32933},
{-3.04568, -0.15376, 0.03051, 2.74830, -0.07237, 0.02359, 2.96758, 0.05812},
{-0.12791, -2.50370, 2.63524, 0.15000, 2.26310, -2.39198, -0.05032, -2.41050},
{-0.07663, 2.40350, -2.45346, -0.00479, -2.62160, 2.29896, -0.11746, 2.49031},
{-2.90385, -0.11742, -0.15037, 2.88956, 0.01517, -0.06700, 2.96463, -0.10442},
{-0.17761, 2.01661, -2.23660, -0.07113, -2.39688, 2.19306, 0.07902, 2.37361}%
}
\def\max{3}
\begin{document}
\begin{tikzpicture}
\foreach \line [count=\y] in \mymatrix {
\foreach \val [count=\x] in \line {
\pgfmathsetmacro\col{(\val>=0)?"orange":"lime"}
\pgfmathsetmacro\len{sqrt(abs(\val)/\max)/2}
\fill[fill=\col] (\x,-\y) +(\len cm,\len cm) rectangle +(-\len cm,-\len cm);
}
}
\begin{scope}[on background layer]
\node[fill=gray,fit=(current bounding box),inner sep=1mm,draw]{};
\end{scope}
\end{tikzpicture}
\end{document}