pgfplots 的自动十次方缩放功能是一项很棒的功能,它使轴上的数字刻度变得清晰(见图)。但是,由于指数值(例如 10^3、10^4)很难在不同但相似的范围内保持一致性(例如,一个图的数据在 8000 到 9000 之间,另一个图的数据在 11000 到 12000 之间)。此外,如果单位是 SI,如果指数不是 3 的倍数,则人们往往会混淆前缀。
有没有办法强制 pgfplots 仅选择 10 的幂(也是 10^3 的幂)的缩放比例?例如,10^6、10^9、10^12,但绝不会是 10^4 或 10^10。
在这个例子中,选择的功率(由 pgfplot 自动选择 10^10),我怎样才能让它自动选择 10^9(在轴旁边的数字中作相应的更改 --乘以 10--)
答案1
缩放由 中的宏处理pgfplotsticks.code.tex
。您可以编辑此宏来实现所需的行为。修补宏后,您可以说
\begin{axis}[scaled ticks=engineering]
\addplot {1/10000*rnd};
\end{axis}
将比例因子限制为三的倍数的指数,即所谓的工程符号:
和\addplot {1/100*rnd};
:
与\addplot {10000*rnd};
:
这是您需要放入序言中的代码块:
\makeatletter
\newif\ifpgfplots@scaled@x@ticks@engineering
\pgfplots@scaled@x@ticks@engineeringfalse
\newif\ifpgfplots@scaled@y@ticks@engineering
\pgfplots@scaled@y@ticks@engineeringfalse
\newif\ifpgfplots@scaled@z@ticks@engineering
\pgfplots@scaled@z@ticks@engineeringfalse
\pgfplotsset{
scaled x ticks/engineering/.code=
\pgfplots@scaled@x@ticks@engineeringtrue,
scaled y ticks/engineering/.code=
\pgfplots@scaled@y@ticks@engineeringtrue,
scaled z ticks/engineering/.code=
\pgfplots@scaled@y@ticks@engineeringtrue,
% scaled ticks=engineering % Uncomment this line if you want "engineering" to be on by default
}
\def\pgfplots@init@scaled@tick@for#1{%
\global\def\pgfplots@glob@TMPa{0}%
\expandafter\pgfplotslistcheckempty\csname pgfplots@prepared@tick@positions@major@#1\endcsname
\ifpgfplotslistempty
% we have no tick labels. Omit the tick scale label as well!
\else
\begingroup
\ifcase\csname pgfplots@scaled@ticks@#1@choice\endcsname\relax
% CASE 0 : scaled #1 ticks=false: do nothing here.
\or
% CASE 1 : scaled #1 ticks=true:
%--------------------------------
% the \pgfplots@xmin@unscaled@as@float is set just before the data
% scale transformation is initialised.
%
% The variables are empty if there is no datascale transformation.
\expandafter\let\expandafter\pgfplots@cur@min@unscaled\csname pgfplots@#1min@unscaled@as@float\endcsname
\expandafter\let\expandafter\pgfplots@cur@max@unscaled\csname pgfplots@#1max@unscaled@as@float\endcsname
%
\ifx\pgfplots@cur@min@unscaled\pgfutil@empty
\edef\pgfplots@loc@TMPa{\csname pgfplots@#1min\endcsname}%
\expandafter\pgfmathfloatparsenumber\expandafter{\pgfplots@loc@TMPa}%
\let\pgfplots@cur@min@unscaled=\pgfmathresult
\edef\pgfplots@loc@TMPa{\csname pgfplots@#1max\endcsname}%
\expandafter\pgfmathfloatparsenumber\expandafter{\pgfplots@loc@TMPa}%
\let\pgfplots@cur@max@unscaled=\pgfmathresult
\fi
%
\expandafter\pgfmathfloat@decompose@E\pgfplots@cur@min@unscaled\relax\pgfmathfloat@a@E
\expandafter\pgfmathfloat@decompose@E\pgfplots@cur@max@unscaled\relax\pgfmathfloat@b@E
\pgfplots@init@scaled@tick@normalize@exponents
\ifnum\pgfmathfloat@b@E<\pgfmathfloat@a@E
\pgfmathfloat@b@E=\pgfmathfloat@a@E
\fi
\xdef\pgfplots@glob@TMPa{\pgfplots@scale@ticks@above@exponent}%
\ifnum\pgfplots@glob@TMPa<\pgfmathfloat@b@E
% ok, scale it:
\expandafter\ifx % Check whether we're using engineering notation (restricting exponents to multiples of three)
\csname ifpgfplots@scaled@#1@ticks@engineering\expandafter\endcsname
\csname iftrue\endcsname
\divide\pgfmathfloat@b@E by 3
\multiply\pgfmathfloat@b@E by 3
\fi
\multiply\pgfmathfloat@b@E by-1
\xdef\pgfplots@glob@TMPa{\the\pgfmathfloat@b@E}%
\else
\xdef\pgfplots@glob@TMPa{\pgfplots@scale@ticks@below@exponent}%
\ifnum\pgfplots@glob@TMPa>\pgfmathfloat@b@E
% ok, scale it:
\expandafter\ifx % Check whether we're using engineering notation (restricting exponents to multiples of three)
\csname ifpgfplots@scaled@#1@ticks@engineering\expandafter\endcsname
\csname iftrue\endcsname
\advance\pgfmathfloat@b@E by -2
\divide\pgfmathfloat@b@E by 3
\multiply\pgfmathfloat@b@E by 3
\fi
\multiply\pgfmathfloat@b@E by-1
\xdef\pgfplots@glob@TMPa{\the\pgfmathfloat@b@E}%
\else
% no scaling necessary:
\xdef\pgfplots@glob@TMPa{0}%
\fi
\fi
\or
% CASE 2 : scaled #1 ticks=base 10:
%--------------------------------
\c@pgf@counta=\csname pgfplots@scaled@ticks@#1@arg\endcsname\relax
%\multiply\c@pgf@counta by-1
\xdef\pgfplots@glob@TMPa{\the\c@pgf@counta}%
\or
% CASE 3 : scaled #1 ticks=real:
%--------------------------------
\pgfmathfloatparsenumber{\csname pgfplots@scaled@ticks@#1@arg\endcsname}%
\global\let\pgfplots@glob@TMPa=\pgfmathresult
\or
% CASE 4 : scaled #1 ticks=manual:
\expandafter\global\expandafter\let\expandafter\pgfplots@glob@TMPa\csname pgfplots@scaled@ticks@#1@arg\endcsname
\fi
\endgroup
\fi
\expandafter\let\csname pgfplots@tick@scale@#1\endcsname=\pgfplots@glob@TMPa%
}
\makeatother
完整代码如下:
\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\makeatletter
\newif\ifpgfplots@scaled@x@ticks@engineering
\pgfplots@scaled@x@ticks@engineeringfalse
\newif\ifpgfplots@scaled@y@ticks@engineering
\pgfplots@scaled@y@ticks@engineeringfalse
\newif\ifpgfplots@scaled@z@ticks@engineering
\pgfplots@scaled@z@ticks@engineeringfalse
\pgfplotsset{
scaled x ticks/engineering/.code=
\pgfplots@scaled@x@ticks@engineeringtrue,
scaled y ticks/engineering/.code=
\pgfplots@scaled@y@ticks@engineeringtrue,
scaled z ticks/engineering/.code=
\pgfplots@scaled@y@ticks@engineeringtrue,
% scaled ticks=engineering % Uncomment this line if you want "engineering" to be on by default
}
\def\pgfplots@init@scaled@tick@for#1{%
\global\def\pgfplots@glob@TMPa{0}%
\expandafter\pgfplotslistcheckempty\csname pgfplots@prepared@tick@positions@major@#1\endcsname
\ifpgfplotslistempty
% we have no tick labels. Omit the tick scale label as well!
\else
\begingroup
\ifcase\csname pgfplots@scaled@ticks@#1@choice\endcsname\relax
% CASE 0 : scaled #1 ticks=false: do nothing here.
\or
% CASE 1 : scaled #1 ticks=true:
%--------------------------------
% the \pgfplots@xmin@unscaled@as@float is set just before the data
% scale transformation is initialised.
%
% The variables are empty if there is no datascale transformation.
\expandafter\let\expandafter\pgfplots@cur@min@unscaled\csname pgfplots@#1min@unscaled@as@float\endcsname
\expandafter\let\expandafter\pgfplots@cur@max@unscaled\csname pgfplots@#1max@unscaled@as@float\endcsname
%
\ifx\pgfplots@cur@min@unscaled\pgfutil@empty
\edef\pgfplots@loc@TMPa{\csname pgfplots@#1min\endcsname}%
\expandafter\pgfmathfloatparsenumber\expandafter{\pgfplots@loc@TMPa}%
\let\pgfplots@cur@min@unscaled=\pgfmathresult
\edef\pgfplots@loc@TMPa{\csname pgfplots@#1max\endcsname}%
\expandafter\pgfmathfloatparsenumber\expandafter{\pgfplots@loc@TMPa}%
\let\pgfplots@cur@max@unscaled=\pgfmathresult
\fi
%
\expandafter\pgfmathfloat@decompose@E\pgfplots@cur@min@unscaled\relax\pgfmathfloat@a@E
\expandafter\pgfmathfloat@decompose@E\pgfplots@cur@max@unscaled\relax\pgfmathfloat@b@E
\pgfplots@init@scaled@tick@normalize@exponents
\ifnum\pgfmathfloat@b@E<\pgfmathfloat@a@E
\pgfmathfloat@b@E=\pgfmathfloat@a@E
\fi
\xdef\pgfplots@glob@TMPa{\pgfplots@scale@ticks@above@exponent}%
\ifnum\pgfplots@glob@TMPa<\pgfmathfloat@b@E
% ok, scale it:
\expandafter\ifx % Check whether we're using engineering notation (restricting exponents to multiples of three)
\csname ifpgfplots@scaled@#1@ticks@engineering\expandafter\endcsname
\csname iftrue\endcsname
\divide\pgfmathfloat@b@E by 3
\multiply\pgfmathfloat@b@E by 3
\fi
\multiply\pgfmathfloat@b@E by-1
\xdef\pgfplots@glob@TMPa{\the\pgfmathfloat@b@E}%
\else
\xdef\pgfplots@glob@TMPa{\pgfplots@scale@ticks@below@exponent}%
\ifnum\pgfplots@glob@TMPa>\pgfmathfloat@b@E
% ok, scale it:
\expandafter\ifx % Check whether we're using engineering notation (restricting exponents to multiples of three)
\csname ifpgfplots@scaled@#1@ticks@engineering\expandafter\endcsname
\csname iftrue\endcsname
\advance\pgfmathfloat@b@E by -2
\divide\pgfmathfloat@b@E by 3
\multiply\pgfmathfloat@b@E by 3
\fi
\multiply\pgfmathfloat@b@E by-1
\xdef\pgfplots@glob@TMPa{\the\pgfmathfloat@b@E}%
\else
% no scaling necessary:
\xdef\pgfplots@glob@TMPa{0}%
\fi
\fi
\or
% CASE 2 : scaled #1 ticks=base 10:
%--------------------------------
\c@pgf@counta=\csname pgfplots@scaled@ticks@#1@arg\endcsname\relax
%\multiply\c@pgf@counta by-1
\xdef\pgfplots@glob@TMPa{\the\c@pgf@counta}%
\or
% CASE 3 : scaled #1 ticks=real:
%--------------------------------
\pgfmathfloatparsenumber{\csname pgfplots@scaled@ticks@#1@arg\endcsname}%
\global\let\pgfplots@glob@TMPa=\pgfmathresult
\or
% CASE 4 : scaled #1 ticks=manual:
\expandafter\global\expandafter\let\expandafter\pgfplots@glob@TMPa\csname pgfplots@scaled@ticks@#1@arg\endcsname
\fi
\endgroup
\fi
\expandafter\let\csname pgfplots@tick@scale@#1\endcsname=\pgfplots@glob@TMPa%
}
\makeatother
\begin{document}
\pgfmathsetseed{1}
\begin{tikzpicture}
\begin{axis}[height=4cm, width=8cm]
\addplot {1/100000*x};
\end{axis}
\end{tikzpicture}
\end{document}
答案2
编辑2
使用此解决方案,您只需使用myaxis
环境,只需在序言中输入几行即可完成工作。
\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepgflibrary{fixedpointarithmetic}
\usepackage{fp}
\makeatletter
\newcommand{\pgfplotsdrawaxis}{\pgfplots@draw@axis}
\makeatother
\pgfplotsset{after end axis/.append code={
\pgfmathsetmacro{\maxexponent}{round(log10(\pgfkeysvalueof{/pgfplots/ymax}))}
\pgfmathparse{-3*floor(\maxexponent/3)}
\pgfmathsetmacro{\exponent}{\pgfmathresult}
\def\axisdefaultticklabel{$\pgfmathprintnumber{\tick}$}
\pgfplotsset{scaled y ticks=base 10:\exponent}
\pgfplotsdrawaxis}}
\newenvironment{myaxis}[1][]
{\begin{axis}[scaled y ticks=false,#1]%
\def\axisdefaultticklabel{}}
{\end{axis}}
\begin{document}
\begin{tikzpicture}[fixed point arithmetic]
\begin{myaxis}
\addplot {1000*x^2};
\end{myaxis}
\end{tikzpicture}
\end{document}
编辑1
ymax
这可以完成工作,但需要在axis
环境中指定
\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepgflibrary{fixedpointarithmetic}
\usepackage{fp}
\begin{document}
\begin{tikzpicture}[fixed point arithmetic]
\begin{axis}[ymax=2e7]
\pgfmathsetmacro{\maxexponent}{round(log10(\pgfkeysvalueof{/pgfplots/ymax}))}
\pgfmathparse{-3*floor(\maxexponent/3)}%
\pgfmathsetmacro{\exponent}{\pgfmathresult}
\pgfplotsset{scaled y ticks=base 10:\exponent}
\addplot {1000000*x^2};
\end{axis}
\end{tikzpicture}
\end{document}
原来的
您可以使用
scaled ticks=base 10:-9
或者单独改变x
和y
因素scaled x ticks
或者但是如果您在图中使用它则scaled y ticks
必须删除该线。y tick label style={/pgf/number format/.cd,sci,precision=5}