Автоматически делать линии pgfplot пунктирными под максимумом функций

Автоматически делать линии pgfplot пунктирными под максимумом функций

Я хочу создать график, отображающий линейные функции, максимум которых создает кусочно-линейную функцию (PWLF), помеченную maxв минимальном рабочем примере ниже. В настоящее время, чтобы выделить максимум, я добавляю график, который вызывает max() и в качестве аргументов берет линейные функции и накладывает другой график в толстом черном цвете, чтобы показать PWLF. Вносящие вклад функции нарисованы вручную пунктиром, чтобы подчеркнуть тот факт, что они «не вносят вклад» в определенных областях.

На самом деле, мне бы хотелось, чтобы все линии были пунктирными, если они не являются частью максимума, а в противном случае — сплошными, чтобы сохранить в PWLF цветовую информацию о том, какая линейная функция составляет этот сегмент графика.

Есть ли способ сделать это описательно, в идеале без необходимости вручную рисовать отрезки линий? Мне действительно не хочется вычислять пересечения для каждого примера, а затем каждый раз создавать соответствующие графики.

В настоящее время MWE генерирует следующий вывод:

введите описание изображения здесь

МВЭ:

\documentclass{article}
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}
\usetikzlibrary{positioning}
\usepackage{amsmath}

\pgfplotsset{
    legend entry/.initial=,
    every axis plot post/.code={%
            \pgfkeysgetvalue{/pgfplots/legend entry}\tempValue
            \ifx\tempValue\empty
                    \pgfkeysalso{/pgfplots/forget plot}%
            \else
                    \expandafter\addlegendentry\expandafter{\tempValue}%
            \fi
    },
}

\begin{document}

\begin{figure}
    \centering

    \begin{tikzpicture}

        \begin{axis}[width=\textwidth, enlargelimits=false, legend pos=outer north east, ytick=\empty, xtick={0, 1}, %
            xticklabels={1 - $S_0$, $S_0$}]
            \addplot[blue, dashed, thick, no marks, domain=0:1, legend entry=$a_1$]%
                ({x},{0.8 - 0.5*x});%

            \addplot[olive, thick, dashed, no marks, domain=0:1, legend entry=$a_2$]%
            ({x}, {0.6 - 0.2*x});%

            \addplot [red, thick, dashed, no marks, domain=0:1, legend entry=$a_3$]%
            ({x}, {0.3+0.4*x});%

            \addplot [orange, dashed, thick, no marks, domain=0:1, legend entry=$a_4$]%
            ({x}, {0.5+0.1*x});%

            \addplot [black, ultra thick, no marks, domain=0:1, legend entry=$\text{max}$] {max(0.8-0.5*x,0.3+0.4*x, 0.5+0.1*x)};

        \end{axis}
    \end{tikzpicture}
\end{figure}
\end{document}

решение1

Пакет sagetexможет справиться с этим. Его документация находится на CTANздесь. Это позволяет вам передать работу системе компьютерной алгебры SAGE, у которой есть свой веб-сайтздесь. Это означает, что вам нужно будет загрузить SAGE на свой компьютер и правильно установить его или открыть бесплатныйКокалкучетная запись. Если у вас есть учетная запись Cocalc, просто вставьте create a LaTeX document, скопируйте/вставьте код ниже в свой документ, сохраните его, а затем нажмите build, чтобы увидеть результат.РЕДАКТИРОВАТЬ:Я изменил код, чтобы исправить ошибку в легенде и сделать его более похожим на график, который опубликовал OP. Добавление функции max в легенду окрашивает ее в сплошной синий цвет, поэтому я ее исключил.

\documentclass[border=4pt]{standalone}
\usepackage{sagetex}
\usepackage[usenames,dvipsnames]{xcolor}
\usepackage{pgfplots}
\pgfplotsset{compat=1.15}
\begin{document}
\begin{sagesilent}
f1 = 0.8-0.5*x
f2 = 0.6-0.2*x
f3 = 0.3+0.4*x
f4 = 0.5+0.1*x
t = var('t')
LowerY = 0.0
UpperY = 1.0
LowerX = 0.0
UpperX = 1.0
step = .001

