Grafici Excel più chiari in JavaScript: etichette multilivello e doppi assi

2026-09-23 08:01:39 Allen Yang
AI Summarize:
ChatGPT
ChatGPT ✓
Claude ✓
Grok ✓
Perplexity ✓
Quick
Quick
Concise overview
Highlights
Key takeaways
Detailed
Structured explanation
Brief
One sentence summary
Summarize |

Creating multi-level category labels and adding a secondary axis to an Excel chart in the browser with Spire.XLS for JavaScript

Un grafico a colonne con regioni e mesi sullo stesso asse presenta due problemi, e non si tratta dello stesso problema. Il primo è che le etichette di categoria si riducono a un'unica riga — "North", "Jan", "North", "Feb" — e il lettore deve raggruppare mentalmente quale mese appartiene a quale regione. Il secondo è che quando una serie di tasso di crescita viene aggiunta accanto a una serie di vendite che arriva a milioni, il tasso di crescita diventa una linea piatta aderente alla linea di base, perché un unico asse dei valori non può servire due ordini di grandezza contemporaneamente.

Le etichette di categoria multilivello risolvono il primo problema. Un asse secondario risolve il secondo. Sono funzionalità indipendenti che si trovano a essere utili sullo stesso grafico, e Spire.XLS for JavaScript gestisce entrambe tramite l'API degli assi del grafico — direttamente nel browser su WebAssembly, con i file che transitano attraverso un file system virtuale (VFS) e senza alcun backend coinvolto.

Per la configurazione del progetto, vedere Integrare Spire.XLS for JavaScript in un progetto React. Gli esempi seguenti presuppongono che il pacchetto sia installato e che il modulo WebAssembly sia stato inizializzato.


Quando un asse non è sufficiente

I due problemi si presentano sullo stesso tipo di foglio di lavoro — uno in cui le categorie hanno una gerarchia e i valori hanno un'ampia gamma — ma provengono da origini diverse:

Problema Da dove deriva Come appare il grafico Cosa lo risolve
Le etichette si accalcano in un'unica riga Le categorie sono gerarchiche (regione → mese, anno → trimestre) ma l'asse le tratta come piatte Un'unica riga di etichette in cui le categorie esterne e interne si alternano senza raggruppamento visivo Etichette di categoria multilivello
Una serie si appiattisce in una linea Due serie differiscono di ordini di grandezza (vendite in milioni, crescita in percentuale) ma condividono un unico asse dei valori La serie più piccola si comprime quasi a zero e la sua variazione è invisibile Asse secondario

Nessuno dei due è un problema di stile. Entrambi dipendono dal fatto che l'asse non sa qualcosa che deve sapere — che le categorie hanno livelli, o che i valori hanno scale incompatibili. Le due sezioni seguenti li affrontano una dopo l'altra, e la seconda si basa sulla prima, così il grafico finale contiene entrambe le soluzioni.


Prerequisiti

Serve un progetto React con Spire.XLS for JavaScript installato e il modulo WebAssembly inizializzato, accessibile all'indirizzo window.wasmModule.spirexls. L'esempio carica un font e un file di dati predefinito nella VFS prima di creare il grafico, ed entrambi vengono recuperati dalla cartella public del progetto.


I dati alla base delle etichette multilivello

Le etichette multilivello non vengono create da una sola proprietà — vengono lette dai dati. L'asse delle categorie disegna tanti livelli di etichette quante sono le colonne nell'intervallo a cui punta CategoryLabels. Quindi il foglio di lavoro deve essere organizzato con la gerarchia distribuita sulle colonne:

Colonna A (esterna) Colonna B (interna) Colonna C (valori)
North Jan 120,000
North Feb 135,000
South Jan 98,000
South Feb 110,000

Le etichette esterne nella colonna A sono unite per tutte le righe che coprono — "North" comprende le due righe di Jan e Feb. È questa unione che fa sì che il livello si comprima visivamente in un'unica etichetta per gruppo quando il grafico viene renderizzato. Senza di essa, l'asse mostra comunque due livelli, ma il livello esterno ripete l'etichetta su ogni riga invece di raggrupparla.

Questa è una questione di layout dei dati, non di API del grafico. Il codice del grafico deve solo far puntare CategoryLabels a entrambe le colonne; se le celle esterne sono unite viene deciso nella cartella di lavoro, non nell'oggetto grafico.


Creare un grafico con etichette di categoria multilivello

