Skip to content

Eixo secundário no Matplotlib: twinx vs secondary_yaxis

Updated on

Um gráfico pode precisar de duas escalas (dinheiro vs unidades, °C vs °F). Se o segundo eixo for adicionado de forma incorreta, os leitores interpretam errado: ticks desalinhados, legendas inconsistentes e rótulos cortados. A solução é simples: escolher a ferramenta certa e aplicar uma conversão clara para manter as duas escalas fiéis.

Guia rápido de decisão

AbordagemQuando usarPrósCuidados
twinx / twinyDuas séries independentes que só compartilham posições em x (ou y)Rápido, pouco códigoFormatação manual de ticks; sem sincronização automática
secondary_yaxis / secondary_xaxisSéries são convertíveis (ex.: °C ↔ °F)Garante alinhamento de ticks com funções direta/inversaPrecisa de conversão precisa; apenas transformações monótonas
Dois subplots com eixos compartilhadosQuer comparar sem sobreporSeparação claraMais espaço, legendas por subplot

Receita: twinx para dois eixos y

import matplotlib.pyplot as plt
import numpy as np
 
x = np.arange(1, 13)
sales = np.array([12, 18, 25, 30, 28, 35, 40, 38, 32, 28, 22, 18])
customers = np.array([120, 155, 180, 210, 205, 230, 245, 240, 225, 200, 175, 150])
 
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(x, sales, color="tab:blue", label="Vendas (k$)")
ax.set_xlabel("Mês")
ax.set_ylabel("Vendas (k$)", color="tab:blue")
ax.tick_params(axis="y", labelcolor="tab:blue")
 
ax2 = ax.twinx()
ax2.plot(x, customers, color="tab:orange", label="Clientes")
ax2.set_ylabel("Clientes", color="tab:orange")
ax2.tick_params(axis="y", labelcolor="tab:orange")
 
linhas = ax.get_lines() + ax2.get_lines()
rotulos = [line.get_label() for line in linhas]
ax.legend(linhas, rotulos, loc="upper left")
plt.tight_layout()
plt.show()

Dicas:

  • Use cores diferentes por eixo para manter a legenda clara.
  • Una as linhas dos dois eixos antes de chamar legend.
  • tight_layout() ou constrained_layout=True evitam rótulos cortados.

Receita: secondary_yaxis com conversão segura

import matplotlib.pyplot as plt
import numpy as np
 
temps_c = np.linspace(-20, 40, 200)
fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(temps_c, np.sin(temps_c / 10), color="tab:blue", label="Sinal vs °C")
ax.set_xlabel("Temperatura (°C)")
ax.set_ylabel("Sinal")
 
def c_to_f(c):
    return c * 9/5 + 32
 
def f_to_c(f):
    return (f - 32) * 5/9
 
ax_f = ax.secondary_xaxis("top", functions=(c_to_f, f_to_c))
ax_f.set_xlabel("Temperatura (°F)")
 
ax.legend(loc="lower right")
plt.tight_layout()
plt.show()

Dicas:

  • Sempre forneça funções direta e inversa para manter os ticks alinhados.
  • Use apenas conversões monótonas e inversíveis.
  • Formate os ticks (ax_f.xaxis.set_major_formatter("{x:.0f}°F")) para clareza.

Mantenha as escalas honestas

  • Evite eixo duplo se as séries forem pouco relacionadas; dois subplots costumam ser mais claros.
  • Se uma série domina, normalize antes de comparar.
  • Deixe a grade apenas no eixo primário para reduzir ruído visual.

Checklist de solução de problemas

  • Legendas duplicadas? Una as linhas dos dois eixos e chame legend.
  • Rótulos cortados? Use constrained_layout=True ou plt.tight_layout().
  • Cores de ticks diferentes? Aplique tick_params(labelcolor=...) em ambos os eixos.