我有一个相当大的二进制矩阵,可能有 70 行和 64 列。为了方便查看,我想在 TikZ 中绘制此矩阵,其中例如 1 用红色方块表示,0 用白色方块表示。有人知道我该如何获得这个吗?
理想情况下,我会有一个可以只从文件加载矩阵的东西,TikZ 会处理其他所有事情。否则,我也很乐意使用一个解决方案,即用某个字符串查找/替换每个 0,用另一个字符串替换每个 1。
先感谢您!
示例矩阵:
10110101010
10010101010
01010111010
11110010100
01100011001
11101010111
10101010111
答案1
答案提供了两种解决方案:通过第一种方法,可以自定义正方形的尺寸,也许更适合您的需求。两者都基于此处给出的答案。
解决方案 1 基于使用 pgfplotstable 在表格中创建方形和自定义大小的单元格:
\documentclass{article}
\usepackage{filecontents}
\usepackage[table]{xcolor}
\usepackage{pgfplotstable}
\usetikzlibrary{calc}
\pgfplotsset{compat=1.8}
\begin{filecontents}{matrix.cvs}
1 0 1 1 0 1 0 1 0 1 0
1 0 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 1 1 0 1 0
1 1 1 1 0 0 1 0 1 0 0
0 1 1 0 0 0 1 1 0 0 1
1 1 1 0 1 0 1 0 1 1 1
1 0 1 0 1 0 1 0 1 1 1
\end{filecontents}
\makeatletter
\tikzset{
zero color/.initial=white,
zero color/.get=\zerocol,
zero color/.store in=\zerocol,
one color/.initial=red,
one color/.get=\onecol,
one color/.store in=\onecol,
cell wd/.initial=1ex,
cell wd/.get=\cellwd,
cell wd/.store in=\cellwd,
cell ht/.initial=1ex,
cell ht/.get=\cellht,
cell ht/.store in=\cellht,
}
\newcommand{\drawgrid}[2][]{
\medskip
\begin{tikzpicture}[#1]
\pgfplotstableforeachcolumn#2\as\col{
\pgfplotstableforeachcolumnelement{\col}\of#2\as\colcnt{%
\ifnum\colcnt=0
\fill[\zerocol]($ -\pgfplotstablerow*(0,\cellht) + \col*(\cellwd,0) $) rectangle+(\cellwd,\cellht);
\fi
\ifnum\colcnt=1
\fill[\onecol]($ -\pgfplotstablerow*(0,\cellht) + \col*(\cellwd,0) $) rectangle+(\cellwd,\cellht);
\fi
}
}
\end{tikzpicture}
\medskip
}
\makeatother
\begin{document}
% read the file
\pgfplotstableread{matrix.cvs}{\matrixfile}
\drawgrid{\matrixfile}
\drawgrid[zero color=green, one color=cyan]{\matrixfile}
\drawgrid[zero color=orange,
one color=violet,
cell ht=2em,
cell wd=2em]{\matrixfile}
\end{document}
结果:
解决方案 2 基于通过 TikZ 对表格中的阴影进行参数化:
\documentclass{article}
\usepackage{filecontents}
\usepackage[table]{xcolor}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.8}
\begin{filecontents}{matrix.cvs}
1 0 1 1 0 1 0 1 0 1 0
1 0 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 1 1 0 1 0
1 1 1 1 0 0 1 0 1 0 0
0 1 1 0 0 0 1 1 0 0 1
1 1 1 0 1 0 1 0 1 1 1
1 0 1 0 1 0 1 0 1 1 1
\end{filecontents}
\makeatletter
\pgfplotstableset{
zero color/.initial=white,
zero color/.get=\zerocol,
zero color/.store in=\zerocol,
one color/.initial=red,
one color/.get=\onecol,
one color/.store in=\onecol,
color cells/.style={
every head row/.style={output empty row},
string type,
postproc cell content/.code={%
\pgfkeysalso{@cell content=\rule{0cm}{2.4ex}\cellcolor{\zerocol}
\pgfmathtruncatemacro\number{##1}
\ifnum\number>0\cellcolor{\onecol}\fi}%
},
columns/x/.style={
column name={},
postproc cell content/.code={}
}
}
}
\makeatother
\begin{document}
% read the file
\pgfplotstableread{matrix.cvs}{\matrixfile}
\begin{table}
\centering
\pgfplotstabletypeset[color cells]\matrixfile
\end{table}
\begin{table}
\centering
\pgfplotstabletypeset[color cells, zero color=green, one color=cyan]\matrixfile
\end{table}
\end{document}
结果:
答案2
只是为了好玩和比较,我实现了一个 lualatex 解决方案。
在这个解决方案中,我使用 lua 将矩阵从其文本形式(0 和 1 的序列)转换为包含大量绘制图形的 tikz 命令的另一个字符串。
基于 lua 的解决方案似乎比纯 tikz 解决方案慢,但这可能是由于 lualatex 启动。lua 函数的执行非常快,但生成的 tikz 代码的编译显然是瓶颈。可能我的 lua 代码可以生成更高效的 tikz 代码。
要编译我的示例,你需要:
- 正在运行的 lualatex
- 该文件的副本
matrix2tikz.lua
(如下) - 该文件
sample.tex
(下)
样本
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fit}
\directlua{dofile("matrix2tikz.lua")}
\newcommand{\bitmapmatrix}[2][10]{%
\begin{scope}[bitmapmatrix]
\directlua{matrix2tikz("#2",#1)}%
\end{scope}
}
\tikzset{
bitmapmatrix/.style = {line width = 2sp},
pixel on/.style = {red},
pixel off/.style = {white},
pixel err/.style = {pink}
}
\def\mydata{
10110101010
10010101010
01010111010
11110010100
01100011001
11101010111
10101010111
}
\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}[node distance=2mm]
\bitmapmatrix[5]{\mydata}
\node[below=of matrix] {This is a test};
\end{tikzpicture}
\end{document}
矩阵2tikz.lua
local function matrix_to_tikz(tab , size)
local width = size
if (size == nil) then size=10 end
local pixel_width = size / #tab[1]
local height = pixel_width * #tab
local pixel_cmd = string.format("\\filldraw[%%s] (%%f, %%f) +(-%f, %f) → rectangle +(%f, -%f);",
pixel_width/2, pixel_width/2, pixel_width/2, pixel_width/2)
local str_tab = {}
for y=1,#tab do
row = {}
for x=1,#tab[y] do
if tab[y][x] == 1 then
style = "pixel on"
elseif tab[y][x] == 0 then
style = "pixel off"
else
style = "pixel err"
end
row[x] = string.format(pixel_cmd, style, x*pixel_width, -y*pixel_width)
end
str_tab[y] = table.concat(row, "\n")
end
local extra = {}
extra[1] = string.format("\\coordinate (aux1) at (%f,-%f);", pixel_width/2, → height+pixel_width/2)
extra[2] = string.format("\\coordinate (aux2) at (%f, %f);", width+ → pixel_width/2, -pixel_width/2)
extra[3] = "\\node[inner sep=0pt, fit=(aux1) (aux2)] (matrix) {};"
str_tab[#tab+1] = table.concat(extra, "\n")
return table.concat(str_tab,"\n")
end
function justWords(str)
local t = {}
local function helper(word) table.insert(t, word) return "" end
if not str:gsub("%w+", helper):find"%S" then return t end
end
local function text_to_matrix(txt)
local m = {}
local l = justWords(txt)
for i=1,#l do
if (l[i]~= nil and #l[i]>1) then
j = 1; row = {}
for c in l[i]:gmatch(".") do
row[j] = tonumber(c)
j = j + 1
end
m[i] = row
end
end
return m
end
function matrix2tikz(data, size)
local t = text_to_matrix(data)
local s = matrix_to_tikz(t, size)
tex.print(s)
end
编译
将两者放在同一个文件夹中并运行lualatex sample.tex
。结果如下:
答案3
运行xelatex
\documentclass{article}
\usepackage{filecontents}
\usepackage{pstricks-add}
\begin{filecontents*}{matrix.data}
/dotmatrix [
1 0 1 1 0 1 0 1 0 1 0
1 0 0 1 0 1 0 1 0 1 0
0 1 0 1 0 1 1 1 0 1 0
1 1 1 1 0 0 1 0 1 0 0
0 1 1 0 0 0 1 1 0 0 1
1 1 1 0 1 0 1 0 1 1 1
1 0 1 0 1 0 1 0 1 1 1
] def
\end{filecontents*}
\begin{document}
\begin{pspicture}(-0.5,-0.75)(7,11)
\psframe*[linecolor=blue!60](0.5,0.5)(11.5,7.5)
\psMatrixPlot[dotsize=1.1cm,dotstyle=square*,linecolor=red!60]{7}{11}{matrix.data}
\end{pspicture}
\end{document}
答案4
只是为了好玩,直接从提供的数据中获取。L3 版本可能正在开发中 :)
\documentclass{standalone}
\usepackage{tikz,xstring,etoolbox,catchfile}
\usetikzlibrary{matrix}
%=== Remove these later, it creates a dummy data file
\usepackage{filecontents}
\begin{filecontents*}{testdata.txt}
101101010101011010101010110101010
100101010101001010101010010101010
010101110100101011101001010111010
111100101001111001010011110010100
011000110010110001100101100011001
111010101111110101011111101010111
101010101111010101011110101010111
101101010101011010101010110101010
100101010101001010101010010101010
010101110100101011101001010111010
111100101001111001010011110010100
011000110010110001100101100011001
111010101111110101011111101010111
101010101111010101011110101010111
\end{filecontents*}
%================================
%Replace your file name
\CatchFileDef{\mydata}{testdata.txt}{}
\def\doit#1{%
\let\mymatrixcontent\empty%
\StrCount{#1}{ }[\myrownumber]%
\xdef\mormatrix{#1}%
\foreach \m in {1,...,\myrownumber}{%
\StrCut{\mormatrix}{ }\myextractedrow\myremainingmatrix%
\xdef\mormatrix{\myremainingmatrix}%
\StrLen{\myextractedrow}[\mycolnum]%
\foreach \k in {1,...,\mycolnum}{%
\StrChar{\myextractedrow}{\k}[\kk]%
\begingroup\edef\x{\endgroup%
\noexpand\gappto\noexpand\mymatrixcontent{\ifnum\kk>0|[fill=red]|\fi\noexpand\&}}\x%
}\gappto\mymatrixcontent{\\}}%
\begin{tikzpicture}
\matrix[matrix of nodes,ampersand replacement=\&,inner sep=0pt,
nodes={minimum size=4mm,outer sep=0pt}] {\mymatrixcontent};
\end{tikzpicture}%
\let\mymatrixcontent=\empty
}
\begin{document}
\doit{\mydata}
\end{document}