Как установить легенды вне графики в OpenTURNS?

#matplotlib #openturns

#matplotlib #openturns

Вопрос:

Я хочу создать контурный график логарифмической вероятности гауссовой выборки с помощью OpenTURNS. Каждый контур соответствует значению функции, которое обозначается легендой графика. Проблема в том, что легенда несколько скрывает контуры: как настроить сюжет так, чтобы легенда не скрывала содержимое?

Вот пример. Я создаю Normal распределение, соответствующее росту человека в возрасте от 20 до 79 лет (см. «Статистическую справку Бюро переписи населения США». Таблица 209. 2012). Затем я генерирую образец из этого дистрибутива. Я определяю функцию логарифмического правдоподобия, которая принимает вектор (mu, sigma) на входе и возвращает одномерный вектор, содержащий логарифмическое правдоподобие на выходе. Я могу использовать draw метод этой функции для создания контурного графика.

 import openturns as ot
import openturns.viewer as otv

mu = 1.763
sigma = 0.0680
N = ot.Normal(mu, sigma)
sample_size = 100
sample = N.getSample(sample_size)

def loglikelihood_gauss(X):
    """Compute the log-likelihood of a Gaussian sample."""
    mu, sigma = X
    N = ot.Normal(mu, sigma)
    log_pdf = N.computeLogPDF(sample)
    sample_size = sample.getSize()
    log_likelihood = log_pdf.computeMean() * sample_size
    return log_likelihood

# Contour plot
logLikelihoodFunction = ot.PythonFunction(2, 1, loglikelihood_gauss)
ot.ResourceMap_SetAsUnsignedInteger("Contour-DefaultLevelsNumber", 5)
graph = logLikelihoodFunction.draw([1.65, 0.04], [1.85, 0.15], [50]*2)
graph.setXTitle(r"$mu$")
graph.setYTitle(r"$sigma$")
graph.setTitle("Log-Likelihood.")
view = otv.View(graph)
 

Это приводит к:

Логарифмическая вероятность выборки по Гауссу

Как настроить график так, чтобы легенда не скрывала контуры?

Ответ №1:

Первый трюк заключается в использовании bbox_to_anchor опции функции legend matplotlib. Это возможно, потому что вся графика OpenTURNS взята из Matplotlib на уровне Python. Второй трюк заключается в получении рисунка из View объекта на основе getFigure метода. Без дополнительного кода это создает вторую легенду, которая находится в правильном месте, но дублирует легенду. Третий трюк заключается в том, чтобы скрыть старую легенду, установив содержимое в пустые строки.

 logLikelihoodFunction = ot.PythonFunction(2, 1, loglikelihood_gauss)
ot.ResourceMap_SetAsUnsignedInteger("Contour-DefaultLevelsNumber", 5)
graph = logLikelihoodFunction.draw([1.65, 0.04], [1.85, 0.15], [50]*2)
graph.setXTitle(r"$mu$")
graph.setYTitle(r"$sigma$")
graph.setTitle("Log-Likelihood.")
legends = graph.getLegends()
graph.setLegendPosition("")
view = otv.View(graph)
figure = view.getFigure()
figure.legend(legends, bbox_to_anchor=(1.1, 0.9))
 

График контура логарифмического правдоподобия с легендой вне поля

При сохранении рисунка легенда может быть обрезана. Возможно, потребуется использовать bbox_inches опцию:

 figure.savefig("filename.png", bbox_inches="tight")
 

Ответ №2:

Очень хорошая функциональность! Меня часто смущают графики, легенда которых слишком велика. Вы можете улучшить свой скрипт, используя:

 graph.setLegendPosition('')
 

вместо:

 graph.setLegends([""] * 5)
 

Это позволяет избежать подсчета количества чертежей, которые у вас есть на графике.

Ответ №3:

К сожалению, это плохо работает, если вы смешиваете разные виды чертежей:

 import openturns as ot
import openturns.viewer as otv

f = ot.SymbolicFunction(["x", "y"], ["x^4 y^4-8*(x^2 y^2)"])
graph = f.draw([-4.0]*2, [4.0]*2)
graph.setLegendPosition("bottomleft")
graph.add(ot.Curve([[-4.0]*2, [4.0]*2], "red", "dashed", 1.0, "line"))
graph.add(ot.Cloud([[0.0]*2], "black", "fcircle", "point"))
legends = graph.getLegends()
view = otv.View(graph)
figure = view.getFigure()
figure.legend(legends, bbox_to_anchor=(1.0, 1.0))
 

На результирующем рисунке вы видите, что новая легенда заменила метки точки и линии метками первых двух значений isovalues. Правильный способ получить метки легенды:

 _, legends = view._ax[0].get_legend_handles_labels()