HotXLS conserva el ChartML original de un gráfico de Excel importado y lo reproduce byte a byte cuando nada del modelo tipado cambió, así que abrir y volver a guardar un libro no elimina silenciosamente las partes de un gráfico que el modelo de objetos no representa. Edita un título, una serie o un eje y HotXLS fusiona estructuralmente los nuevos nodos tipados en el árbol original en vez de regenerar el gráfico desde cero
Esa distinción — reproducir cuando no se toca, fusionar cuando se edita — es lo que vuelve seguro apuntar una aplicación Delphi a gráficos que un analista construyó en Excel. Regenerar un gráfico desde un modelo tipado siempre pierde lo que el modelo no conoce, y los gráficos de Excel están llenos de cosas que una biblioteca no conoce: estilos personalizados, listas de extensión, ramas de contenido alternativo, formato calificado por espacios de nombres proveniente de complementos
¿Por qué volver a guardar un libro aplana sus gráficos?
Porque la implementación habitual lee lo que entiende y escribe lo que entiende. Todo lo que queda en medio — un extLst de una versión más nueva de Excel, una rama mc:AlternateContent, un efecto de forma para el que el modelo no tiene propiedad — existe en el archivo, no tiene hogar en el modelo de objetos, y desaparece al guardar. El usuario ve un gráfico que perdió su degradado, sus etiquetas de datos personalizadas o su efecto 3D, y el libro no puede explicar por qué
Con PreserveUnsupportedParts habilitado en el libro, HotXLS almacena al importar los bytes UTF-8 originales del gráfico junto con una longitud y una huella digital de 64 bits del contenido modelado. Si el modelo tipado no cambió al momento de guardar, escribe los bytes originales de vuelta. Sin reordenamiento de XML, sin deriva de espacios en blanco, sin copia UTF-16 residente del gráfico colgada en memoria para un gráfico que nadie editó
var
Workbook: TXLSXWorkbook;
Chart: TXLSXChart;
begin
Workbook := TXLSXWorkbook.Create(nil);
try
Workbook.PreserveUnsupportedParts := True; // set before Open
Workbook.Open('quarterly-review.xlsx');
Chart := Workbook.Sheets[1].Charts[0]; // Sheets[] is 1-based
if Chart.HasPreservedXml then
Log('original ChartML retained; untouched charts replay exactly');
Chart.Title := 'Revenue by region, Q3 2026'; // now the merge path runs
Workbook.SaveAs('quarterly-review-out.xlsx');
finally
Workbook.Free;
end;
end;
Qué conserva la fusión y de qué es dueño el modelo
La regla es la propiedad. Los nodos públicos del modelo — título, series, cachés, grupos de trazado, ejes — los decide el árbol recién generado. Los subárboles no modelados se trasladan desde el original. Esa asimetría es deliberada, y es la parte que toma un momento asimilar: eliminar una serie no debe resucitar la serie vieja desde el XML preservado, así que cualquier cosa de la que el modelo es dueño se toma del modelo incluso cuando el modelo dice «desaparecido»
El contenido sin dueño se reinserta junto a los nodos coincidentes junto a los que estaba, y extLst se queda de último dentro de su padre porque ahí es donde el esquema lo exige. Limpiar una propiedad conocida — quitar una bandera de negrita, descartar un color — se trata como una limpieza, no como un hueco a rellenar desde el árbol original. Los atributos desconocidos en la misma vecindad conservan su lugar
El contenido de compatibilidad de marcado recibe manejo específico. Al analizar, HotXLS salta mc:Choice y lee mc:Fallback; si esa rama de respaldo envuelve un grupo de trazado que el modelo conoce, la fusión escribe el nuevo contenido tipado de vuelta en el subárbol de respaldo. Sin ese paso un guardado emitiría el nuevo grupo de trazado y dejaría el viejo dentro del respaldo, y el gráfico llevaría dos
Sacar un gráfico del esquema
ClearPreservedXml descarta el XML y la huella originales de un gráfico, así el próximo guardado reconstruye ese gráfico puramente desde el modelo tipado. Es una decisión por gráfico; el PreserveUnsupportedParts a nivel de libro sigue rigiendo si el estado de preservación se construye al importar
Recurre a ello cuando quieres un gráfico limpio en vez de uno fiel — por ejemplo cuando un gráfico de plantilla lleva formato de un tema corporativo antiguo y el punto de la operación es descartarlo. No lo uses como reflejo de depuración: un gráfico que se renderiza mal tras una edición es más a menudo una pregunta de modelado que de preservación, y limpiar el XML preservado destruye la evidencia
Gráficos combinados y el segundo eje
AddPlotGroup construye gráficos combinados ordenados, donde cada grupo de trazado conserva su propia familia de gráfico y su propia asignación de eje primario o secundario. Eso es lo que el ubicuo gráfico de negocios necesita: ingresos como columnas en el eje izquierdo, margen porcentual como línea en el derecho
Los gráficos exponen ejes de categoría y de valor primarios y secundarios más un eje de series, con ajustes tipados de categoría, valor, fecha y eje de series que cubren posiciones, identificadores, cruces, unidades de fecha, intervalos de etiqueta y visibilidad. La API plana anterior — ChartType, AddSeries, la colección plana Series — sigue dirigiéndose al grupo de trazado primario, así que el código existente sigue funcionando mientras el modelo subyacente sostiene cada grupo ordenado
var
Chart: TXLSXChart;
Line: TXLSXChartPlotGroup;
begin
// Column chart anchored over rows 1..15, columns 5..12
Chart := Sheet.Charts.Add(xlsxChartColumn, 'Revenue and margin',
1, 5, 15, 12);
Chart.AddSeries('Revenue', 'Data!$A$2:$A$13', 'Data!$B$2:$B$13');
// Second plot group: a line, read against the secondary value axis
Line := Chart.AddPlotGroup(xlsxChartLine, xlsxAxisSecondary);
Line.AddSeries('Margin %', 'Data!$A$2:$A$13', 'Data!$C$2:$C$13');
end;
Antes de que existiera este modelo, abrir y volver a guardar un gráfico combinado lo colapsaba en una sola familia de gráfico y perdía los ejes secundario, de fecha y de series. Las referencias a fórmulas de gráfico y los valores de serie cacheados ahora sobreviven a copias del libro y a ciclos de apertura y guardado también, y los anclajes de gráfico se emparejan con sus partes de gráfico por identificador de relación — así que una aplicación que reordena entradas de relación ya no intercambia contenidos de gráfico entre posiciones de la hoja de cálculo
La trampa del manual layout
Si posicionas a mano un área de trazado, un título, un título de eje o una leyenda, escribe las cuatro coordenadas. Office exige x, y, w y h como un grupo completo siempre que cualquiera de ellos esté presente, e ignora el manualLayout entero en caso contrario. HotXLS siempre emite el rectángulo completo por esa razón, y SetPositionAndSize lo fija y habilita en una sola llamada
Dos detalles más siguen a Excel en vez de la amplitud total de la especificación. La posición se escribe con xMode e yMode puestos en edge mientras el tamaño usa factor para wMode y hMode, porque eso es lo que Excel escribe y lo que convierte en otras combinaciones. Y layoutTarget se emite solo para el área de trazado, nunca para títulos o leyendas, donde las notas de implementación de Microsoft lo prohíben
Cómo encajar esto en un ciclo de ida y vuelta del libro
La preservación de gráficos es una instancia de una política general: una biblioteca que edita documentos creados en otra parte debería cambiar lo que se le pidió cambiar y nada más. El mismo razonamiento impulsa a HotXLS en temas, cadenas de cálculo y extensiones de hoja de cálculo, descrito en las notas sobre los ciclos sin pérdida para tema, extLst y calcChain, y sobre proyectos VBA y enlaces externos en la preservación de VBA y enlaces externos. Para la superficie de creación de gráficos en sí — crear gráficos, colocar imágenes y dibujos desde Delphi — consulta el recorrido por gráficos, imágenes y dibujos en HotXLS
HotXLS lee, edita y escribe gráficos XLSX desde código nativo de Delphi y C++Builder sin instalación de Excel en la máquina, que es lo que convierte la fidelidad en un problema de biblioteca en vez de un problema de automatización — la página del componente de hoja de cálculo HotXLS tiene la lista de características de gráficos y una descarga de prueba