2

I have a matrix, M, exported from Matlab to a .dat file. I want to import this into tikz and plot a density plot for the real and imaginary parts of M separately. The x-axis being the column index, y-axis the rows and the z being the value stored in element [M]_{i,j}.

This question was asked and got a reply to in this post. However, the solution required specific manipulation of the data and given that it was asked almost 4 years ago, I'm wondering whether there is an alternative approach.

The data matrix looks like this:

1.083+0.329i    0.329+-0.373i   0-0.139i            -0.139-0.896i
0.329-0.683i    -0.683-0.379i   0.139+0i            4.494e-12+0.215i
0.329-0.683i    -0.683-0.379i   0.139-4.494e-12i    0+0.215i
-0.373-0.379i   -0.379+0.282i   0.896-0.215i        -0.215+0i

Any help is appreciated.

Sid
  • 1,806
  • If the matrix comes from Matlab, would it not be easier to make the plot there and save it as a vector image? – Disenchanted Lurker Nov 15 '19 at 12:37
  • @DisenchantedLurker, That is certainly a possibility. I do prefer the more native TikZ option – Sid Nov 15 '19 at 12:40
  • Yes, there are solutions that do the conversion like this one. If you provide some information on how one should deal with the is, probably an explicit answer can be written. –  Nov 15 '19 at 15:57
  • @Schrödinger'scat, I will need to do the plot with the Real and Imaginary parts separately. I am working on separating these. – Sid Nov 15 '19 at 16:41
  • Is the +- in 0.329+-0.373i a typo? If yes, it is not too difficult to separate them. If it is not a typo, it is still possible, but I would not know what the interpretation of this complex number is. –  Nov 15 '19 at 17:17
  • @Schrödinger'scat, unfortunately, it's not a typo. The +- should read -. – Sid Nov 16 '19 at 15:02
  • @Sid I believe I was able to make my answer deal with that now. –  Nov 16 '19 at 15:24

1 Answers1

2

This is some code that reads your table and allows you to produce a matrix plot for the real and imaginary parts. The extraction of the real and imaginary parts uses xstring. For the real part, we just replace i by *0, and parse the result. For the imaginary part, we replace i by *1 and subtract the real part. Seems to work fine.

\documentclass[border=3mm,tikz]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{pgfplots.colormaps}
\pgfplotsset{compat=1.16}
\usepackage{pgfplotstable}
\usepackage{filecontents}
\usepackage{xstring}

