使用 pgfplots 绘制气候图(气候图)

使用 pgfplots 绘制气候图(气候图)

我想用 创建气候图 (climographs) pgfplots,但这些图表对于轴缩放有一些特殊规则(大约 50 年前由 Walter 和 Lieth 定义),我完全不知道如何使用 来实现pgfplots,因为第二个 y 轴缩放可以在中间更改,并且两个 y 轴的缩放相互耦合。示例如下。

规则:如果不存在低于零度的温度,则左侧 y 轴(温度 T)以 10°C 为单位从零度开始缩放,否则也会以 10°C 为单位从零度以下开始扩展。这仍然是简单的部分(我可以做到),现在是困难的部分:右侧 y 轴(降雨量)以 T 值的两倍缩放,最高可达 300 毫米。但如果存在 300 毫米以上的降雨,则以 200 毫米为单位从 100 毫米开始缩放。右轴永远不会低于零度。

我的问题是:我必须使用哪些命令才能根据输入值动态更改轴缩放比例并将轴相互耦合?{x,y}{min,max}tick朋友肯定是不够的。 我知道使用 pgfplots 绘图的基础知识,但我完全不知道从哪里开始这种动态缩放方法,也不知道其中有多少是我必须自己计算的(使用自己的代码)以及有多少pgfplots可以为我做。 例如,我显然需要以某种方式解析输入数据以找到最大值,但我不知道如何在 中做到这一点pgfplots

为了便于操作,以下是第一个示例中的数据:

#bombay.txt
#M T/°C N/mm
 1 23.9    3
 2 23.9    3
 3 26.1    3
 4 28.1    2
 5 29.7   18
 6 28.9  485
 7 27.2  617
 8 27.0  340
 9 27.0  264
10 28.1   64
11 27.2   13
12 25.6    3

这就是我得到的代码,但现在我不知道如何继续(颜色,线条样式,网格等现在并不重要,我可以自己做,只有轴缩放/耦合是个问题):

\documentclass{standalone}
\usepackage{pgfplots} \pgfplotsset{compat=newest}
\usepackage{siunitx}
\begin{document}
\begin{tikzpicture}
  \def\filename{bombay.txt}
  \def\monthnames{{"J","F","Mar","A","May","Jun","Jul","A","S","O","N","D"}}
  \begin{axis}[
        ylabel={Temperature in \si{\celsius}},
        tick pos=left,
        xticklabel={\pgfmathparse{\monthnames[Mod(\tick-1,12)]}\pgfmathresult},
        xmin=1, xmax=12,
        ymin=0, ytick={0,10,20,30,40,50}]
    \addplot+[red, mark=none] table [x index=0, y index=1] {\filename};
  \end{axis}
    \begin{axis}[
        ylabel={Rain in \si{\milli\metre}},
        axis y line*=right,
        hide x axis,
        xmin=1, xmax=12, ymin=0]
    \addplot+[blue, mark=none] table [x index=0, y index=2] {\filename};
  \end{axis}
\end{tikzpicture}
\end{document}

例 1:雨轴缩放比例发生变化(因为 > 300mm),仅 T > 0 在此处输入图片描述

例 2:雨轴不改变比例,因为它始终 < 300mm。T < 0。 在此处输入图片描述

答案1

您需要的可以通过设置样式来实现

  • 配置雨轴的非线性变换
  • 计算两个 y 轴的合适(耦合)轴限值
  • 计算两个 y 轴的合适(耦合)单位
  • 需要手动输入来决定两个轴的起始/结束位置。据我从您的用例中了解,此输入包括最低温度和最高降雨量(另一个限制始终是隐式绑定的)。

我得到了以下先进原型:

