Faça com que as linhas do pgfplot sejam tracejadas automaticamente abaixo do máximo de funções

Faça com que as linhas do pgfplot sejam tracejadas automaticamente abaixo do máximo de funções

Quero criar um gráfico que exiba funções lineares cujo máximo construa uma função linear por partes (PWLF) rotulada maxno exemplo de trabalho mínimo abaixo. Atualmente, para destacar o máximo, estou adicionando um gráfico que chama max() e como argumentos, pega as funções lineares e sobrepõe outro gráfico em preto grosso para mostrar o PWLF. As funções de contribuição são desenhadas tracejadas manualmente para destacar o fato de que “não estão contribuindo” em determinadas regiões.

Na verdade, o que eu gostaria de fazer é que todas as linhas fossem tracejadas se não fizerem parte do máximo e, caso contrário, fossem sólidas, para reter as informações de cor no PWLF sobre qual função linear compõe aquele segmento do gráfico.

Existe alguma maneira de fazer isso de forma descritiva, de preferência sem precisar desenhar os segmentos de linha manualmente? Eu realmente não quero ter que calcular as interseções para cada exemplo e depois criar gráficos apropriados sempre.

O MWE atualmente gera esta saída:

insira a descrição da imagem aqui

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}

Responder1

O sagetexpacote pode lidar com isso. Sua documentação está localizada no CTANaqui. Isso permite que você terceirize o trabalho para um sistema de álgebra computacional, SAGE, que tem seu siteaqui. Isso significa que você precisará baixar o SAGE para o seu computador e instalá-lo corretamente ou abrir um software gratuito.Cocalcconta. Se você tiver uma conta Cocalc, basta colar, criar um documento LaTeX, copiar/colar o código abaixo em seu documento, salvá-lo e pressionar build para ver o resultado.EDITAR:Modifiquei o código para corrigir um erro na legenda e para torná-lo mais parecido com o gráfico que o OP postou. Colocar a função max na legenda colore-a em azul sólido, então a deixei de fora.

\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}

A saída no Colcalc é mostrada abaixo: insira a descrição da imagem aqui Uma visão de perto: insira a descrição da imagem aqui

Python é a linguagem usada no SAGE. Depois de definir suas 4 linhas como f1 a f4, o código 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]cria uma lista de coordenadas xey para a linha f1. Um ponto é adicionado a f1x se f1 for o ponto máximo em todas as 4 linhas; nesse caso, o valor de y é adicionado a f1y. Pode ser o caso (como 3 linhas que se cruzam no mesmo ponto) de haver apenas 1 valor x para o qual uma linha atinge o máximo, caso em que não traçamos isso; qualquer linha que realmente faça parte da função max terá pelo menos dois pontos nos quais atinge o máximo. Portanto, supondo que f1 tenha mais de um ponto, verificado pela if len(f1x)>1:linha será plotado como parte da função max.

informação relacionada