f1x = [t for t in srange(LowerX,UpperX,step) if     f1(t)==max(f1(t),f2(t),f3(t),f4(t))]
f1y = [f1(t) for t in f1x]
f2x = [t for t in srange(LowerX,UpperX,step) if f2(t)==max(f1(t),f2(t),f3(t),f4(t))]
f2y = [f2(t) for t in f2x]
f3x = [t for t in srange(LowerX,UpperX,step) if f3(t)==max(f1(t),f2(t),f3(t),f4(t))]
f3y = [f3(t) for t in f3x]
f4x = [t for t in srange(LowerX,UpperX,step) if f4(t)==max(f1(t),f2(t),f3(t),f4(t))]
f4y = [f4(t) for t in f4x]

output = r""
output += r"\begin{tikzpicture}[scale=.7]"
output += r"\begin{axis}[width=\textwidth, enlargelimits=false, legend pos=outer north east, ytick=\empty, xtick={0, 1}, xticklabels={1-$S_0$,$S_0$}]"

output += r"\addplot[blue, dashed, thick, no marks, domain=0:1]"
output += r"({x},{0.8 - 0.5*x});"
output += r"\addlegendentry{$f1$}"
output += r"\addplot[olive, thick, dashed, no marks, domain=0:1]"
output += r"({x}, {0.6 - 0.2*x});"
output += r"\addlegendentry{$f2$}"
output += r"\addplot [red, thick, dashed, no marks, domain=0:1]"
output += r"({x}, {0.3+0.4*x});"
output += r"\addlegendentry{$f3$}"
output += r"\addplot [orange, dashed, thick, no marks, domain=0:1]"
output += r"({x}, {0.5+0.1*x});"
output += r"\addlegendentry{$a4$}"

if len(f1x)>1:
    output += r"\addplot[blue,thick] coordinates {"
    for i in range(0,len(f1x)-1):
        output += r"(%f,%f) "%(f1x[i],f1y[i])
    output += r"};"

if len(f2x)>1:
    output += r"\addplot[olive,thick] coordinates {"
    for i in range(0,len(f2x)-1):
        output += r"(%f,%f) "%(f2x[i],f2y[i])
    output += r"};"

if len(f3x)>1:
    output += r"\addplot[red,thick] coordinates {"
    for i in range(0,len(f3x)-1):
        output += r"(%f,%f) "%(f3x[i],f3y[i])
    output += r"};"

if len(f4x)>1:
    output += r"\addplot[orange,thick] coordinates {"
    for i in range(0,len(f4x)-1):
        output += r"(%f,%f) "%(f4x[i],f4y[i])
    output += r"};"

output += r"\end{axis}"
output += r"\end{tikzpicture}"
\end{sagesilent}
\sagestr{output}
\end{document}

Вывод в Colcalc показан ниже: введите описание изображения здесь Вид крупным планом: введите описание изображения здесь

Python — это язык, используемый в SAGE. После определения ваших 4 линий как f1 через f4, код f1x = [t for t in srange(LowerX,UpperX,step) if f1(t)==max(f1(t),f2(t),f3(t),f4(t))] f1y = [f1(t) for t in f1x]создает список координат x и y для линии f1. Точка добавляется к f1x, если f1 является максимальной точкой на всех 4 линиях, в этом случае значение y добавляется к f1y. Может быть так (например, 3 линии пересекаются в одной точке), что существует только 1 значение x, для которого линия достигает максимума, в этом случае мы не рисуем это; любая линия, действительно являющаяся частью функции max, будет иметь по крайней мере две точки, в которых она достигает максимума. Таким образом, предполагая, что f1 имеет более одной точки, проверенная if len(f1x)>1:линия будет нанесена на график как часть функции max.

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