1

I am trying to make an animation from a table that contains a row for every frame (year) where the rows are a 9x7 matrix unzipped:

Date, Row1Col1, Row1Col2, ..., Row9Col7
1864,   0.65,     0.01,  ...,   0.2

I want to present each frame as a 2D surface plot. Thanks to: Using pgfplots, how do I arrange my data matrix for a surface plot so that each cell in the matrix is plotted as a square? and Building a 2D histogram with PGFPlots I have this working as a minimal example:

\documentclass{article}

\usepackage{fullpage}
\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\begin{document}
%For a 3x2 matrix output, need 4x3 input..., with a mesh/rows=4 OR a mesh/cols=3
\pgfplotstableread{
%x y value
0 0 0.5
0 1 4
%Dummy row
0 2 0
%
1 0 0
1 1 3
%dummy row
1 2 0
%
2 0 1
2 1 2
%dummy row
2 2 0
%
%Dummy column
3 0 4
3 1 4
%dummy row
3 2 0
%%
}\data

\begin{tikzpicture}
  \begin{axis}[
    view={0}{90},
    colorbar,
    xtick=data,
    xticklabels={NotGuilty,Corporal,Death,},
    x tick label style={anchor=north,yshift=0cm,xshift=1.3cm},
    ytick=data,
    y tick label style={anchor=east,yshift=1.3cm,xshift=0cm},
    yticklabels={BreakingPeace,Damage,}
  ]
    \addplot3[
      surf,
      shader=flat corner,
      mesh/rows=4,
      mesh/cols=3,
      mesh/ordering=rowwise,
    ] table {\data};
  \end{axis}
\end{tikzpicture}

\end{document}

Now what I hoped would work was that I could use the mesh/cols and mesh/rows to unpack the data in one line as:

\pgfplotstableread{0 0 0.5 0 1 4 0 2 0 1 0 0 1 1 3 1 2 0 2 0 1 2 1 2 2 2 0 3 0 4 3 1 4 3 2 0 }\data

I can get one row to work with:

\pgfplotsset{table/col sep = comma,table/row sep=\\}
\pgfplotstableread{0,0,0.5\\0,1,4\\0,2,0\\1,0,0\\1,1,3\\1,2,0\\2,0,1\\2,1,2\\2,2,0\\3,0,4\\3,1,4\\3,2,0\\}\data

This data format will be fairly trivial to get out of my raw data, but I need it to work with 200 rows or so and hoping I could loop through them with something like:

\foreach \row in {0,...200}{
  ...
  \addplot[...] table[row = \row] \data
}

But.. there is no such key! Could my CSV be converted to the required row type on the fly somehow with pgf trickery?

I am trying to avoid turning rows back into matrices as I would probably need to generate a new file for every row in pandas (~300 rows)

Also, how can the labels be dynamically shifted to the center of the box. If they were at positions 0.5, 1.5 etc that would work...

1 Answer 1

1

I have found a way to do it, its a bit brute force-sh and requires the additional step of replacing all newlines with \\ to combine the multiline output into one long row:

sed ':a;N;$!ba;s/\n/\\\\/g'

I will edit the post with the steps for preparing the data with python pandas when I have it all sorted. But the pgfplots bit is working on the dummy data at least. I combine all the rows together as one long row with the sed command as above using \\ as the row separator, then loop through column block ranges using select coords between index thanks to @Fritz from How can I filter/select data from a table and plot it? where our one long row is actually a whole heap of rows (The animation stuff is left in there as this is the final intended output)

\documentclass{standalone}
\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\begin{document}

%Style to select only points from #1 to #2 (inclusive)
\pgfplotsset{select coords between index/.style 2 args={
    x filter/.code={
        \ifnum\coordindex<#1\def\pgfmathresult{}\fi
        \ifnum\coordindex>#2\def\pgfmathresult{}\fi
    }
}}

\newcommand{\rowlength}{12}

%For a 3x2 matrix output, need 4x3 input..., with a mesh/rows=4 OR a mesh/cols=3
\pgfplotsset{table/col sep = comma,table/row sep=\\}
\pgfplotstableread{%
0,0,0.1\\0,1,1.0\\0,2,0\\1,0,0\\1,1,0.8\\1,2,0\\2,0,0.4\\2,1,0.6\\2,2,0\\3,0,0\\3,1,0\\3,2,0\\% First 'row'
0,0,0.5\\0,1,4\\0,2,0\\1,0,0\\1,1,3\\1,2,0\\2,0,1\\2,1,2\\2,2,0\\3,0,4\\3,1,4\\3,2,0\\}\data