\documentclass{standalone}
\usepackage{pgfplots} 
\pgfplotsset{compat=1.9}

  % The following \pgfplotsset macro defines a *manual* wheather
  % visualization system which couples temperature and rain axis.
  \pgfplotsset{
     rain trafo/.style={
        y coord trafo/.code={%
            \pgfmathparse{##1 > 100 ? 100 + 0.1*(##1 - 100) : ##1}%
        },%
        y coord inv trafo/.code={%
            \pgfmathparse{##1 > 100 ? 100 + 10*(##1 - 100) : ##1}%
        },%
        %
        % configure the allowed tick positions for the rain
        % (UNTRANSFORMED!):
        ytick={0,20,...,100,300,500,...,1000},
     },
     %
     /wheather/temp min/.initial=,
     /wheather/rain max/.initial=,
     %
     % USAGE: \pgfkeys{/wheather/set up={temp min=<min temperature>, rain max=<max rain axis value>}
     % It will set up two styles "temp axis" and "rain axis". These
     % styles will contain suitable axis limits and unit scales.
     /wheather/set up/.code={%
        \pgfkeysalso{/wheather/.cd,#1}%
        %
        % these values are supposed to be given:
        \pgfkeysgetvalue{/wheather/rain max}\rainMax
        \pgfkeysgetvalue{/wheather/temp min}\temperatureMin
        %
        % make sure they are given!
        \ifx\rainMax\empty
            \PackageError{wheather}{Please provide 'rain max=MAX RAIN VALUE IN AXIS'}{}%
        \fi
        \ifx\temperatureMin\empty
            \PackageError{wheather}{Please provide 'temp min=MIN TEMPERATURE VALUE IN AXIS'}{}%
        \fi
        %
        % now, compute the MISSING values. These are rain min and
        % temperature max....
        \begingroup
        % do this in a group such that 'rain trafo' is only applied
        % within the group...
        % 
        % store it - just in case 'y coord trafo' is empty.
        \let\pgfmathresult=\rainMax
        %
        \pgfplotsset{rain trafo,y coord trafo={\rainMax}}%
        \global\let\rainMaxTransformed=\pgfmathresult
        \pgfmathparse{\pgfmathresult /2}%
        \global\let\temperatureMax=\pgfmathresult
        \endgroup
        %
        \pgfmathparse{2*(\pgfkeysvalueof{/wheather/temp min})}%
        \let\rainMin=\pgfmathresult
        %
        % now we want to compute a suitable axis scale for both axes.
        % To this end, we scale them such that they fit into the value
        % of  \axisdefaultheight :
        \pgfmathparse{\axisdefaultheight/(\temperatureMax-\temperatureMin)}%
        \let\temperatureUnit=\pgfmathresult
        %
        \pgfmathparse{\axisdefaultheight/(\rainMaxTransformed-\rainMin)}%
        \let\rainUnit=\pgfmathresult
        %
        % OK, compute the result:
        \pgfplotsset{%
            set layers,
            %
            % this is to be used for the temperature axis:
             temp axis/.style={
                y=\temperatureUnit,
                ymin=\temperatureMin,
                ymax=\temperatureMax,
                %
                % configure the allowed tick positions for a temperature:
                ytick={-40,-30,-20,...,140},
                % ... but only show the *label* for "small"
                % temperatures:
                yticklabel={%
                    \ifdim\tick pt<45pt 
                        \pgfmathprintnumber\tick
                    \fi
                },
                ylabel={Temperature},
                %tick pos=left,% seems to fail for 'axis x line=middle'!?
                %
                % configure the x axis:
                axis x line*=middle,
                xmin=1, xmax=12,
                xtick={1,2,...,12},
                xticklabels={J,F,M,A,M,J,J,A,S,O,N,D},
                x tick label as interval,
                grid=major,
             },
             %
             % ... and this is to be used for the rain axis:
             rain axis/.style={
                y=\rainUnit,
                ymin=\rainMin,
                ymax=\rainMax,
                % this range will be overwritten by 'rain trafo' if it
                % is active:
                ytick={0,20,...,400},
                rain trafo,
                yticklabel style={/pgf/number format/precision=0},
                ylabel={Rain},
                axis y line*=right,
                hide x axis,
                xmin=1, xmax=12,
             },
        }%
     },
  }

\begin{filecontents}{bombay.txt}
#bombay.txt
#M T/°C N/mm
 1 23.9    3
 2 23.9    3
 3 26.1    3
 4 28.1    2
 5 29.7   18
 6 28.9  485
 7 27.2  617
 8 27.0  340
 9 27.0  264
10 28.1   64
11 27.2   13
12 25.6    3
\end{filecontents}

\begin{filecontents}{moskow.txt}
#M T/°C N/mm
 1 -10.9    30
 2 -12.9    23
 3 -6.1    30
 4 3.1    40
 5 6.7   50
 6 15.9  60
 7 20.2  61
 8 22.0  50
 9 17.0  45
10 10.1   20
11 3.2   22
12 -9.6    25
\end{filecontents}

\begin{document}
\begin{tikzpicture}

  \pgfplotsset{/wheather/set up={temp min=0, rain max=800}}

  \def\filename{bombay.txt}

  \begin{axis}[
        temp axis,
    ]
    \addplot+[red, mark=none] table [x index=0, y index=1] {\filename};
  \end{axis}
    \begin{axis}[
        rain axis,
    ]
    \addplot+[blue, mark=none] table [x index=0, y index=2] {\filename};
  \end{axis}
\end{tikzpicture}

\begin{tikzpicture}

  \pgfplotsset{
     *clear* the nonlinear rain trafo. We do not want it here:
     rain trafo/.style=,
     /wheather/set up={temp min=-20, rain max=160},
  }

  \def\filename{moskow.txt}

  \begin{axis}[
        temp axis,
    ]
    \addplot+[red, mark=none] table [x index=0, y index=1] {\filename};
  \end{axis}
    \begin{axis}[
        rain axis,
    ]
    \addplot+[blue, mark=none] table [x index=0, y index=2] {\filename};
  \end{axis}
\end{tikzpicture}
\end{document}

在此处输入图片描述

我相信它已经相当不错了,尽管它还剩下几个项目 - 主要是格式和填充路径。

还有一个未解决的问题,实际上是 pgfplots 中的“缺失功能”:只要有人写入axis x line=middle,pgfplots 就不会显示第一个和最后一个刻度标签。对于这个应用程序来说非常不幸。我会把它放在 pgfplots 的待办事项列表中。也许你应该撤消axis x line=middle以解决这个问题。请注意,将 x 个刻度显示为间隔意味着您有 n 个刻度位置的 n-1 个刻度标签。简而言之:您可能需要以某种方式复制 1 月的数据点。

相关内容