Una volta organizzati i dati, il codice del grafico fa due cose: fa puntare CategoryLabels a un intervallo che comprende sia la colonna esterna sia quella interna, e attiva MultiLevelLable in modo che l'asse espanda tali colonne in righe sovrapposte. I passaggi sono:

  1. Caricare il font e il file di dati di test nella VFS.
  2. Caricare la cartella di lavoro e ottenere il foglio di lavoro.
  3. Aggiungere un grafico a colonne e aggiungere una serie di vendite con nome.
  4. Far puntare le etichette di categoria sia alla colonna della regione sia a quella del mese.
  5. Attivare le etichette multilivello per l'asse delle categorie e salvare la cartella di lavoro.
function App() {
  const createMultiLevelChart = async () => {
    // Get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    // Check if the module is ready
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // Load the font and the test data file into the VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'MultiLevelChartData.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);

    // Load the workbook and get the first worksheet
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: inputFileName });
    const sheet = workbook.Worksheets.get(0);

    // Add a column chart
    const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
    chart.ChartTitle = "Sales";
    chart.Legend.Delete();

    // Add the sales series and give it a name
    const serie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
    serie.Values = sheet.Range.get("C2:C7");

    // Point the category labels at both the region and the month column
    serie.CategoryLabels = sheet.Range.get("A2:B7");

    // Turn on multi-level category labels so each level gets its own row
    chart.PrimaryCategoryAxis.MultiLevelLable = true;

    // Place the chart on the worksheet
    chart.LeftColumn = 5;
    chart.TopRow = 1;
    chart.RightColumn = 14;

    // Save the workbook
    const outputFileName = "MultiLevelLabels.xlsx";
    workbook.SaveToFile({ fileName: outputFileName });

    // Dispose of the workbook object to free resources
    workbook.Dispose();

    // Read the result file from the VFS and trigger the download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Multi-Level Labels</h1>
      <button onClick={createMultiLevelChart}>Start</button>
    </div>
  );
}

export default App;

Un grafico con etichette di categoria multilivello, ogni livello sulla propria riga

Create a chart with multi-level category labels

È l'intervallo A2:B7 che fa mostrare all'asse due livelli. Associare un intervallo a colonna singola come B2:B7 produrrebbe comunque un solo livello anche con MultiLevelLable impostato su true — la proprietà controlla se più livelli vengono espansi in righe, non se esiste un livello di dati da espandere.


Perché la serie di crescita scompare

Aggiungete una seconda serie per la crescita anno su anno — valori a due cifre basse, percentuali — e tracciatela sullo stesso asse dei valori delle vendite. Le colonne delle vendite raggiungono 120,000; il tasso di crescita raggiunge 12. Su un asse che va da 0 a 140,000, il numero 12 è indistinguibile dallo zero. La serie c'è, i dati sono corretti, e il grafico mostra una linea piatta contro la linea di base.

Non è un bug nei dati o nel grafico. È l'asse dei valori che fa il suo lavoro — mappare un intervallo che copre la serie più grande — a scapito della più piccola. L'unico modo per vedere chiaramente entrambe le serie è dare a ciascuna la propria scala, ed è ciò che fa l'asse secondario.


Spostare una serie sull'asse secondario

La serie di crescita viene aggiunta come linea anziché come colonna. Una linea non occupa larghezza di barra, quindi risulta ben leggibile rispetto alla serie a colonne che condivide le stesse categorie. Spostarla dall'asse primario richiede una sola proprietà: UsePrimaryAxis = false. I passaggi sono:

  1. Caricare il font e il file di dati di test nella VFS.
  2. Caricare la cartella di lavoro e ottenere il foglio di lavoro.
  3. Aggiungere un grafico a colonne e aggiungere una serie di vendite con nome.
  4. Aggiungere la serie di crescita come linea.
  5. Spostare la serie di crescita sull'asse secondario e salvare la cartella di lavoro.
function App() {
  const addSecondaryAxis = async () => {
    // Get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    // Check if the module is ready
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // Load the font and the test data file into the VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'MultiLevelChartData.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);

    // Load the workbook and get the first worksheet
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: inputFileName });
    const sheet = workbook.Worksheets.get(0);

    // Add a column chart
    const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
    chart.ChartTitle = "Sales and YoY Growth";

    // Add the sales series, which stays on the primary axis
    const salesSerie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
    salesSerie.Values = sheet.Range.get("C2:C7");

    // Point the category labels at both the region and the month column
    salesSerie.CategoryLabels = sheet.Range.get("A2:B7");

    // Add the growth series as a line
    const growthSerie = chart.Series.Add({ name: "YoY Growth", serieType: xlsModule.ExcelChartType.Line });
    growthSerie.Values = sheet.Range.get("D2:D7");

    // Move the growth series to the secondary axis so it plots on its own percentage scale
    growthSerie.UsePrimaryAxis = false;

    // Turn on multi-level category labels
    chart.PrimaryCategoryAxis.MultiLevelLable = true;

    // Place the chart on the worksheet
    chart.LeftColumn = 5;
    chart.TopRow = 1;
    chart.RightColumn = 14;

    // Save the workbook
    const outputFileName = "SecondaryAxis.xlsx";
    workbook.SaveToFile({ fileName: outputFileName });

    // Dispose of the workbook object to free resources
    workbook.Dispose();

    // Read the result file from the VFS and trigger the download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Secondary Axis</h1>
      <button onClick={addSecondaryAxis}>Start</button>
    </div>
  );
}