%\begin{animateinline}[controls,autopause,autoresume]{2}
%  \multiframe{2}{blah=0+1}{%
\foreach \blah in {0,1}{
  \pgfmathparse{\blah*\rowlength}
  \let\startrow=\pgfmathresult
  \pgfmathparse{\startrow+\rowlength-1}
  \let\endrow=\pgfmathresult
  \begin{tikzpicture}
    \begin{axis}[
      view={0}{90},
      colorbar,
      xtick=data,
      xticklabels={NotGuilty,Corporal,Death,},
      x tick label style={anchor=north,yshift=0cm,xshift=1.3cm},
      ytick=data,
      y tick label style={anchor=east,yshift=1.3cm,xshift=0cm},
      yticklabels={BreakingPeace,Damage,}
    ]
      \addplot3[
        surf,
        shader=flat corner,
  %       mesh/rows=4,
        mesh/cols=3,
        mesh/ordering=rowwise,
        select coords between index={\startrow}{\endrow}
      ] table {\data};
    \end{axis}
  \end{tikzpicture}
}
%\end{animateinline}

\end{document}

Still back patting self,

I could not find a solution to the above so I placed all the data in the expected format using python and a bit of regex find and replace giving the solution below:

Using:

% Style to select only points from #1 to #2 (inclusive), needed by animate
\pgfplotsset{select coords between index/.style 2 args={
    x filter/.code={
        \ifnum\coordindex<#1\def\pgfmathresult{}\fi
        \ifnum\coordindex>#2\def\pgfmathresult{}\fi
    }
}}

from https://tex.stackexchange.com/a/199396/4621

 \newcommand{\offencepunishmentGridAnimation}{

  \pgfplotstableread{Resources/Data/Plots/OffPunMatrix.csv}\data
  \newcommand{\rowlength}{80}
  \begin{figure}[!htb]
    \begin{animateinline}[controls,autopause,autoresume]{2}
    \multiframe{119}{i=0+1}{%
  %   \foreach \i in {0}{
      \pgfmathparse{\i*\rowlength}
      \let\startrow=\pgfmathresult
      \pgfmathparse{\startrow+\rowlength-1}
      \let\endrow=\pgfmathresult
      \tikzsetnextfilename{OffPunMatrix\i}
      \begin{tikzpicture}
        \begin{axis}[
          view={0}{90},
          colorbar,
          xtick=data,
          xticklabels={BreakingPeace,Damage,Deception,Kill,Misc.,RoyalOffence,Sexual,Theft,ViolentTheft},
          x tick label style={anchor=west,rotate=-45,yshift=0cm,xshift=0.2cm},
          ytick=data,
          y tick label style={anchor=east,yshift=0.5cm,xshift=0cm},
          yticklabels={NotGuilty,Corporal,Death,Imprison,MiscPunish,NoPunish,Transport},
          point meta max=0.7071,
          point meta = sqrt(z),
          colorbar style={
    %         ylabel=Probability,
            ytick={0,0.14,0.28,0.42,0.56,0.7},
            yticklabels = {0,0.1,0.2,0.3,0.4,0.5},
          }
        ]
          \addplot3[
            surf,
            shader=flat corner,
    %         mesh/rows=8,
            mesh/cols=8,
            mesh/ordering=rowwise,
            select coords between index={\startrow}{\endrow}
          ] table {\data};
        \end{axis}
          \draw[black,line width = 1]  (0,9) node[left] {Year\ }--(11.6,9);
          \pgfmathparse{int(1674+2*\i)}
          \let\year=\pgfmathresult
          \fill (0.09747899159663865546*\i,9) circle (2pt) node[above] {\year};
      \end{tikzpicture}
      }
    \end{animateinline}
    \caption[Offence Punishment grid]{Offence punishment grid animation, where the colour in a square represents the estimate for the occurence.}
    \label{anim:offpungrid}
  \end{figure}
}

Where the data file looks like:

0,0,0.0148148148148
0,1,0.00740740740741
0,2,0.00740740740741
0,3,0.00740740740741
0,4,0.0148148148148
0,5,0.00740740740741
0,6,0.00740740740741
0,7,0
1,0,0.0148148148148
1,1,0.00740740740741
1,2,0.00740740740741
1,3,0.00740740740741
1,4,0.00740740740741
1,5,0.00740740740741
1,6,0.00740740740741
1,7,0
2,0,0.00740740740741
2,1,0.0148148148148
2,2,0.00740740740741
2,3,0.00740740740741
2,4,0.0148148148148
2,5,0.00740740740741
2,6,0.00740740740741
2,7,0
3,0,0.0148148148148
3,1,0.00740740740741
3,2,0.0814814814815
3,3,0.00740740740741
3,4,0.00740740740741
3,5,0.00740740740741
3,6,0.00740740740741
3,7,0
4,0,0.00740740740741
4,1,0.00740740740741
4,2,0.0148148148148
4,3,0.00740740740741
4,4,0.0148148148148
4,5,0.00740740740741
4,6,0.00740740740741
4,7,0
5,0,0.0222222222222
5,1,0.0148148148148
5,2,0.0222222222222
5,3,0.00740740740741
5,4,0.0222222222222
5,5,0.00740740740741
5,6,0.00740740740741
5,7,0
6,0,0.037037037037
6,1,0.00740740740741
6,2,0.00740740740741
6,3,0.00740740740741
6,4,0.0148148148148
6,5,0.00740740740741
6,6,0.00740740740741
6,7,0
7,0,0.0740740740741
7,1,0.0296296296296
7,2,0.148148148148
7,3,0.00740740740741
7,4,0.0222222222222
7,5,0.00740740740741
7,6,0.0222222222222
7,7,0
8,0,0.0296296296296
8,1,0.00740740740741
8,2,0.0296296296296
8,3,0.00740740740741
8,4,0.0148148148148
8,5,0.00740740740741
8,6,0.00740740740741
8,7,0
9,0,0
9,1,0
9,2,0
9,3,0
9,4,0
9,5,0
9,6,0
9,7,0
0,0,0.00595238095238
0,1,0.00595238095238
0,2,0.0119047619048
0,3,0.00595238095238
0,4,0.00595238095238
0,5,0.00595238095238
0,6,0.00595238095238
0,7,0
1,0,0.0119047619048
1,1,0.00595238095238
1,2,0.00595238095238
1,3,0.00595238095238
1,4,0.00595238095238
1,5,0.00595238095238
1,6,0.00595238095238
1,7,0
2,0,0.00595238095238
2,1,0.0119047619048
2,2,0.00595238095238
2,3,0.00595238095238
2,4,0.00595238095238
2,5,0.00595238095238
2,6,0.00595238095238
2,7,0
3,0,0.10119047619
3,1,0.00595238095238
3,2,0.0238095238095
3,3,0.00595238095238
3,4,0.0238095238095
3,5,0.00595238095238
3,6,0.00595238095238
3,7,0
4,0,0.0119047619048
4,1,0.00595238095238
4,2,0.0119047619048
4,3,0.00595238095238
4,4,0.00595238095238
4,5,0.00595238095238
4,6,0.00595238095238
4,7,0
5,0,0.0357142857143
5,1,0.0119047619048
5,2,0.0119047619048
5,3,0.00595238095238
5,4,0.0178571428571
5,5,0.00595238095238
5,6,0.00595238095238
5,7,0
6,0,0.0297619047619
6,1,0.00595238095238
6,2,0.0357142857143
6,3,0.00595238095238
6,4,0.0119047619048
6,5,0.00595238095238
6,6,0.00595238095238
6,7,0
7,0,0.190476190476
7,1,0.0178571428571
7,2,0.0833333333333
7,3,0.00595238095238
7,4,0.047619047619
7,5,0.00595238095238
7,6,0.0119047619048
7,7,0
8,0,0.0238095238095
8,1,0.00595238095238
8,2,0.0178571428571
8,3,0.00595238095238
8,4,0.00595238095238
8,5,0.00595238095238
8,6,0.00595238095238
8,7,0
9,0,0
9,1,0
9,2,0
9,3,0
9,4,0
9,5,0
9,6,0
9,7,0

etc. Hope this helps someone one day, and maybe motivates a simpler solution in pgfplots.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .