diff --git a/index.html b/index.html
index d8e6cf339837b31cfef877259bef790cfdf9a9e3..ffd85166a637d2e9f2663e4d0af622259c486144 100644
--- a/index.html
+++ b/index.html
@@ -18,10 +18,23 @@
         <div id="bubble-chart-wrapper">
 
         </div>
-        <div id="zoom-wrapper">
-            <button id="zoom-out">-</button>
-            <input type="range" min="1" max="100" value="50" class="slider" id="zoom-slider"/>
-            <button id="zoom-in">+</button>
+        <div class="bubble-chart-settings">
+            <div class="group-by">
+                <label for="group-by-setting">Gruppieren nach:</label>
+
+                <select id="group-by-setting" name="group-by-setting">
+                    <option value="default">Keine</option>
+                    <option value="nation">Nation</option>
+                    <option value="pos">Position</option>
+                    <option value="team">Team</option>
+                    <option value="league">Liga</option>
+                </select>
+            </div>
+            <div id="zoom-wrapper">
+                <button id="zoom-out">-</button>
+                <input type="range" min="1" max="100" value="50" class="slider" id="zoom-slider"/>
+                <button id="zoom-in">+</button>
+            </div>
         </div>
     </div>
     <div class="right">
diff --git a/src/charts/bubbleChart.ts b/src/charts/bubbleChart.ts
index e3d409ab2466a44ee9ca470b5ee2ae951fd4fd85..8eab46d63293e7faf1c76488954976999f9ca16c 100644
--- a/src/charts/bubbleChart.ts
+++ b/src/charts/bubbleChart.ts
@@ -41,6 +41,21 @@ export default class BubbleChart extends SearchableChart {
         this.initVis()
     }
 
+    set _config(_config: BubbleChartConfigParam) {
+        this.config = {
+            ..._config,
+            parentElement: typeof _config.parentElement === 'string' ? document.querySelector(_config.parentElement) as HTMLElement : _config.parentElement,
+            containerWidth: _config.containerWidth || 500,
+            containerHeight: _config.containerHeight || 140,
+            margin: _config.margin || {top: 10, bottom: 30, right: 10, left: 30},
+            tooltipPadding: _config.tooltipPadding || 15,
+            groupAccessor: _config.groupAccessor || (() => 'default'),
+            sizeAccessor: _config.sizeAccessor || (() => 5),
+            colorAccessor: _config.colorAccessor || (() => null),
+            zoomExtent: _config.zoomExtent || [0.5, 20],
+        }
+    }
+
     initVis() {
         let vis = this;
         vis.config.parentElement.innerHTML += `
@@ -68,40 +83,47 @@ export default class BubbleChart extends SearchableChart {
     }
 
     updateVis(data: any[]): void {
-        this.data = data
+        this.data = data;
+        this.update()
     }
 
-    renderVis(): void {
-        let vis: BubbleChart = this;
+    updateVisConfig(_config: BubbleChartConfigParam): void {
+        this._config = {...this.config, ..._config};
+        this.update()
+    }
 
-        /*vis.config.groupAccessor = (d: any) => {
-            return d['nation']
-        }*/
+    private update() {
+        let vis: BubbleChart = this;
 
-        const chart = vis.chart
+        vis.updatePackRoot()
 
-        const groupedData = d3.group(
-            vis.data,
-            (d: any) => vis.config.groupAccessor(d)
-        )
+        const node = vis.chart
+            .selectAll("g")
+            .data(vis.packRoot?.descendants())
+            .transition()
+            .duration(1000)
+            .attr("transform", (d: any) => `translate(${d.x},${d.y})`)
 
+        node.selectAll('circle')
+            .transition()
+            .duration(1000)
+            .attr('fill', (d: any) => vis.getFillForNode(d))
+    }
 
-        const pack = d3.pack()
-            .size([vis.width(), vis.height()])
-            .padding(2)
+    renderVis(): void {
+        let vis: BubbleChart = this;
 
-        vis.packRoot = pack((d3.hierarchy(groupedData) as HierarchyNode<any>)
-            .sum((d: any) => vis.config.sizeAccessor(d)))
+        vis.updatePackRoot()
 
-        const node = chart
+        const node = vis.chart
             .selectAll("g")
-            .data(vis.packRoot.descendants())
+            .data(vis.packRoot?.descendants())
             .join("g")
             .attr("transform", (d: any) => `translate(${d.x},${d.y})`)
 
         node
             .append('circle')
-            .attr('fill', (d:any) => d.children ? "transparent" : 'var(--primary)')
+            .attr('fill', (d: any) => vis.getFillForNode(d))
             .attr('stroke', 'none')
             .attr('stroke-width', 2)
             .attr('r', (d: any) => d.r)
@@ -116,12 +138,13 @@ export default class BubbleChart extends SearchableChart {
                     .style('left', (event.layerX + vis.config.tooltipPadding) + 'px')
                     .style('top', (event.layerY + vis.config.tooltipPadding) + 'px')
             })
-            .on('mouseleave', () => {
+            .on('mouseleave', (_: Event, d: any) => {
+                console.log(d.data)
                 d3.select('#tooltip').style('display', 'none');
             })
     }
 
-    renderTooltip(dataPoint: { player: string; league: string; pos: string; nation: string; team: string;}) {
+    private renderTooltip(dataPoint: { player: string; league: string; pos: string; nation: string; team: string; }) {
         d3.select('#tooltip')
             .style('display', 'block')
             .html(`
@@ -135,6 +158,31 @@ export default class BubbleChart extends SearchableChart {
         `)
     }
 
+    /**
+     * Updates the d3 hierachy pack root with the current data.
+     * Uses the groupAccessor and sizeAccessor to group the data.
+     * @private
+     */
+    private updatePackRoot() {
+        const groupedData = d3.group(
+            this.data,
+            (d: any) => this.config.groupAccessor(d)
+        )
+        console.log(groupedData)
+        this.packRoot = d3.pack()
+            .size([this.width(), this.height()])
+            .padding(4)
+            (
+                (d3.hierarchy(groupedData) as HierarchyNode<any>)
+                    .sum((d: any) => this.config.sizeAccessor(d))
+            )
+    }
+
+    private getFillForNode(node: HierarchyNode<any>) {
+        if (node.children) return "transparent"
+        return this.config.colorAccessor(node) ?? 'var(--primary)'
+    }
+
     search(input: string): void {
         if (!input) return
         if (!input || !this.packRoot) return
diff --git a/src/main.ts b/src/main.ts
index 7c06fcd56c99c04cefdfb5b1a894e3b524b26aeb..8cf09e2d218558fcdfcf33ff110ffc94b0b437a1 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,6 +1,6 @@
 import "@/styles/index.scss"; // imports the default styles
 import {dsv} from "d3-fetch";
-import BubbleChart from "@/charts/bubbleChart.ts";
+import BubbleChart, {BubbleChartConfigParam} from "@/charts/bubbleChart.ts";
 import Search from "@/search.ts";
 
 // const radarChartWrapper = document.querySelector('#radar-chart-wrapper') as HTMLDivElement;
@@ -20,6 +20,13 @@ zoomSlider.oninput = (event) => {
     }
 }
 
+const groupBySetting = document.querySelector('#group-by-setting') as HTMLInputElement
+groupBySetting.oninput = (event) => {
+    if (bubbleChart) {
+        bubbleChart.updateVisConfig({groupAccessor: (d: any) => d[event.target?.value]} as BubbleChartConfigParam)
+    }
+}
+
 dsv(';', 'data/output.csv').then(data => {
     bubbleChart = new BubbleChart(data, {
         parentElement: bubbleChartWrapper,