我正在创建一个动态 LaTeX (LuaLaTeX) 脚本,该脚本会根据给定的 CSV 文件创建图表。xmin、xmax 等设置取决于该 CSV 文件。
该 CSV 文件包含硬盘的存储使用情况以及日期时间戳。
该图的范围从两年前到未来一年。黑色图显示 CSV 数据,粗红色线为线性回归线,在两个方向上扩展(使用“缩短”键)。线性回归是使用此代码创建的:
\addplot [line width=10pt, opacity=.3, red, shorten >= -10cm, shorten <= -10cm] table [
x index=5,
y={create col/linear regression={
x=JulianDayMod,
y="size",
}}
] {\loadedtable};
由于 CSV 具有日期格式,我需要预先使用此脚本对其进行转换:pgfplots 中 x 轴上有日期的线性回归
现在我需要 xmax 处的线性回归的 y 值。你知道如何获取它吗?
(同样重要的是要知道 xmax 也是一个日期,例如“2022-11-23”)
它应该显示在我放置占位符的图例中。我已经知道您可以使用和x
访问线性回归的系数。我可以使用访问 xmax\pgfplotstableregressiona
\pgfplotstableregressionb
\pgfkeysgetvalue{/pgfplots/xmax}{\xmax}
但我在网上找不到任何解决方案......
答案1
经过尝试,我找到了解决方案!
(我心中已经有了正确的想法,但第一次运行没有奏效......)
回顾:线性函数具有以下功能:a · x + b
并允许pgfplotstable
您访问a
线性\pgfplotstableregressiona
回归图。b
\pgfplotstableregressionb
所以我用这个代码来访问该值:(xmin 是先前定义的)
% get xmax (e.g. 2021-11-25)
\pgfkeysgetvalue{/pgfplots/xmax}{\xmax}
% convert xmax (date to julian, which is an integer number)
\newcount\xmaxjulian
\pgfcalendardatetojulian{\xmax}{\xmaxjulian}
\xmaxjulian=\numexpr\xmaxjulian-\xmin % remove offset
% store y value at xmax in \var
\pgfmathsetmacro{\var}{\pgfplotstableregressiona * (\the\xmaxjulian) + \pgfplotstableregressionb}
% print legend:
\addlegendentry{Forecast utilization in one year:
\luaexec{ tex.sprint ( string.format ( "\%.2f" , \var ) ) } TB}
笔记:
该代码\luaexec{ tex.sprint ( string.format ( "\%.2f" , \var ) ) }
将我的值四舍五入到小数点后两位。它仅适用于 LuaLaTeX,您需要将其添加\usepackage{luacode}
到代码中。
笔记2:
您可以使用以下命令打印线性回归函数:
Formula of linear regression:
$\pgfmathprintnumber{\pgfplotstableregressiona}\cdot x
\pgfmathprintnumber[print sign]{\pgfplotstableregressionb}$
注3:
我在这里添加了一个 MWE 示例:(您需要 LuaLaTeX 才能运行它)
\documentclass{article}
\usepackage[letterpaper,top=2cm,bottom=2cm,left=3cm,right=3cm,marginparwidth=1.75cm]{geometry}
\usepackage{datatool}
\usepackage{luacode}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{pgfcalendar}
\usepgfplotslibrary{dateplot}
\pgfplotsset{compat=newest}
\begin{filecontents*}{data.csv}
date, size
2021-04-01, 1.42
2021-05-01, 1.46
2021-06-01, 1.58
2021-07-01, 1.55
2021-08-01, 1.69
\end{filecontents*}
\begin{document}
\thispagestyle{empty}
\centering
\pgfplotstableread[col sep=comma]{data.csv}\loadedtable
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% add new column with Julian integer numbers
\newcount\julianday
\pgfplotstablecreatecol[
create col/assign/.code={
\pgfcalendardatetojulian{\thisrowno{0}}{\julianday}
\edef\entry{\the\julianday}
\pgfkeyslet{/pgfplots/table/create col/next content}\entry
},
]{JulianDay}{\loadedtable}
\pgfplotstablegetelem{0}{JulianDay}\of{\loadedtable}
\pgfmathtruncatemacro{\xmin}{\pgfplotsretval}
\pgfplotstablecreatecol[
expr={\thisrow{JulianDay}-\xmin},
]{JulianDayMod}{\loadedtable}
% source: https://tex.stackexchange.com/questions/367339/linear-regression-with-dates-on-x-axis-in-pgfplots
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% compute dates for xmin and xmax
% get last date in file
\DTLloaddb[%
noheader,%
keys={date,2}%
]{myDB}{data.csv}
\DTLforeach*{myDB}{\CurrentA=date}{%
\xdef\LastDate{\CurrentA}
}
\newcount\DateOfLastScan
\pgfcalendardatetojulian{\LastDate{}}{\DateOfLastScan}
\pgfcalendarjuliantodate{\DateOfLastScan}{\theyear}{\themonth}{\theday}
\year=\theyear
\month=\themonth
\day=\theday
% get date two years ago
\year=\numexpr\year-2
\edef\twoyearsago{\the\year-\ifnum\the\month<10 0\fi\the\month-\ifnum\the\day<10 0\fi\the\day}
\year=\numexpr\year+2
% get date one year in the future
\year=\numexpr\year+1
\edef\oneyearfuture{\the\year-\ifnum\the\month<10 0\fi\the\month-\ifnum\the\day<10 0\fi\the\day}
\year=\numexpr\year-1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% print plot
\begin{tikzpicture}
\begin{axis}
[
date coordinates in=x,
ylabel={Terabyte},
xticklabel style={rotate=90,anchor=near xticklabel},
xticklabel=\scriptsize\texttt{\day-\month-\year},
yticklabel={\luaexec{ tex.sprint ( string.format ( "\%.2f" , \tick ) ) }},
grid,
tick align=inside,
width=\textwidth,
xmin=\twoyearsago{},
xmax=\oneyearfuture{},
ymin=-0.05,
legend pos = south east,
legend image post style={only marks, mark=none},
legend cell align={left},
]
% linear regression
\addplot [line width=10pt, opacity=.3, red, shorten >= -10cm, shorten <= -10cm] table [
x index=0,
% now we can use the newly created column to do the linear regression
y={create col/linear regression={
x=JulianDayMod,
y=size,
}}
] {\loadedtable};
% contents from CSV file
\addplot[thick, no marks, solid] table[col sep=comma, x index=0, y index=1]{\loadedtable};
% get y value at xmax
\pgfkeysgetvalue{/pgfplots/xmax}{\xmax}
\newcount\xmaxjulian
\pgfcalendardatetojulian{\xmax}{\xmaxjulian}
\xmaxjulian=\numexpr\xmaxjulian-\xmin
\pgfmathsetmacro{\var}{\pgfplotstableregressiona * (\the\xmaxjulian) + \pgfplotstableregressionb}
% add legends
\addlegendentry{Forecast utilization in one year: \textbf{\luaexec{%
tex.sprint ( string.format ( "\%.2f" , \var ) ) } TB}}
\addlegendentry{Formula of linear regression:
$\pgfmathprintnumber{\pgfplotstableregressiona}\cdot x
\pgfmathprintnumber[print sign]{\pgfplotstableregressionb}$
}
% add invisible point at end of linear regression to keep the end of line inside of the plot
\addplot[forget plot,draw=none] coordinates {(\xmax,\var)};
\end{axis}
\end{tikzpicture}
\end{document}