无需外部程序即可生成三维直方图

无需外部程序即可生成三维直方图

我在以下帖子中找到了 @marmot 的答案,它看起来非常好,不需要任何外部程序。但我在根据我的数据调整 z 轴时遇到了一些问题。

pgfplots 中的三维直方图

在此示例中,我的数据的 z 值不在 0 到 100 之间,而是在 0 到 1000 之间。我不明白“此处必须作弊”这部分。我需要对不在 0 到 100 之间的 z 值进行哪些调整?

\documentclass[tikz,border=3.14pt]{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.15}
\begin{document}
\pgfplotstableread[col sep=comma,header=true]{%
x,y,color,myvalue
2,3,1,1000
4,3,2,30
2,7,3,0.75
7,7,4,450
8,5,2,300
2,5,1,100
4,-4,2,1
4,1,3,750
5,-1,4,4
5,2,2,300
1,-2,1,100
2,5,2,5
3,-8,3,750
4,5,4,420
7,-2,2,200
}{\datatable}
%
\pgfplotstablesort[col sep=comma,header=true]\resulttable{\datatable}
\begin{tikzpicture}%[x={(0.866cm,-0.5cm)},y={(0.866cm,0.5cm)},z={(0cm,1 cm)}]
\pgfplotsset{set layers}
\begin{axis}[% from section 4.6.4 of the pgfplotsmanual
        view={120}{40},
        width=320pt,
        height=280pt,
        z buffer=none,
        xmin=-1,xmax=8,
        ymin=-10,ymax=8,
        zmin=0,zmax=1000,
        enlargelimits=upper,
        ztick={0,500,1000},
        zticklabels={0,500,1000}, % here one has to "cheat"
        xtick=data,
        extra tick style={grid=major},
        ytick=data,
        grid=minor,
        xlabel={$x$},
        ylabel={$y$},
        zlabel={$z$},
        minor tick num=1,
        point meta=explicit,
        colormap name=viridis,
        scatter/use mapped color={
            draw=mapped color,fill=mapped color!70},
        ]
\addplot3 [visualization depends on={z \as \myz},
scatter/@pre marker code/.append style={/pgfplots/cube/size z=\myz},%
scatter,only marks,
mark=cube*,mark size=5]
 table[x expr={\thisrow{x}},y expr={\thisrow{y}},z
 expr={\thisrow{myvalue}},
 meta expr={\thisrow{color}}
        ] \resulttable;
    \end{axis}
\end{tikzpicture}
\end{document}

结果:

在此处输入图片描述

编辑:现在,在 Marmot 提出了绘制 3D 直方图的非常好的解决方案之后,我想问是否可以通过计算条形的深度和宽度使其更加自动化?

补充:我有一些数据集,其 x 和 y 方向的范围非常大。当我按照建议在 x 和 y 方向上更改立方体大小时,我得到的条形非常小(见下面的第一张图)。我的数据是一个分类,其中范围分为 64 或 100 个类。因此,一个条形需要与范围除以 x 和 y 方向的 64 或 100 一样大。marmot 建议的解决方案工作正常,但在这个特定情况下,立方体大小太小。它表示 x 方向为 0,00192pt,y 方向为 0,00272pt。现在我正在手动计算立方体大小。我取 marmot 给出的值,将它们乘以我的范围,然后将它们除以我的类。对于 x 方向:0,00192pt*65000/64=1,95pt,对于 y:0,00272pt*65000/64=2,7625pt。 (第二幅图的结果)我该如何使其适应代码?

在此处输入图片描述

在此处输入图片描述

答案1

在这种情况下,您还需要调整高度。请注意,您还会在相同的xy值处绘制一些条形图。此技巧的当前版本不支持此功能。在修复此问题之前,我想知道您是否真的想在相同的 xy 位置绘制它们。 更新:我添加了一个改进排序。猜猜我从谁那里偷来的。(提示:他的姓氏以“F”开头,以“euersänger”结尾;-)另一更新:我让事情变得更加自动化。由于常见的扩展问题,我无法使转换完全自动化,但现在至少它会告诉你要放什么。

\documentclass[tikz,border=3.14pt]{standalone}
\usetikzlibrary{calc}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.16}
% from https://tex.stackexchange.com/a/102770/121799
\def\pgfplotsinvokeiflessthan#1#2#3#4{%
    \pgfkeysvalueof{/pgfplots/iflessthan/.@cmd}{#1}{#2}{#3}{#4}\pgfeov
}%
\def\pgfplotsmulticmpthree#1#2#3#4#5#6\do#7#8{%
    \pgfplotsset{float <}%
    \pgfplotsinvokeiflessthan{#1}{#4}{%
        % first key <:
        #7%
    }{%
        \pgfplotsinvokeiflessthan{#4}{#1}{%
            % first key >:
            #8%
        }{%
            % first key ==:
            \pgfplotsset{float <}%
            \pgfplotsinvokeiflessthan{#2}{#5}{%
                % second key <
                #7%
            }{%
                \pgfplotsinvokeiflessthan{#5}{#2}{%
                    % second key >
                    #8%
                }{%
                    % second key ==
                    \pgfplotsset{float <}%
                    \pgfplotsinvokeiflessthan{#3}{#6}{%
                        % third key <
                        #7%
                    }{%
                        % third key >=
                        #8%
                    }%
                }%
            }%
        }%
    }%
}%

