![pgfplots: исправление проблем округления](https://rvso.com/image/328833/pgfplots%3A%20%D0%B8%D1%81%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5%20%D0%BF%D1%80%D0%BE%D0%B1%D0%BB%D0%B5%D0%BC%20%D0%BE%D0%BA%D1%80%D1%83%D0%B3%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F.png)
У меня возникла проблема с исчезновением маркера, так как сумма данных превысила 100, хотя xmax был установлен на 100. Смотритеpgfplots: узел около координат отсутствует из-за проблем округления.
Как написано в ответе на цитируемый вопрос, я пытался избежать проблемы, нормализуя значение до 100. Но это привело к (гораздо меньшим) ошибкам округления в ранее правильных строках, и теперь маркер там исчез. Смотрите следующий пример. До нормализации затронут столбец F, следующий за столбцом B.
Как я могу внадежныйкак обойти эту проблему округления? Или хотя бы получить четкое сообщение об ошибке. У меня довольно много таких графиков, и я не хочу постоянно проверять их на предмет отсутствующих маркеров.
\documentclass{scrreprt}
\usepackage{pgfplots}
\pgfplotsset{compat=1.13}
\usepackage{pgfplotstable}
\pgfplotsset{
my stackbar plot/.style={
xbar stacked,
xmin=0,xmax=100,
symbolic y coords={A,B,C,D,E,F,G},
ytick=data,
nodes near coords={xxx},}}
\begin{document}
\pgfplotstableread[col sep=space]{
text -- - + ++
A 0.0 1.7 13.8 84.5
B 0.0 0.6 20.1 79.3
C 0.0 1.9 13.2 84.9
D 0.0 1.6 27.9 70.5
E 1.3 3.9 19.5 75.3
F 0.0 1.4 15.0 83.7
G 0.3 1.7 24.8 73.2
}\data
\pgfplotstablecreatecol[create col/expr={\thisrow{--}+\thisrow{-}+\thisrow{+}+\thisrow{++}}]{sum}\data %
\pgfplotstablecreatecol[create col/copy=--]{--o}\data
\pgfplotstablecreatecol[create col/copy=-]{-o}\data
\pgfplotstablecreatecol[create col/copy=+]{+o}\data
\pgfplotstablecreatecol[create col/copy=++]{++o}\data
\pgfplotstablecreatecol[create col/expr={100/\thisrow{sum}*\thisrow{--o}}]{--}\data
\pgfplotstablecreatecol[create col/expr={100/\thisrow{sum}*\thisrow{-o}}]{-}\data
\pgfplotstablecreatecol[create col/expr={100/\thisrow{sum}*\thisrow{+o}}]{+}\data
\pgfplotstablecreatecol[create col/expr={100/\thisrow{sum}*\thisrow{++o}}]{++}\data
\pgfplotstablecreatecol[create col/expr={\thisrow{--}+\thisrow{-}+\thisrow{+}+\thisrow{++}}]{sumnew}\data
\pgfplotstabletypeset[columns={text,sum} ,precision=10,columns/text/.style={string type}]\data \quad
\pgfplotstabletypeset[columns={text,sumnew},precision=10,columns/text/.style={string type}]\data
%\pgfplotstablesave{\data}{pgfplotstempout.dat}
\begin{tikzpicture}
\begin{axis}[my stackbar plot]
\addplot table [x expr = \thisrow{--o},y=text] {\data};
\addplot table [x expr = \thisrow{-o}, y=text] {\data};
\addplot table [x expr = \thisrow{+o}, y=text] {\data};
\addplot table [x expr = \thisrow{++o}, y=text] {\data};
\end{axis}
\end{tikzpicture}
\quad
\begin{tikzpicture}
\begin{axis}[my stackbar plot]
\addplot table [x expr = \thisrow{--},y=text] {\data};
\addplot table [x expr = \thisrow{-}, y=text] {\data};
\addplot table [x expr = \thisrow{+}, y=text] {\data};
\addplot table [x expr = \thisrow{++}, y=text] {\data};
\end{axis}
\end{tikzpicture}
\end{document}
решение1
Вот способ использования\usepackage{xintexpr}
:
\xinttheiexpr [d] ...\relax
выдает число с фиксированной точкой сd
цифрами после десятичной точки, гдеd
есть числоd =1, 2, ...
. Этораундовточно вычисленный результат.\xinttheexpr trunc(..., d)\relax
делает то же самое, но вместо округления, онусекает. (Извините за сомнительный синтаксис сi
округлением и отсутствиемi
усечения, происходит то, что некоторые из них\xinttheiexpr [d,trunc] ... \relax
должны быть реализованы, я в тупике с выбором синтаксиса, потому что я не хочу, чтобы он был многословным, подумал[d↓]
...).
Мы можем использовать это, в частности, в местах, где разрешены вещи, работающие за счет чистого расширения, например, \xinttheexpr, \xinttheiexpr
f-расширяемые. (см. xint
документацию, чтобы узнать, что именно это означает).
Вот несколько комментариев, которые теперь не может понять никто, даже сам автор, даже после некоторого редактирования с целью сделать их менее многословными.
В суммировании для sumnew
мы добавляем 4 числа, которые были округлены. Каждое округление (с фиксированной точкой) вносило абсолютную ошибку не более 5 10^-7
, следовательно, у нас есть ошибка в точной сумме, которая составляет не более 2 10^-6 = 0.02 10^-4
. Если мы округлим это сейчас до 4 цифр, у нас есть возможная ошибка 0.52 10^-4
. Это означает, что это может быть некорректное округление точной суммы, но off by 1
для единицы на последнем месте. Это S_exact
мы обсуждаем здесь, 100 (exact sum of the original data)/S_pgfplots
где S_pgfplots
вычисленная pgfplots
сумма, следовательно, она близка к 100
.
Если бы перемасштабированные слагаемые были сначала усечены до 6 цифр, их вычисленная сумма могла бы быть меньше максимум на 4 10^-6=0.04 10^-4
по сравнению с реальной. Если мы снова усечем ее до 4 цифр, мы окажемся максимум off by 1
в последней цифре по сравнению с усечением точной суммы, но с преимуществом знания того, что мы находимся ниже точного результата. Если точный результат равен точно 100
, то мы почти гарантированно получаем, что эта процедура всегда будет давать результат 99.9999
(она могла бы давать результат, 100
только если бы все соотношения были точными в 6 digits
--- ну, на самом деле это так, если , sum
на который мы делим, само равно точно 100
).
В любом случае, вот код:
\documentclass{scrreprt}
\usepackage{xintexpr}
\usepackage{pgfplots}
\pgfplotsset{compat=1.13}
\usepackage{pgfplotstable}
\pgfplotsset{
my stackbar plot/.style={
xbar stacked,
xmin=0,xmax=100,
symbolic y coords={A,B,C,D,E,F,G},
ytick=data,
nodes near coords={xxx},}}
\begin{document}
\pgfplotstableread[col sep=space]{
text -- - + ++
A 0.0 1.7 13.8 84.5
B 0.0 0.6 20.1 79.3
C 0.0 1.9 13.2 84.9
D 0.0 1.6 27.9 70.5
E 1.3 3.9 19.5 75.3
F 0.0 1.4 15.0 83.7
G 0.3 1.7 24.8 73.2
}\data
\pgfplotstablecreatecol[create col/expr={\thisrow{--}+\thisrow{-}+\thisrow{+}+\thisrow{++}}]{sum}\data %
\pgfplotstablecreatecol[create col/copy=--]{--o}\data
\pgfplotstablecreatecol[create col/copy=-]{-o}\data
\pgfplotstablecreatecol[create col/copy=+]{+o}\data
\pgfplotstablecreatecol[create col/copy=++]{++o}\data
\pgfplotstablecreatecol[create col/expr={\xinttheiexpr[6]
100/\thisrow{sum}*\thisrow{--o}\relax}]{--}\data
\pgfplotstablecreatecol[create col/expr={\xinttheiexpr[6]
100/\thisrow{sum}*\thisrow{-o}\relax}]{-}\data
\pgfplotstablecreatecol[create col/expr={\xinttheiexpr[6]
100/\thisrow{sum}*\thisrow{+o}\relax }]{+}\data
\pgfplotstablecreatecol[create col/expr={\xinttheiexpr[6]
100/\thisrow{sum}*\thisrow{++o}\relax }]{++}\data
\pgfplotstablecreatecol[create col/expr={\xinttheiexpr [6]
\thisrow{--}+\thisrow{-}+\thisrow{+}+\thisrow{++}\relax}]{sumnew}\data
% better? or even without [4] to get 100 as rounded integer ?
% \pgfplotstablecreatecol[create col/expr={\xinttheiexpr[4]
% \thisrow{--}+\thisrow{-}+\thisrow{+}+\thisrow{++}\relax}]{sumnew}\data
\pgfplotstabletypeset[columns={text,sum} ,precision=10,columns/text/.style={string type}]\data \quad
\pgfplotstabletypeset[columns={text,sumnew},precision=10,columns/text/.style={string type}]\data
%\pgfplotstablesave{\data}{pgfplotstempout.dat}
\begin{tikzpicture}
\begin{axis}[my stackbar plot]
\addplot table [x expr = \thisrow{--o},y=text] {\data};
\addplot table [x expr = \thisrow{-o}, y=text] {\data};
\addplot table [x expr = \thisrow{+o}, y=text] {\data};
\addplot table [x expr = \thisrow{++o}, y=text] {\data};
\end{axis}
\end{tikzpicture}
\quad
\begin{tikzpicture}
\begin{axis}[my stackbar plot]
\addplot table [x expr = \thisrow{--},y=text] {\data};
\addplot table [x expr = \thisrow{-}, y=text] {\data};
\addplot table [x expr = \thisrow{+}, y=text] {\data};
\addplot table [x expr = \thisrow{++}, y=text] {\data};
\end{axis}
\end{tikzpicture}
\end{document}