3

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}
  • 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
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}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.