pgfplots: исправление проблем округления

pgfplots: исправление проблем округления

У меня возникла проблема с исчезновением маркера, так как сумма данных превысила 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, \xinttheiexprf-расширяемые. (см. 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} 

Цитата из блока

Связанный контент