Quero criar um gráfico que exiba funções lineares cujo máximo construa uma função linear por partes (PWLF) rotulada max
no 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:
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 sagetex
pacote 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: Uma visão de perto:
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.