export default App;

Un grafico a colonne con un asse secondario per la serie a linee del tasso di crescita

Add a secondary axis to the chart

UsePrimaryAxis = false influisce solo sulla serie su cui è impostato; tutte le altre serie rimangono sull'asse primario. Il grafico acquisisce una seconda coppia di assi dei valori e delle categorie, ottenendo due intervalli di scala separati. Series.Add accetta contemporaneamente il nome della serie, così la legenda mostra il nome passato invece di un "Series 1" generato automaticamente.


Impostare la scala dell'asse secondario

Una volta che una serie passa all'asse secondario, quell'asse calcola la propria scala — e lo fa indipendentemente da quello primario. I due intervalli non si conoscono a vicenda, il che significa che l'asse secondario potrebbe scegliere limiti che non si allineano bene con i dati.

PrimaryValueAxis.MinValue, MaxValue e MajorUnit controllano solo l'asse primario. Per impostare la scala dell'asse secondario, usate SecondaryValueAxis:

// Give the secondary axis a 0-20 scale with a major unit of 5
chart.SecondaryValueAxis.MinValue = 0;
chart.SecondaryValueAxis.MaxValue = 20;
chart.SecondaryValueAxis.MajorUnit = 5;

Impostate la scala dopo che la serie è stata spostata sull'asse secondario. Finché nessuna serie utilizza l'asse secondario, l'assegnazione viene accettata ma non viene mai scritta nel file — l'asse non esiste nell'output finché non vi viene tracciata una serie.


Problemi comuni

L'asse delle categorie mostra un solo livello di etichette. CategoryLabels punta a un intervallo a colonna singola. Il numero di livelli è determinato da quante colonne copre l'intervallo, non dalla proprietà MultiLevelLable. Puntate a un intervallo multicolonna come A2:B7 e assicuratevi che le celle delle etichette esterne siano unite nei dati.

La scala dell'asse secondario sembra sbagliata. Gli assi dei valori primario e secondario calcolano le rispettive scale in modo indipendente. Impostare MinValue o MaxValue su PrimaryValueAxis non influisce sull'asse secondario. Usate chart.SecondaryValueAxis per impostarne direttamente la scala, e fatelo dopo aver spostato una serie su di esso.

La serie di crescita appare ancora piatta dopo aver aggiunto un asse secondario. Verificate che UsePrimaryAxis = false sia impostato sulla serie di crescita, non su quella delle vendite. La proprietà è per serie — impostarla sulla serie sbagliata sposta quella sbagliata sull'asse secondario.

La legenda mostra "Series 1" invece del nome della serie. Il nome non è stato passato a Series.Add. Usate chart.Series.Add({ name: "Sales", ... }) in modo che la legenda riprenda il nome che intendevate invece di un'etichetta generata automaticamente.


FAQ

Posso avere più di due livelli di etichette di categoria?

Sì. Il numero di livelli è determinato dal numero di colonne che l'intervallo CategoryLabels copre. Un intervallo a tre colonne produce tre livelli — ad esempio anno, trimestre e mese. Le celle delle etichette esterne devono essere unite nei dati affinché ogni livello venga raggruppato correttamente.

L'asse secondario funziona con tipi di grafico diversi da colonne e linee?

Sì. L'asse secondario non è legato a un tipo di grafico specifico. Lo schema più comune è colonne più linee — la linea non occupa larghezza di barra e risulta ben leggibile rispetto alle colonne — ma qualsiasi serie può essere spostata sull'asse secondario impostando UsePrimaryAxis = false.

Devo avere Excel installato per creare questi grafici?

No. Il motore per fogli di calcolo è incluso nel pacchetto e viene eseguito come WebAssembly nel browser. La cartella di lavoro viene creata, rappresentata con grafici e salvata interamente lato client.

Posso controllare separatamente l'asse delle categorie secondario?

Quando una serie passa all'asse secondario, il grafico acquisisce un asse delle categorie secondario oltre all'asse dei valori secondario. I due assi delle categorie condividono le stesse etichette di categoria per impostazione predefinita, quindi le etichette multilivello si applicano a entrambi.

Il file di output è compatibile con Excel?

Sì. La cartella di lavoro viene salvata come .xlsx e il grafico — comprese le etichette multilivello e l'asse secondario — viene scritto come XML di grafico standard che Excel legge nativamente.


Vedi anche