This demo uses imperative chart updates. The generated code is a faithful Angular translation: open it in CodeSandbox to run and tweak.

import { Component, AfterViewInit, OnDestroy, ViewChild } from '@angular/core';
import {
  ChartComponent,
  ApexAxisChartSeries,
  ApexNonAxisChartSeries,
  ApexChart,
  ApexXAxis,
  ApexYAxis,
  ApexTitleSubtitle,
  ApexDataLabels,
  ApexStroke,
  ApexFill,
  ApexLegend,
  ApexTooltip,
  ApexMarkers,
  ApexPlotOptions,
  ApexResponsive,
  ApexGrid,
  ApexAnnotations,
  ApexStates,
  ApexTheme,
  NgApexchartsModule,
} from 'ng-apexcharts';

export type ChartOptions = {
  series?: ApexAxisChartSeries | ApexNonAxisChartSeries;
  chart?: ApexChart;
  xaxis?: ApexXAxis;
  yaxis?: ApexYAxis | ApexYAxis[];
  title?: ApexTitleSubtitle;
  subtitle?: ApexTitleSubtitle;
  dataLabels?: ApexDataLabels;
  stroke?: ApexStroke;
  fill?: ApexFill;
  legend?: ApexLegend;
  tooltip?: ApexTooltip;
  markers?: ApexMarkers;
  plotOptions?: ApexPlotOptions;
  responsive?: ApexResponsive[];
  grid?: ApexGrid;
  annotations?: ApexAnnotations;
  states?: ApexStates;
  theme?: ApexTheme;
  colors?: string[];
  labels?: any;
};

@Component({
  selector: 'app-chart',
  standalone: true,
  imports: [NgApexchartsModule],
  templateUrl: './chart.component.html',
})
export class AppChart implements AfterViewInit, OnDestroy {
  @ViewChild('chart') chart!: ChartComponent;
  private REGIONS: any = [
          { name: 'Americas', color: '#22C55E' },
          { name: 'Europe', color: '#0EA5E9' },
          { name: 'Asia', color: '#F59E0B' },
          { name: 'Oceania', color: '#F43F5E' },
        ];

  private DATA: any = {
          Americas: [
            ['New York', 55000, 100, 18.9, 2000],
            ['San Francisco', 62000, 98, 4.7, 650],
            ['Toronto', 40000, 72, 6.4, 400],
            ['Sao Paulo', 12000, 40, 22.6, 480],
            ['Mexico City', 11000, 38, 22.0, 480],
          ],
          Europe: [
            ['Zurich', 72000, 118, 1.4, 340],
            ['London', 45000, 85, 14.3, 1000],
            ['Paris', 38000, 80, 11.1, 850],
            ['Berlin', 36000, 70, 6.1, 180],
            ['Moscow', 18000, 45, 12.6, 550],
          ],
          Asia: [
            ['Tokyo', 40000, 83, 37.4, 1600],
            ['Singapore', 55000, 95, 5.9, 470],
            ['Dubai', 45000, 70, 3.5, 130],
            ['Hong Kong', 42000, 90, 7.5, 380],
            ['Seoul', 34000, 78, 26.0, 780],
            ['Shanghai', 20000, 60, 27.0, 680],
            ['Mumbai', 8000, 35, 20.7, 310],
            ['Delhi', 7000, 32, 32.0, 370],
          ],
          Oceania: [
            ['Sydney', 48000, 88, 5.3, 400],
            ['Melbourne', 44000, 82, 5.0, 250],
          ],
        };

  private seriesFor = (sizeBy: any): any => {
          return this.REGIONS.map(function (r) {
            return {
              name: r.name,
              data: this.DATA[r.name].map(function (c) {
                return {
                  name: c[0],
                  x: c[1],
                  y: c[2],
                  z: sizeBy === 'gdp' ? c[4] : c[3],
                }
              }),
            }
          })
        };

  private VIEWS: any = {
          population: {
            caption:
              'Sized by population, the megacities swell: Tokyo, Delhi, Shanghai and Sao Paulo dominate, even where incomes are low and living is cheap.',
          },
          gdp: {
            caption:
              'Sized by economic output, the money centres take over: New York, Tokyo, London and Paris lead, while populous but poorer cities shrink.',
          },
        };

  private buttons: any = document.querySelectorAll('#size-nav button');

  private caption: any = document.getElementById('caption');

  private showSize = (key: any): any => {
          this.buttons.forEach(function (b) {
            b.classList.toggle('active', b.getAttribute('data-size') === key)
          })
          this.caption.textContent = this.VIEWS[key].caption
          this.chart.updateSeries(this.seriesFor(key))
        };

  public chartOptions: Partial<ChartOptions> = {
          series: this.seriesFor('population'),
          chart: {
            id: 'cityBubbles',
            type: 'unit',
            height: 520,
            animations: {
              enabled: true,
              speed: 700,
            },
          },
          colors: this.REGIONS.map(function (r) {
            return r.color
          }),
          // Translucent fills so overlapping bubbles read through each other.
          fill: {
            opacity: 0.7,
          },
          legend: {
            position: 'bottom',
          },
          plotOptions: {
            unit: {
              layout: 'scatter',
              scatter: {
                y: 'value',
                xMin: 0,
                yMin: 0,
                xTitle: 'Average income (US$/yr)',
                yTitle: 'Cost of living (NYC = 100)',
                xFormatter: (v) => {
                  return '$' + Math.round(v / 1000) + 'k'
                },
                sizeRange: [7, 44],
              },
              tooltip: {
                formatter: (o) => {
                  var d = (o && o.datum) || {}
                  if (!d.name) return ''
                  return (
                    d.name +
                    ': $' +
                    Math.round(d.x / 1000) +
                    'k income, cost of living ' +
                    d.y
                  )
                },
              },
            },
          },
        };
  ngAfterViewInit() {
    (window as any).ApexCharts.setLicense('APEX-eyJpc3N1ZURhdGUiOiIyMDI2LTA0LTE2IiwiZXhwaXJ5RGF0ZSI6IjIwNTItMDQtMTciLCJwbGFuIjoiZW50ZXJwcmlzZSIsImRvbWFpbnMiOlsiYXBleGNoYXJ0cy5jb20iLCIxMjcuMC4wLjEiXX0=');

    function showSize(key) {
            this.buttons.forEach(function (b) {
              b.classList.toggle('active', b.getAttribute('data-size') === key)
            })
            this.caption.textContent = this.VIEWS[key].caption
            this.chart.updateSeries(this.seriesFor(key))
          }
    this.buttons.forEach(function (btn) {
            btn.addEventListener('click', () => {
              this.showSize(btn.getAttribute('data-size'))
            })
          })
  }

  ngOnDestroy() {
    // no cleanup needed
  }
}
City Bubbles - Angular Unit Charts | ApexCharts.js | ApexCharts.js