\begin{filecontents*}{complexentries.dat}
1.083+0.329i    0.329+-0.373i   0-0.139i            -0.139-0.896i
0.329-0.683i    -0.683-0.379i   0.139+0i            4.494e-12+0.215i
0.329-0.683i    -0.683-0.379i   0.139-4.494e-12i    0+0.215i
-0.373-0.379i   -0.379+0.282i   0.896-0.215i        -0.215+0i
\end{filecontents*}
\def\pgfmathsetmacroFPU#1#2{\begingroup%
\pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}%
\pgfmathsetmacro{#1}{#2}%
\pgfmathsmuggle#1\endgroup}%
\newcommand\ExtractRealAndImaginary[1]{%
\StrSubstitute{#1}{i}{*0}[\mytemp]%
\pgfmathsetmacroFPU{\myreal}{\mytemp}%
\StrSubstitute{#1}{i}{*1}[\mytemp]%
\pgfmathsetmacroFPU{\myim}{\mytemp-\myreal}}


\def\ipExtractRealAndImaginary#1+#2i{\def\myreal{#1}\def\myim{#2}}
\def\imExtractRealAndImaginary#1-#2i{\def\myreal{#1}\def\myim{-#2}}
\newcommand*{\ReadOutElement}[4]{%
    \pgfplotstablegetelem{#2}{[index]#3}\of{#1}%
    \let#4\pgfplotsretval
}
\begin{document}
\pgfplotstableread[header=false]{complexentries.dat}\datatable
%\pgfplotstabletypeset\datatable

%\end{document}
\pgfplotstablegetrowsof{\datatable}
\pgfmathtruncatemacro{\numrows}{\pgfplotsretval}
\pgfplotstablegetcolsof{\datatable}
\pgfmathtruncatemacro{\numcols}{\pgfplotsretval}
\foreach \nY in {1,...,\numrows}
{\pgfmathtruncatemacro{\newY}{\numrows-\nY}
\foreach \nX in {1,...,\numcols}
{
\ReadOutElement{\datatable}{\the\numexpr\nY-1}{\the\numexpr\nX-1}{\Current}%
%\typeout{===========}
\edef\temp{\noexpand\ExtractRealAndImaginary{\Current}}
\temp
%\typeout{Re(\Current)=\myreal,Im(\Current)=\myim}
%\edef\myentry{\myim}%
\pgfmathtruncatemacro{\nZ}{\nX+\nY}%
\ifnum\nZ=2
\xdef\LstX{\the\numexpr\nX-1}%
\xdef\LstY{\the\numexpr\nY-1}%
\xdef\LstRe{\myreal}%
\xdef\LstIm{\myim}%
\else
\xdef\LstX{\LstX,\the\numexpr\nX-1}%
\xdef\LstY{\LstY,\the\numexpr\nY-1}%
\xdef\LstRe{\LstRe,\myreal}%
\xdef\LstIm{\LstIm,\myim}%
\fi
}
}
\edef\temp{\noexpand\pgfplotstableset{
 create on use/x/.style={create col/set list={\LstX}},
 create on use/y/.style={create col/set list={\LstY}},
 create on use/real/.style={create col/set list={\LstRe}},
 create on use/im/.style={create col/set list={\LstIm}},
}}
\temp
\pgfmathtruncatemacro{\strangenum}{\numrows*\numcols}
\pgfplotstablenew[columns={x,y,real,im}]{\strangenum}\strangetable

%\pgfplotstabletypeset\strangetable

\begin{tikzpicture}
\begin{axis}[%
    small,title=real parts,
    tick align=outside,
    minor tick num=4,
    %
    xlabel=$x$,
    xlabel near ticks,
    xmin=-1, xmax=4,
    xtick=\empty,
    %
    ylabel=$y$,
    ylabel style={rotate=-90},
    ymin=-1, ymax=4,     
    ytick=\empty,
%     point meta min=0,
%     point meta max=32,
    point meta=explicit,
    %
    %colorbar sampled,
    colorbar as palette,
    colorbar style={samples=3},
    %colormap name=WhiteRedBlack,
    scale mode=scale uniformly,
]
 \addplot [
        matrix plot,
        mesh/cols=4,
        point meta=explicit,
] table [meta=real,col sep=comma] \strangetable;
\end{axis}
\end{tikzpicture}

\begin{tikzpicture}
\begin{axis}[%
    small,title=imaginary parts,
    tick align=outside,
    minor tick num=4,
    %
    xlabel=$x$,
    xlabel near ticks,
    xmin=-1, xmax=4,
    xtick=\empty,
    %
    ylabel=$y$,
    ylabel style={rotate=-90},
    ymin=-1, ymax=4,     
    ytick=\empty,
%     point meta min=0,
%     point meta max=32,
    point meta=explicit,
    %
    %colorbar sampled,
    colorbar as palette,
    colorbar style={samples=3},
    %colormap name=WhiteRedBlack,
    scale mode=scale uniformly,
]
 \addplot [
        matrix plot,
        mesh/cols=4,
        point meta=explicit,
] table [meta=im,col sep=comma] \strangetable;
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

  • I've managed to split the data into real and imaginary parts. This removes the need to have TikZ handle the i and the +-. So now I have two data sets containing the separate parts. Will this work for that? – Sid Nov 16 '19 at 15:26
  • 1
    @Sid I believe so, yes. You only need the plot with ...table [meta=real,col sep=comma].... You could also just use this answer then. (I should say it was fun to make pgfplots work with complex entries. ;-) –  Nov 16 '19 at 15:28
  • Rather than loading the data file complexentries.dat through \begin{filecontents*}{complexentries.dat}, how can I load my data? I have previously used \pgfplotstableread{complexentries.dat}{\compexentries} but this doesn't seem to work. – Sid Nov 17 '19 at 17:36
  • @Sid \begin{filecontents*} does not load a file, it creates it. If you have the file, \pgfplotstableread{complexentries.dat}{\compexentries} should load the data. In the above code, this is done with \pgfplotstableread[header=false]{complexentries.dat}\datatable, so perhaps you only miss [header=false]. –  Nov 17 '19 at 17:58
  • I did miss the [header=false], so now it is working. However, the heat map has colours that are not in the legend. Specifically, the grey areas. How can this be corrected for? – Sid Nov 17 '19 at 18:30
  • 1
    @sid You could replace colorbar style={samples=3}, by colormap/viridis,colorbar sampled,. (Color bars and maps are tricky beasts...) –  Nov 17 '19 at 18:34
  • Thank you. One final question: how can I remove the erroneous white gaps? I would like the axes borders to have no white spaces – Sid Nov 18 '19 at 13:22
  • @Sid You could use xmin=-0.5, xmax=3.5,ymin=-0.5, ymax=3.5,. –  Nov 18 '19 at 14:35