4

I want to plot a matrix of color-values from a csv file. Inspired by this website, I set out to write my MWE below, to which I added this way of dynamically loading symbolic ticks/labels from my data file.

However, It turns out that my resulting ticks/labels are not distinct, but instead are repeated, like my rendering shows.
Another way to think of it (according to @Jake's comments) is that flexible (x|y)ticklabels from table does not tell PGFplots that these labels are supposed to be symbolic, as doing it manually using symbolic (x|y) coords would.

How can I tell PGFplots that all distinct values from the xitem and yitem columns in my data file are to be used as symbolic labels?
Maybe the problem lies within (x|y) expr=\coordindex. What I want here is to fill in the (symbolic, not numerical) value from the respective colum (xitem|yitem). But using x=xitem,y=yitem, instead gives the error "Package PGF Math Error: Could not parse input 'X' as a floating point number".

Rendering:
not distinct

MWE:

\documentclass{standalone}

\usepackage{filecontents}
\usepackage{pgfplots, pgfplotstable}

\begin{filecontents}{data.csv}
yitem,xitem,val
r,X,0.1
r,Y,0.2
r,Z,0.3
d,X,0.4
d,Y,0.5
d,Z,0.6
j,X,0.5
j,Y,0.8
j,Z,0.9
\end{filecontents}

\pgfplotstableread[col sep=comma]{data.csv}\datatable
\makeatletter
\pgfplotsset{
    /pgfplots/flexible xticklabels from table/.code n args={3}{
        \pgfplotstableread[#3]{#1}\coordinate@table
        \pgfplotstablegetcolumn{#2}\of{\coordinate@table}\to\pgfplots@xticklabels
        \let\pgfplots@xticklabel=\pgfplots@user@ticklabel@list@x
    },
    /pgfplots/flexible yticklabels from table/.code n args={3}{
        \pgfplotstableread[#3]{#1}\coordinate@table
        \pgfplotstablegetcolumn{#2}\of{\coordinate@table}\to\pgfplots@yticklabels
        \let\pgfplots@yticklabel=\pgfplots@user@ticklabel@list@y
    }
}
\makeatother

\begin{document}
\begin{tikzpicture}
\begin{axis}[
    flexible xticklabels from table={data.csv}{xitem}{col sep=comma},
    xtick=data,
    flexible yticklabels from table={data.csv}{yitem}{col sep=comma},
    ytick=data,
    unbounded coords=jump,
]
\addplot[
    mark=square*,
    only marks,
    scatter,
    point meta=explicit,
] table [
    col sep=comma,
    x expr=\coordindex,
    y expr=\coordindex,
    meta expr=\thisrow{val},
] {\datatable};

\end{axis}
\end{tikzpicture}
\end{document}
derabbink
  • 1,640
  • With the table you currently use, you'll need to use symbolic x coords={a,b,c} and symbolic y coords={X,Y,Z} (while also removing x expr=\coordindex, y expr=\coordindex). That's a bit cumbersome to work with, though. There might be better ways to organise your data. How do you generate your data table? – Jake Jan 13 '14 at 15:26
  • The table I posed here is just an example; My actual use case contains 25000 rows and 30 columns. I wish there was a way to adapt flexible (x|y)ticklabels from table in a way that it filters duplicates. But I don't know how. – derabbink Jan 13 '14 at 15:35
  • 1
    flexible ticklabels from table won't help here, because that's just for generating the labels, but not the coordinates. You're currently plotting the data points at (i|i), where i is the coordinate index, so filtering duplicates out of the labels won't help you. Rather, you need to map a, b, c... to x=1, 2, 3... and X, Y, Z to y=1, 2, 3... (which is what symbolic x coords does). – Jake Jan 13 '14 at 15:38
  • If you could create a table that contains proper numerical coordinates instead of the symbolic ones, things would be much easier. – Jake Jan 13 '14 at 15:39
  • I can generate numbers/IDs representing a,b,c and X,Y,Z, but eventually I need these original values (not the IDs) to be written near the axes. – derabbink Jan 13 '14 at 15:42
  • It cannot be assumed for both the yitem or xitem columns that labels are sorted. It is important though, that ticklabels end up in order of first appearance. I have updated the question's MWE to reflect that. – derabbink Jan 14 '14 at 07:43
  • You need to define how to map the letters to Cartesian coordinates. How do you want to specify that the point (r|X) should be plotted below and left of the point (d|Y)? I think it would be good if you could update your question to explain in a bit more detail what kind of data we're dealing with here. – Jake Jan 14 '14 at 07:44
  • I have updated the question. Please see my remarks regarding (x|y) expr=\coordindex and symbolic (x|y) coords. – derabbink Jan 14 '14 at 07:58

1 Answers1

4

You need to generate the mapping from the symbolic coordinates to Cartesian coordinates. If the Cartesian coordinates correspond to the rank of the first appearance of a symbol in a column, you can use the etoolbox package to generate a list that represents the mapping, and then use symbolic x coords to pass that mapping to PGFPlots:

\documentclass[border=5mm]{article}

\usepackage{filecontents}
\usepackage{pgfplots, pgfplotstable}
\usepackage{etoolbox}

\begin{filecontents}{data.csv}
yitem,xitem,val
a,X,0.1
a,Y,0.2
a,Z,0.3
b,X,0.4
b,Y,0.5
b,Z,0.6
c,X,0.5
c,Y,0.8
c,Z,0.9
\end{filecontents}

\pgfplotstableread[col sep=comma]{data.csv}\datatable


\begin{document}
\def\xlistmacro{}
\def\xliststring{}
\pgfplotstableforeachcolumnelement{xitem}\of\datatable\as\entry{%
\xifinlist{\entry}{\xlistmacro}{}{
        \listxadd{\xlistmacro}{\entry}
        \edef\xliststring{\xliststring\entry,}
    }
}

\def\ylistmacro{}
\def\yliststring{}
\pgfplotstableforeachcolumnelement{yitem}\of\datatable\as\entry{%
\xifinlist{\entry}{\ylistmacro}{}{
        \listxadd{\ylistmacro}{\entry}
        \edef\yliststring{\yliststring\entry,}
    }
}

\begin{tikzpicture}
\begin{axis}[
    xtick=data,
    ytick=data,
    symbolic x coords/.expand once={\xliststring},
    symbolic y coords/.expand once={\yliststring},
]
\addplot[
    mark=square*,
    only marks,
    scatter,
    point meta=explicit,
] table [
    col sep=comma,
    meta expr=\thisrow{val},
    x=xitem, y=yitem
] {\datatable};

\end{axis}
\end{tikzpicture}
\end{document}
Jake
  • 232,450