Milhões de pontos em tempo real? Conheça Reflex XY.

XY Library: A Revolução da Visualização de Dados Interativos em Python Que Você PRECISA Conhecer!

Olá, pessoal! Aqui é o Lucas Tech, e hoje vamos mergulhar de cabeça em algo que vai mudar a forma como você enxerga seus dados: a biblioteca XY do Python! Se você, assim como eu, adora transformar números brutos em histórias visuais incríveis e interativas, prepare-se, porque o que vem por aí é simplesmente sensacional. O XY não é só mais uma ferramenta de gráficos; ele é um game changer para quem busca visualizações escaláveis, extensíveis e que realmente conversam com o usuário.

Vamos explorar juntos como essa ferramenta nos permite construir gráficos interativos e super completos, desde a base até as personalizações mais avançadas. Bora lá!

Configurando o Ambiente e o Primeiro Gráfico!

Para começar nossa jornada, precisamos do XY instalado e configurado, especialmente se você estiver usando o Google Colab para acompanhar. Esse primeiro bloco de código é a nossa porta de entrada, garantindo que tudo funcione direitinho, incluindo os widgets interativos que tornam o XY tão poderoso.

php
import subprocess, sys, os
subprocess.run([sys.executable, "-m", "pip", "install", "-q", "xy"], check=True)
WIDGETS_OK = True
try:
from google.colab import output as _colab_output
_colab_output.enable_custom_widget_manager()
except Exception:
WIDGETS_OK = False
import numpy as np
import pandas as pd
import xy
from IPython.display import display, HTML
print("xy", xy.version, "| live widgets:", WIDGETS_OK)
def render(chart, note=""):
if note:
display(HTML(f"

{note}

"))
try:
display(chart)
except Exception:
display(HTML(chart.to_html()))
return chart
rng = np.random.default_rng(7)
days = np.arange(180)
trend = 200 + 0.9 days + 18 np.sin(days / 9.0)
revenue = trend + rng.normal(0, 12, days.size)
sigma = 10 + 6 np.abs(np.sin(days / 15.0))
conv = 0.06 + 0.02
np.sin(days / 21.0) + rng.normal(0, 0.003, days.size)
peak = int(np.argmax(revenue))
layered = xy.chart(
xy.error_band(days, revenue – 1.96 sigma, revenue + 1.96 sigma,
name="95% band", color="#7c3aed", opacity=0.16),
xy.line(days, revenue, name="Revenue", color="#7c3aed", width=2.5,
curve="smooth"),
xy.scatter(days[::12], revenue[::12], name="Weekly check", color="#7c3aed",
size=7, stroke="#ffffff", stroke_width=1.5),
xy.line(days, conv, name="Conversion", color="#f59e0b", width=2,
dash="dashed", y_axis="y2"),
xy.x_axis(label="Day", grid=True),
xy.y_axis(label="Revenue (k)", grid=True, format=",.0f"),
xy.y_axis(id="y2", label="Conversion", side="right", grid=False, format=".1%"),
xy.x_band(120, 150, text="Campaign", color="#22c55e", opacity=0.10),
xy.hline(float(revenue.mean()), text="mean", color="#94a3b8"),
xy.callout(float(days[peak]), float(revenue[peak]), "peak", dx=-60, dy=-40),
xy.legend(loc="upper left", ncols=2, toggle=True),
xy.tooltip(title="Day", format={"y": ",.1f"}),
xy.modebar(True),
xy.theme(palette=["#7c3aed", "#f59e0b"], grid_color="#e6e6ef"),
title="Layered composition · dual axes · annotations",
width=900, height=440, crosshair=True,
)
render(layered, "1 · Composition model")

Depois de instalar e preparar o terreno, a mágica começa! O XY usa um modelo de composição onde você combina diferentes "marcas" (linhas, pontos, bandas de erro) e as sobrepõe para criar gráficos riquíssimos. No exemplo acima, montamos uma visualização em camadas com eixos duplos, anotações (olha o pico de receita e a campanha!), dicas de ferramentas, legendas e até um tema personalizado. É tipo um lego para dados, mas com superpoderes interativos!

Explorando Seus Dados com Pandas e o Poder da Densidade!

Agora a coisa fica séria! O XY se integra perfeitamente com o Pandas, permitindo que a gente use nomes de colunas diretamente para mapear canais visuais. Isso é uma mão na roda para quem já está acostumado a trabalhar com DataFrames.

php
n = 4000
df = pd.DataFrame({
"x": rng.normal(0, 1, n),
"noise": rng.normal(0, 1, n),
"region": rng.choice(["North", "South", "East", "West"], n),
})
df["y"] = 2.1 df["x"] + df["noise"] 0.9
df["mag"] = np.abs(df["y"])
render(xy.scatter_chart(
xy.scatter("x", "y", color="mag", colormap="plasma",
size=5, opacity=0.7, color_domain=(0, 6)),
xy.colorbar(title="|y|"),
xy.x_axis(label="x"), xy.y_axis(label="y"),
data=df, title="Columns resolved by name", width=760, height=420,
), "2 · DataFrame-driven channels")
render(xy.facet_chart(
xy.scatter("x", "y", color="#0ea5e9", size=4, opacity=0.6),
by="region", data=df, cols=2,
share_x=True, share_y=True, link=True, link_select=True,
width=760, height=220, gap=12, title="Faceted by region",
), "3 · Facets with linked axes")
N = 1_500_000
r = 6.0 rng.beta(1.2, 3.0, N)
theta = 2.9
np.log1p(r) + rng.integers(0, 4, N) (np.pi / 2) + rng.normal(0, 0.05, N)
big = xy.scatter_chart(
xy.scatter(r
np.cos(theta), r * np.sin(theta),
color=np.exp(-r / 2.2), colormap="magma_r",
density=True,
size=2.5, opacity=0.85,
zoom_size_factor=2.6, zoom_opacity=0.95),
xy.colorbar(title="density"),
title=f"{N:,} points · drag to pan, scroll to zoom",
width=760, height=520, zoom=True, pan=True, wheel_zoom=True,
)
render(big, "4 · Million-point density surface")
mem = big.memory_report()
print(f"canonical f64 held in Python : {mem[‘canonical_bytes’]/1e6:.1f} MB")
print(f"bytes sent for first paint : {mem[‘transport_bytes_first_paint’]/1e6:.2f} MB "
f"({mem[‘transport_bytes_per_point’]:.3f} B/point)")
print(f"compute backend : {mem[‘backend’]}")

Aqui, criamos um DataFrame e usamos os nomes das colunas x, y e mag diretamente para gerar um gráfico de dispersão com cores. Mas o mais legal é quando dividimos o dataset em "facetas" regionais, mantendo os eixos compartilhados e interligados. Isso é ótimo para comparar categorias!

E para quem lida com Big Data, o XY simplesmente MANDA! Visualizamos 1.5 milhão de pontos usando o sistema de renderização por densidade. Isso significa que mesmo com uma montanha de dados, o gráfico permanece fluido e responsivo. É impressionante ver como ele otimiza o uso de memória e a transferência de dados.

Interatividade Total: Conectando o Navegador ao Python e Streaming de Dados!

Isso aqui é a cereja do bolo! O XY permite que as interações do navegador (tipo selecionar uma área no gráfico) "conversem" de volta com o Python. O gráfico não é só bonito, ele é INTELIGENTE!

php
sel = big.select_range(-1.0, 1.0, -1.0, 1.0)
sx, sy = sel.xy(0)
print(f"\nselect_range hit {len(sel):,} rows; x array {sx.shape}")
print("first rows:", sel.rows(limit=2))
print("pick(trace=1, index=10):", layered.pick(1, 10))
def on_select(selection):
xs, ys = selection.xy(0)
print(f"[callback] {len(selection):,} rows selected, mean y = {ys.mean():.3f}")
def on_view_change(payload):
print("[callback] viewport:", payload)
render(xy.scatter_chart(
xy.scatter("x", "y", color="#ef4444", size=5, opacity=0.7),
data=df, select=True, on_select=on_select, on_view_change=on_view_change,
title="Shift-drag a box → payload lands in Python",
width=760, height=380,
), "5 · Selections routed back to the kernel")
stream = xy.line_chart(
xy.line([0.0], [0.0], color="#10b981", width=2, name="live"),
xy.x_axis(label="t"), xy.y_axis(label="value", domain=(-3, 3)),
title="Streaming via chart.append()", width=760, height=320,
)
render(stream, "6 · Streaming")
import time
for k in range(1, 60):
t = k / 3.0
stream.append(0, [t], [float(np.sin(t) + rng.normal(0, 0.08))])
time.sleep(0.03)

Neste trecho, demonstramos como podemos selecionar pontos exatos de uma visualização grande e obter seus valores originais diretamente no Python. Além disso, definimos funções de callback que reagem a seleções e mudanças de viewport no navegador, mantendo seus dados processáveis no kernel.

E se você precisa de dados em tempo real? O XY também tem isso! Criamos um gráfico de linha que recebe novos dados via streaming, atualizando a visualização dinamicamente. É perfeito para monitoramento ou dashboards ao vivo!

Design e Extensão Sem Limites: Customização, Marks Personalizados e Exportação!

Mas e se você quiser ir além na estética ou funcionalidade? O XY pensa em tudo! Podemos personalizar componentes do gráfico usando slots DOM, classes CSS e estilos inline. E as animações? Elas podem ter um toque especial com efeitos de mola!

php
print("\navailable slots:", ", ".join(sorted(xy.CHART_DOM_SLOTS)))
CSS = """
.xy-card {background:#fafaf9;border:1px solid #e7e5e4;border-radius:16px;padding:10px}
.xy-title{font:600 16px/1.2 ui-sans-serif;letter-spacing:-.01em;color:#1c1917}
.xy-tip {border-radius:10px;background:#1c1917;color:#fafaf9}
"""
display(HTML(f""))
styled = xy.line_chart(
xy.line(days, revenue, color="#111827", width=2,
animation=xy.animation(duration=700,
easing=xy.spring(stiffness=180, damping=22))),
xy.x_axis(label="Day"), xy.y_axis(label="Revenue"),
title="Slot-addressed styling",
class_name="xy-card",
class_names={"title": "xy-title", "tooltip": "xy-tip"},
styles={"canvas": {"border-radius": "12px"}},
width=760, height=360,
)
render(styled, "7 · CSS slots, tokens, spring animation")
def _fit(cols):
x = np.asarray(cols["x"], float); y = np.asarray(cols["y"], float)
b, a = np.polyfit(x, y, 1)
order = np.argsort(x); xs = x[order]
fit = a + b xs
resid = float(np.std(y – (a + b
x)))
return {"x": xs, "y": y[order], "fit": fit,
"lo": fit – 1.96 resid, "hi": fit + 1.96 resid}
def _build(ctx):
color = ctx.options.get("color", "#2563eb")
c, nm = ctx.columns, (ctx.name or "trend")
return [
xy.error_band(c["x"], c["lo"], c["hi"], color=color, opacity=0.18, name=f"{nm} CI"),
xy.line(c["x"], c["fit"], color=color, width=2.5, name=nm),
]
if "trendline" not in xy.registered_marks():
xy.register_mark(xy.MarkPlugin(name="trendline", build=_build,
columns=("x", "y"), calc=_fit,
doc="OLS fit with a 95% band."))
render(xy.chart(
xy.scatter("x", "y", color="#94a3b8", size=4, opacity=0.5, name="observations"),
xy.mark("trendline", x="x", y="y", color="#e11d48", name="OLS"),
xy.legend(loc="upper left"),
data=df, title="Third-party mark kind", width=760, height=400,
), "8 · Custom mark plugin")

Mas o que eu achei mais insano é a capacidade de criar nossas próprias "marcas" personalizadas! Definimos um cálculo de mínimos quadrados ordinários que gera uma linha de tendência e uma banda de confiança. Depois, registramos isso como uma marca reutilizável do XY, combinando-a com os componentes já existentes. Imagina o poder de criar seus próprios tipos de gráfico!

php
import xy.pyplot as plt
t = np.linspace(0, 10, 400)
fig, ax = plt.subplots(figsize=(8, 3.5))
ax.plot(t, np.sin(t), "r–", label="sin")
ax.plot(t, np.cos(t), label="cos")
ax.set_xlabel("t"); ax.set_ylabel("amplitude"); ax.set_title("xy.pyplot compatibility")
ax.legend(); ax.grid(True, alpha=0.3)
plt.show()
os.makedirs("out", exist_ok=True)
layered.to_html("out/chart.html")
layered.to_svg("out/chart.svg")
layered.to_png("out/chart.png", scale=2)
for f in ("chart.html", "chart.svg", "chart.png"):
print(f"out/{f}: {os.path.getsize(‘out/’+f)/1024:.0f} KB")
print("\n✅ tutorial complete")

E pra fechar com chave de ouro: compatibilidade com Matplotlib! O xy.pyplot nos permite usar comandos familiares para criar plots, o que é ótimo para quem já tem intimidade com a biblioteca. E a exportação? Você pode salvar seus gráficos como HTML (mantendo a interatividade!), SVG (qualidade vetorial para publicações) ou PNG de alta resolução. Versatilidade é tudo!

Minha Visão

Cara, sério, depois de explorar o XY em detalhes, minha visão é uma só: essa biblioteca é um divisor de águas! Ela não só simplifica a criação de visualizações complexas e interativas em Python, como também abre um mundo de possibilidades para quem trabalha com análise de dados. A facilidade de lidar com milhões de pontos, a interatividade em tempo real e a flexibilidade para personalizar tudo – até criar seus próprios elementos gráficos – são algo que eu realmente buscava. É a prova de que podemos ter gráficos bonitos, funcionais e super inteligentes, tudo na mesma ferramenta. O XY eleva o nível da nossa comunicação de dados, tornando-a mais dinâmica e envolvente, e isso é o que um entusiasta de tecnologia como eu sempre sonhou!

E aí, o que você achou do XY? Você já usou alguma ferramenta que te surpreendeu tanto quanto essa? Deixa seu comentário aqui embaixo!

Referência: Matéria Original

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Rolar para cima
Tutorial Elevenlabs