%20com%20pgfplots.png)
Eu gostaria de criar climógrafos (diagramas climáticos) com pgfplots
, mas esses gráficos têm algumas regras especiais (definidas por Walter e Lieth há cerca de 50 anos) para dimensionamento de eixos que não tenho absolutamente nenhuma ideia de como realizar pgfplots
, porque o segundo eixo y a escala pode mudar entre si e as escalas de ambos os eixos y são acopladas entre si. Exemplos abaixo.
Regras: O eixo y esquerdo (temperatura T) escala em passos de 10°C começando em zero se não existir temperatura abaixo de zero, caso contrário também se estende em passos de 10°C abaixo de zero. Esta ainda é a parte fácil (eu posso fazer isso), agora a parte difícil: o eixo y direito (quantidade de chuva) é dimensionado com duas vezes o valor de T até 300 mm. Mas se existir chuva acima de 300 mm, ela aumenta em etapas de 200 mm, começando em 100 mm. O eixo direito nunca fica abaixo de zero.
Minha pergunta é: Quais são os comandos que devo usar para alterar dinamicamente a escala do eixo dependendo dos valores de entrada e para acoplar os eixos entre si? {x,y}{min,max}
, tick
e amigos certamente não são suficientes. Eu conheço o básico da plotagem com pgfplots, mas não tenho absolutamente nenhuma ideia de por onde começar essa abordagem de escalonamento dinâmico ou quanto disso eu mesmo tenho que calcular (com código próprio) e quanto pgfplots
posso fazer por mim. Por exemplo, obviamente precisei analisar os dados de entrada de alguma forma para encontrar valores máximos, mas não tenho ideia de como fazer isso em pgfplots
.
Para ter algo com que trabalhar, aqui estão os dados do primeiro exemplo:
#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
E foi assim que aprendi o código, mas agora não sei como proceder (cores, estilos de linha, grade, etc. não importam por enquanto, posso fazer isso sozinho, apenas a escala/acoplamento do eixo é o problema):
\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}
Ex 1: Mudança de escala do eixo de chuva (porque > 300mm), apenas T > 0
Exemplo 2: Eixo chuva não muda de escala porque é sempre < 300mm. T < 0.
Responder1
O que você precisa é possível com uma configuração de estilo que
- configura a transformação não linear para o eixo chuva
- calcula limites de eixo adequados (acoplados) para ambos os eixos y
- calcula unidades adequadas (acopladas) para ambos os eixos y
- requer entrada manual para decidir onde ambos os eixos começam/terminam. Pelo que entendi do seu caso de uso, essa entrada consiste na temperatura mínima e no nível máximo de chuva (o outro limite é sempre vinculado implicitamente).
Cheguei ao seguinte protótipo avançado:
\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}
Acredito que já esteja muito bom, embora ainda restem alguns itens - principalmente a formatação e os caminhos de preenchimento.
E há um problema em aberto que é na verdade um "recurso ausente" no pgfplots: assim que alguém escreve axis x line=middle
, o pgfplots não mostra o primeiro e o último rótulo de tick. Muito lamentável para esta aplicação. Vou colocar isso na lista de tarefas do pgfplots. Talvez você deva desfazer axis x line=middle
para corrigir isso. Observe que exibir x ticks como intervalo significa que você tem n-1 rótulos de tick para n posições de tick. Resumindo: talvez você precise replicar o ponto de dados de janeiro de alguma forma.