Normalização compartilhada e limites de vista
Normalize, ScalarMappable e os limites geográficos são implementações próprias.
O script de desenvolvimento tools/inspect_norm_limits.py usa Matplotlib
3.11.2/Agg como referência e gera os casos comparados.
Matplotlib não é dependência da biblioteca.
Cores compartilhadas
import azimlib as azl
from azimlib.colors import Normalize
fig, axes = azl.subplots(1, 2)
norm = Normalize(0, 100)
left = axes[0].scatter(lon=[-46.63], lat=[-23.55], c=[60], norm=norm)
right = axes[1].scatter(lon=[-43.17], lat=[-22.90], c=[90], norm=norm)
bar = fig.colorbar(left, ax=axes, orientation='horizontal')
norm.vmax = 200 # Atualiza as duas camadas e a barra.
fig.canvas.draw_idle()
fig.savefig('cores.svg')
As propriedades vmin, vmax, clip e TwoSlopeNorm.vcenter notificam seus
mappables. Reatribuir o mesmo valor não emite uma alteração. O sinal
norm.callbacks.connect('changed', callback) chama o callback sem argumentos;
o sinal correspondente do mappable passa o próprio mappable. A ligação usa
métodos fracos e desconecta a norm antiga ao substituí-la.
Alterar limites da mesma norm preserva locators e formatters customizados da colorbar. Substituir a identidade da norm reinicializa seus ticks. Remover a colorbar desconecta sua inscrição. Uma norm pode servir camadas de várias figuras.
mappable.set_clim(low, high) valida e altera o par antes de notificar, inclusive
quando ambos os novos limites ultrapassam o intervalo antigo. autoscale()
recalcula os dois limites pelos dados válidos; autoscale_None() preenche somente
os ausentes. Uma operação sobre dados válidos comunica o intervalo final, sem
publicar os limites intermediários. A atribuição isolada de vmin/vmax pode deixar
um intervalo temporariamente invertido; o mapeamento rejeita esse intervalo.
Prefira set_clim para substituir um par.
Limites explícitos NaN/infinito são rejeitados; valores não finitos nos dados são
ignorados. LogNorm usa dados positivos para autoescala. norm.scaled() indica
que ambos os limites estão definidos. Uma ScalarMappable independente sem dados
permite uma barra linear inicial 0–1. Os intervalos provisórios próprios de
LogNorm e TwoSlopeNorm são respectivamente 1–10 e center±1; não são promessas de
igualdade de todos os casos vazios do Matplotlib. Uma Layer sem dados numéricos
exige limites explícitos para criar uma colorbar.
Normalizações contínuas retornam floats: o extremo cortado 1.0 corresponde à
última cor da paleta. BoundaryNorm mantém seus índices inteiros discretos.
Mutações internas de arrays, dicionários ou Colormap não notificam: use setters
ou mappable.changed(). Reclassificação de quantis e regeneração de legendas
temáticas discretas ainda precisam de trabalho adicional.
Dados e vista são controles distintos
fig, ax = azl.subplots()
line, = ax.plot([-52, -48], [-25, -21], 'o--')
line.set_data([-54, -43], [-28, -18])
ax.relim() # Recompõe os limites dos dados; conserva a vista atual.
ax.autoscale_view() # Ajusta somente os eixos com autoescala habilitada.
ax.set_xlim(-55, -42) # Fixa longitude; latitude pode continuar automática.
ax.autoscale(axis='x', tight=True) # Reabilita X e remove sua margem.
Edição de dados não move a vista por si só. set_extent fixa ambos os eixos;
set_xlim/set_ylim fixam apenas o respectivo eixo, com auto=False por padrão.
auto=True reabilita e auto=None preserva o estado. Há getters/setters
get_autoscalex_on, get_autoscaley_on e get_autoscale_on e seus pares set.
autoscale(enable=False) desabilita; enable=None mantém os estados atuais.
Home/voltar/avançar restauram também os estados de autoescala da vista registrada.
ax.margins() consulta as margens sem invalidar a figura. O padrão é 5% por
eixo, configurável por axes.xmargin/axes.ymargin. ax.margins(.1) muda ambos;
ax.margins(x=.1, y=-.1) admite recorte com margens negativas maiores que -0.5.
Os limites manuais continuam fixos. As políticas explícitas de map/state são
preservadas. Sem dados novos, relim/autoscale_view conservam a vista.
relim(visible_only=True) exclui camadas ocultas. A recomposição inclui
geometrias, pontos de scatter, bordas de mesh e origens de vetores; ignora
texto, ornamentos, insets e camadas com fit=False. Assim, um mapa de fundo não
impede a autoescala de uma rota. A inclusão dessas coleções geográficas é uma
extensão própria: o relim do Matplotlib tem restrições para Collections.
Limites desta implementação
Os limites são longitude/latitude em graus. O domínio ordinário é ±180°/±90°;
na 0.3.0 em desenvolvimento, extents cilíndricos cruzados estabelecem um ramo
contínuo de 360°, descrito em geodesia/antimeridiano. Um dado singular
recebe expansão inicial de ±0.5° antes da margem, uma regra geográfica própria.
Vistas invertidas, sticky_edges, round_numbers e unidades automáticas de Axis
continuam fora deste corte. Shared axes já propagam limites/tickers. tight
controla a política de dados/margens disponível; fit circular é optativo.
Veja o exemplo antes/depois, o ciclo de vida de Artists e as pendências. O HTML é uma cena exportada: alterações posteriores no processo Python exigem nova exportação.