Here is an implementation with expl3
. Table rows are stored in a sequence and then each item is split again for building the table body.
The special column can be decided for the single table or set at the outset with
\settable{column=2}
It wouldn't be really difficult to do the treatment to as many columns as you like.
Here's the code:
\begin{filecontents*}{\jobname.csv}
ColA, ColB, ColC
0.17, 0.91, 0.67
0.15, 0.17, 0.92
0.48, 0.1, 0.28
\end{filecontents*}
\documentclass{article}
\usepackage[table,dvipsnames]{xcolor}
\usepackage{xparse}
\ExplSyntaxOn
\ior_new:N \g_kevin_table_readfile_stream
\tl_new:N \l__kevin_table_body_tl
\seq_new:N \l__kevin_table_rows_seq
\seq_new:N \l__kevin_table_singlerow_seq
\keys_define:nn { kevin/table }
{
column .int_set:N = \l__kevin_table_column_int,
upper-bound .fp_set:N = \l__kevin_table_upper_fp,
lower-bound .fp_set:N = \l__kevin_table_lower_fp,
upper-color .tl_set:N = \l__kevin_table_upper_tl,
lower-color .tl_set:N = \l__kevin_table_lower_tl,
normal-color .tl_set:N = \l__kevin_table_normal_tl,
}
\NewDocumentCommand{\settable}{m}
{
\kevin_table_set:n { #1 }
}
\NewDocumentCommand{\buildtable}{O{}m}
{
% #1 = options
% #2 = file name
\group_begin:
\settable{#1}
\kevin_table_build:n { #2 }
\group_end:
}
\cs_new_protected:Nn \kevin_table_set:n
{
\keys_set:nn { kevin/table } { #1 }
}
\cs_new_protected:Nn \kevin_table_build:n
{
\tl_clear:N \l__kevin_table_body_tl
\seq_clear:N \l__kevin_table_rows_seq
\ior_open:Nn \g_kevin_table_readfile_stream { #1 }
\ior_map_inline:Nn \g_kevin_table_readfile_stream
{
\seq_put_right:Nn \l__kevin_table_rows_seq { ##1 }
}
% get the number of columns and the header row
\seq_set_from_clist:Nx \l__kevin_table_singlerow_seq
{
\seq_item:Nn \l__kevin_table_rows_seq { 1 }
}
\tl_put_right:Nx \l__kevin_table_body_tl
{
\seq_use:Nn \l__kevin_table_singlerow_seq { & } \exp_not:N \\
}
% process each row
\int_step_function:nnnN { 2 } { 1 } { \seq_count:N \l__kevin_table_rows_seq } \__kevin_table_process_row:n
% build the table
\begin{tabular}{*{100}{c}}
\tl_use:N \l__kevin_table_body_tl
\end{tabular}
}
\cs_generate_variant:Nn \seq_set_from_clist:Nn { Nx }
\cs_new_protected:Nn \__kevin_table_process_row:n
{
\seq_set_from_clist:Nx \l__kevin_table_singlerow_seq
{
\seq_item:Nn \l__kevin_table_rows_seq { #1 }
}
\int_step_inline:nnnn { 1 } { 1 } { \seq_count:N \l__kevin_table_singlerow_seq }
{
\tl_put_right:Nx \l__kevin_table_body_tl
{
\int_compare:nF { ##1 = 1 } { & }
\int_compare:nT { ##1 = \l__kevin_table_column_int }
{
\__kevin_table_addcolor:n { \seq_item:Nn \l__kevin_table_singlerow_seq { ##1 } }
}
\seq_item:Nn \l__kevin_table_singlerow_seq { ##1 }
}
}
\tl_put_right:Nn \l__kevin_table_body_tl { \\ }
}
\cs_new_protected:Nn \__kevin_table_addcolor:n
{
\fp_compare:nTF { #1 >= \l__kevin_table_upper_fp }
{ \cellcolor{\l__kevin_table_upper_tl} }
{
\fp_compare:nTF { #1 <= \l__kevin_table_lower_fp }
{ \cellcolor{\l__kevin_table_lower_tl} }
{ \cellcolor{\l__kevin_table_normal_tl} }
}
}
\ExplSyntaxOff
\settable{upper-color=red,lower-color=blue,normal-color=orange}
\begin{document}
\buildtable[column=2,upper-bound=1,lower-bound=0.1]{\jobname.csv}
\bigskip
\buildtable[column=2,upper-bound=0.5,lower-bound=0.1]{\jobname.csv}
\end{document}

A different version where you can do the coloring in as many columns as you please.
\begin{filecontents*}{\jobname.csv}
ColA, ColB, ColC
0.17, 0.91, 0.67
0.15, 0.17, 0.92
0.48, 0.1, 0.28
\end{filecontents*}
\documentclass{article}
\usepackage[table,dvipsnames]{xcolor}
\usepackage{xparse}
\ExplSyntaxOn
\ior_new:N \g_kevin_table_readfile_stream
\tl_new:N \l__kevin_table_body_tl
\seq_new:N \l__kevin_table_rows_seq
\seq_new:N \l__kevin_table_singlerow_seq
\keys_define:nn { kevin/table }
{
column .clist_set:N = \l__kevin_table_column_clist,
upper-bound .fp_set:N = \l__kevin_table_upper_fp,
lower-bound .fp_set:N = \l__kevin_table_lower_fp,
upper-color .tl_set:N = \l__kevin_table_upper_tl,
lower-color .tl_set:N = \l__kevin_table_lower_tl,
normal-color .tl_set:N = \l__kevin_table_normal_tl,
}
\NewDocumentCommand{\settable}{m}
{
\kevin_table_set:n { #1 }
}
\NewDocumentCommand{\buildtable}{O{}m}
{
% #1 = options
% #2 = file name
\group_begin:
\settable{#1}
\kevin_table_build:n { #2 }
\group_end:
}
\cs_new_protected:Nn \kevin_table_set:n
{
\keys_set:nn { kevin/table } { #1 }
}
\cs_new_protected:Nn \kevin_table_build:n
{
\tl_clear:N \l__kevin_table_body_tl
\seq_clear:N \l__kevin_table_rows_seq
\ior_open:Nn \g_kevin_table_readfile_stream { #1 }
\ior_map_inline:Nn \g_kevin_table_readfile_stream
{
\seq_put_right:Nn \l__kevin_table_rows_seq { ##1 }
}
% get the number of columns and the header row
\seq_set_from_clist:Nx \l__kevin_table_singlerow_seq
{
\seq_item:Nn \l__kevin_table_rows_seq { 1 }
}
\tl_put_right:Nx \l__kevin_table_body_tl
{
\seq_use:Nn \l__kevin_table_singlerow_seq { & } \exp_not:N \\
}
% process each row
\int_step_function:nnnN { 2 } { 1 } { \seq_count:N \l__kevin_table_rows_seq } \__kevin_table_process_row:n
% build the table
\begin{tabular}{*{100}{c}}
\tl_use:N \l__kevin_table_body_tl
\end{tabular}
}
\cs_generate_variant:Nn \seq_set_from_clist:Nn { Nx }
\cs_new_protected:Nn \__kevin_table_process_row:n
{
\seq_set_from_clist:Nx \l__kevin_table_singlerow_seq
{
\seq_item:Nn \l__kevin_table_rows_seq { #1 }
}
\int_step_inline:nnnn { 1 } { 1 } { \seq_count:N \l__kevin_table_singlerow_seq }
{
\int_compare:nF { ##1 = 1 } { \tl_put_right:Nn \l__kevin_table_body_tl { & } }
\clist_if_in:NnT \l__kevin_table_column_clist { ##1 }
{
\tl_put_right:Nx \l__kevin_table_body_tl
{
\__kevin_table_addcolor:n { \seq_item:Nn \l__kevin_table_singlerow_seq { ##1 } }
}
}
\tl_put_right:Nx \l__kevin_table_body_tl
{
\seq_item:Nn \l__kevin_table_singlerow_seq { ##1 }
}
}
\tl_put_right:Nn \l__kevin_table_body_tl { \\ }
}
\cs_new_protected:Nn \__kevin_table_addcolor:n
{
\fp_compare:nTF { #1 >= \l__kevin_table_upper_fp }
{ \cellcolor{\l__kevin_table_upper_tl} }
{
\fp_compare:nTF { #1 <= \l__kevin_table_lower_fp }
{ \cellcolor{\l__kevin_table_lower_tl} }
{ \cellcolor{\l__kevin_table_normal_tl} }
}
}
\ExplSyntaxOff
\settable{upper-color=red,lower-color=blue,normal-color=orange}
\begin{document}
\buildtable[column=2,upper-bound=1,lower-bound=0.1]{\jobname.csv}
\bigskip
\buildtable[column={2,3},upper-bound=0.5,lower-bound=0.1]{\jobname.csv}
\bigskip
\buildtable[column={1,3},upper-bound=0.5,lower-bound=0.1]{\jobname.csv}
\end{document}

\ForEachX
statement will work better? I've tried it but can't get that working either. From what I've found online, it looks like the\ForEachX
needs to be split by something, and mine isn't. It's strange because my MWE doesn't give any errors. It just doesn't work.