\begin{document}
\pgfplotstableread[col sep=comma,header=true]{%
x,y,color,myvalue
2,3,1,1000
4,3,2,30
2,7,3,0.75
7,7,4,450
8,5,2,300
2,5,1,100
4,-4,2,1
4,1,3,750
5,-1,4,4
5,2,2,300
1,-2,1,100
2,5,2,5
3,-8,3,750
4,5,4,420
7,-2,2,200
}{\datatable}
%
%\pgfplotstablesort[col sep=comma,header=true]\resulttable{\datatable}
\pgfplotstablesort[create on use/sortkey/.style={
        create col/assign/.code={%
            \edef\entry{{\thisrow{x}}{\thisrow{y}}{\thisrow{myvalue}}}%
            \pgfkeyslet{/pgfplots/table/create col/next content}\entry
        }
    },
    sort key=sortkey,
    sort cmp={%
        iflessthan/.code args={#1#2#3#4}{%
            \edef\temp{#1#2}%
            \expandafter\pgfplotsmulticmpthree\temp\do{#3}{#4}%
        },
    },
    sort,
    columns/Mtx/.style={string type},
    columns/Kind/.style={string type},]\resulttable{\datatable}

\begin{tikzpicture}%[x={(0.866cm,-0.5cm)},y={(0.866cm,0.5cm)},z={(0cm,1 cm)}]
\pgfplotsset{set layers}
\begin{axis}[% from section 4.6.4 of the pgfplotsmanual
        view={120}{40},
        width=320pt,
        height=280pt,
        z buffer=none,
        xmin=-1,xmax=9,
        ymin=-10,ymax=8,
        zmin=0,zmax=2000,
        enlargelimits=upper,
        ztick={0,1000,2000},
        zticklabels={0,500,1000}, % here one has to "cheat"
        % meaning that one has to put labels which are the actual value 
        % divided by 2. This is because the bars will be centered at these
        % values
        xtick=data,
        extra tick style={grid=major},
        ytick=data,
        grid=minor,
        xlabel={$x$},
        ylabel={$y$},
        zlabel={$z$},
        minor tick num=1,
        point meta=explicit,
        colormap name=viridis,
        scatter/use mapped color={
            draw=mapped color,fill=mapped color!70},
        execute at begin plot={}            
        ]
\path let \p1=($(axis cs:0,0,1)-(axis cs:0,0,0)$) in 
\pgfextra{\pgfmathsetmacro{\conv}{2*\y1}
\typeout{Kindly\space\space consider\space setting\space the\space 
        prefactor\space of\space z\space to\space \conv}};      
\addplot3 [visualization depends on={
0.09952*z \as \myz}, % you'll get told how to adjust the prefactor
scatter/@pre marker code/.append style={/pgfplots/cube/size z=\myz},%
scatter,only marks,
mark=cube*,mark size=5,opacity=1]
 table[x expr={\thisrow{x}},y expr={\thisrow{y}},z
 expr={1*\thisrow{myvalue}},
 meta expr={\thisrow{color}}
        ] \resulttable;
    \end{axis}
\end{tikzpicture}
\end{document}

在此处输入图片描述

附录:在此版本中,计算了“全尺寸”条形的尺寸,即 x 和 y 尺寸,以使条形在每个方向上填充一个单位。它还会检查用户是否已经设置了正确的 z 比例。它会计算正确的比例因子,并要求您在必要时重新编译。

\documentclass[tikz,border=3.14pt]{standalone}
\usetikzlibrary{calc}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\pgfplotsset{compat=1.16}
% from https://tex.stackexchange.com/a/102770/121799
\def\pgfplotsinvokeiflessthan#1#2#3#4{%
    \pgfkeysvalueof{/pgfplots/iflessthan/.@cmd}{#1}{#2}{#3}{#4}\pgfeov
}%
\def\pgfplotsmulticmpthree#1#2#3#4#5#6\do#7#8{%
    \pgfplotsset{float <}%
    \pgfplotsinvokeiflessthan{#1}{#4}{%
        % first key <:
        #7%
    }{%
        \pgfplotsinvokeiflessthan{#4}{#1}{%
            % first key >:
            #8%
        }{%
            % first key ==:
            \pgfplotsset{float <}%
            \pgfplotsinvokeiflessthan{#2}{#5}{%
                % second key <
                #7%
            }{%
                \pgfplotsinvokeiflessthan{#5}{#2}{%
                    % second key >
                    #8%
                }{%
                    % second key ==
                    \pgfplotsset{float <}%
                    \pgfplotsinvokeiflessthan{#3}{#6}{%
                        % third key <
                        #7%
                    }{%
                        % third key >=
                        #8%
                    }%
                }%
            }%
        }%
    }%
}%

\begin{document}
\ifdefined\gconv
\else
\pgfmathsetmacro{\gconv}{0.1}
\fi
\pgfplotstableread[col sep=comma,header=true]{%
x,y,color,myvalue
2,3,1,1000
4,3,2,30
2,7,3,0.75
7,7,4,450
8,5,2,300
2,5,1,100
4,-4,2,1
4,1,3,750
5,-1,4,4
5,2,2,300
1,-2,1,100
2,5,2,5
3,-8,3,750
4,5,4,420
7,-2,2,200
}{\datatable}
%
%\pgfplotstablesort[col sep=comma,header=true]\resulttable{\datatable}
\pgfplotstablesort[create on use/sortkey/.style={
        create col/assign/.code={%
            \edef\entry{{\thisrow{x}}{\thisrow{y}}{\thisrow{myvalue}}}%
            \pgfkeyslet{/pgfplots/table/create col/next content}\entry
        }
    },
    sort key=sortkey,
    sort cmp={%
        iflessthan/.code args={#1#2#3#4}{%
            \edef\temp{#1#2}%
            \expandafter\pgfplotsmulticmpthree\temp\do{#3}{#4}%
        },
    },
    sort,
    columns/Mtx/.style={string type},
    columns/Kind/.style={string type},]\resulttable{\datatable}

\begin{tikzpicture}%[x={(0.866cm,-0.5cm)},y={(0.866cm,0.5cm)},z={(0cm,1 cm)}]
\pgfplotsset{set layers}
\begin{axis}[% from section 4.6.4 of the pgfplotsmanual
        view={120}{40},
        width=320pt,
        height=280pt,
        z buffer=none,
        xmin=-1,xmax=9,
        ymin=-10,ymax=8,
        zmin=0,zmax=2000,
        enlargelimits=upper,
        ztick={0,1000,2000},
        zticklabels={0,500,1000}, % here one has to "cheat"
        % meaning that one has to put labels which are the actual value 
        % divided by 2. This is because the bars will be centered at these
        % values
        xtick=data,
        extra tick style={grid=major},
        ytick=data,
        grid=minor,
        xlabel={$x$},
        ylabel={$y$},
        zlabel={$z$},
        minor tick num=1,
        point meta=explicit,
        colormap name=viridis,
        scatter/use mapped color={
            draw=mapped color,fill=mapped color!70},
        execute at begin plot={}            
        ]
\path let \p1=($(axis cs:0,0,1)-(axis cs:0,0,0)$) in 
\pgfextra{\pgfmathsetmacro{\conv}{2*\y1}
\ifx\gconv\conv
\else
\xdef\gconv{\conv}
\typeout{Please\space recompile\space the\space file!}
\fi     
        };  
\path let \p1=($(axis cs:1,0,0)-(axis cs:0,0,0)$) in 
\pgfextra{\pgfmathsetmacro{\convx}{veclen(\x1,\y1)}
\typeout{One\space unit\space in\space x\space 
        direction\space is\space\convx pt}
        };                  
\path let \p1=($(axis cs:0,1,0)-(axis cs:0,0,0)$) in 
\pgfextra{\pgfmathsetmacro{\convy}{veclen(\x1,\y1)}
\typeout{One\space unit\space in\space y\space 
        direction\space is\space\convy pt}
        };                  
\addplot3 [visualization depends on={
\gconv*z \as \myz}, % you may have to recompile to get the prefactor right
scatter/@pre marker code/.append style={/pgfplots/cube/size z=\myz},%
scatter/@pre marker code/.append style={/pgfplots/cube/size x=11.66135pt},%
scatter/@pre marker code/.append style={/pgfplots/cube/size y=9.10493pt},%
scatter,only marks,
mark=cube*,mark size=5,opacity=1]
 table[x expr={\thisrow{x}},y expr={\thisrow{y}},z
 expr={1*\thisrow{myvalue}},
 meta expr={\thisrow{color}}
        ] \resulttable;
    \end{axis}
\makeatletter
\immediate\write\@mainaux{\xdef\string\gconv{\gconv}\relax}
\makeatother

\end{tikzpicture}
\end{document}

在此处输入图片描述

相关内容