diff --git a/visualisation_model.py b/visualisation_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..0d2e61d61ff2af4e320d1a764f8d5135ebf95a6e
--- /dev/null
+++ b/visualisation_model.py
@@ -0,0 +1,167 @@
+import numpy as np
+import pandas as pd
+import matplotlib.pyplot as plt
+from matplotlib.gridspec import GridSpec
+
+class visualisation_model:
+    x_end = 2*np.pi
+    spaced_labels=[]
+    spaced_y_1=[]
+    spaced_y_0=[]
+    spaced_x_angles=[]
+    x_angles=[]
+    x_positions=[]
+    n=0
+    width=0
+    def __init__(self, labels,y,y_1,y_0,IGQRs,group_1,group_0,title,path,group_1_colour='yellow',group_0_colour='midnightblue',at_least_t_colour='lightblue',lower_t_colour='magenta',quality_threshold=0.8,IGQR_threshold=0.8,optimised_performance_measure='Accuracy'):
+        self.labels=labels
+        self.n = len(labels)  
+        self.width = 2*np.pi/(2*self.n)
+        self.y=y 
+        self.y_1=y_1
+        self.y_0=y_0
+        self.IGQRs=IGQRs
+        self.group_1=group_1
+        self.group_0=group_0
+        self.title = title
+        self.path = path
+        self.quality_threshold = quality_threshold
+        self.IGQR_threshold=IGQR_threshold
+        self.group_1_colour=group_1_colour
+        self.group_0_colour=group_0_colour
+        self.at_least_t_colour=at_least_t_colour
+        self.lower_t_colour=lower_t_colour
+        self.optimised_performance_measure = optimised_performance_measure
+        
+
+    def create_final_visualisation(self):
+        self.spacing_and_positioning()
+        fig,axs = self.axs_creator()
+        axs[0],axs[1]=self.create_circular_barplots(fig, axs[0], axs[1])
+        plt.savefig(self.path)
+        plt.show()
+        
+        
+
+    def spacing_and_positioning(self):
+        '''
+        Spaces between the bars are added and the visual hint of the optimised measure is created
+
+        '''
+        self.spaced_labels=list(np.zeros(2*self.n))
+        self.spaced_y_1=list(np.zeros(2*self.n))
+        self.spaced_y_0=list(np.zeros(2*self.n))
+        for i in range(0,self.n):
+            self.spaced_y_1[2*i]=self.y_1[i]
+            self.spaced_y_0[2*i]=self.y_0[i]
+            self.spaced_labels[2*i-1]=''
+            if self.labels[i]== self.optimised_performance_measure:
+                self.labels[i]='★ ' +self.labels[i]
+            self.spaced_labels[2*i]=self.labels[i]
+        self.x_positions= np.linspace(0, self.x_end,2*self.n,endpoint=False)
+        self.spaced_x_angles = [i * self.width for i in range(0,2*self.n)]
+        self.x_angles= [self.spaced_x_angles[2*i] for i in range(0,self.n)]
+
+    def axs_creator(self):
+        '''
+        Creation of the parallel layout of the sun plot and the IGQR plot
+
+        '''
+        fig = plt.figure(figsize=(10,5),layout='constrained')
+        fig.suptitle(self.title)
+        axs=[]
+        gs = GridSpec(1, 2, figure=fig,hspace=0.0,wspace=0.1)
+        axs.append(fig.add_subplot(gs[0, 0],projection='polar'))
+        axs.append(fig.add_subplot(gs[0, 1],projection='polar'))
+        maxs_value = 1.0
+        for ax in axs:
+            ax.grid(visible=True, axis='y', linewidth=0.75)
+            ax.set_xticks(self.x_positions,self.spaced_labels)
+            ax.tick_params(axis='x',pad=10)
+            ax.tick_params(axis='y',top=True)
+            ax.set_rlim(0, maxs_value)
+            ax.set_rlabel_position(180)
+            ax.set_rorigin(-0.25)
+            ax.set_theta_zero_location('S')     
+        return fig,axs
+    
+    def create_circular_barplots(self,fig,ax1,ax2):
+        xmins = [self.spaced_x_angles[i]-self.width/2 for i in range(0,2*self.n)]
+        xmaxs = [xmins[i]+self.width for i in range(0,2*self.n)]
+        ax1=self.create_quality_circular_barplot(xmins,xmaxs,ax1)
+        ax2=self.create_IGQR_circular_barplot(xmins,xmaxs,ax2)
+        return ax1,ax2
+    
+    def create_quality_circular_barplot(self,xmins,xmaxs,ax1):
+        ax1.set_title('Quality Measures',pad=20)
+        #Creation of the red dashed threshold line
+        aimed_qualities = [self.quality_threshold for i in range(0,2*self.n)]
+        ax1.hlines(y=aimed_qualities,xmin=xmins,xmax=xmaxs,color='red',linewidth=2,linestyle='--')
+        #Creation of the star plots            
+        ax1.plot(self.x_angles, self.y_0, alpha=0.2, color=self.group_0_colour, linewidth=0.5, linestyle='solid')
+        ax1.fill(self.x_angles, self.y_0, self.group_0_colour, alpha=0.25)
+        ax1.plot(self.x_angles, self.y_1, alpha=0.2, color=self.group_1_colour, linewidth=0.5, linestyle='solid')
+        ax1.fill(self.x_angles, self.y_1, self.group_1_colour, alpha=0.25)
+
+        #Creation of the overlapping bars
+        for i in range(0,self.n):
+            #Encoding of invalid values as red and bold ticks; No bar is created
+            if self.spaced_y_0[2*i]==-1 or self.spaced_y_1[2*i]==-1:
+                ax1.get_xticklabels()[2*i].set_color('red')
+                ax1.get_xticklabels()[2*i].set_fontweight('bold')
+
+            else:
+                #Creation of the overlapping impression by building the smaller bar normally and
+                #stacking the difference of both values on the smaller bar
+                if self.spaced_y_0[2*i]>=self.spaced_y_1[2*i]:
+                    ax1.bar(self.spaced_x_angles[2*i],self.spaced_y_1[2*i],width=self.width,color=self.group_1_colour,edgecolor='black')
+                    ax1.bar(self.spaced_x_angles[2*i],self.spaced_y_0[2*i]-self.spaced_y_1[2*i],bottom=self.spaced_y_1[2*i],width=self.width,color=self.group_0_colour,edgecolor='black')
+                else:
+                    ax1.bar(self.spaced_x_angles[2*i],self.spaced_y_0[2*i],width=self.width,color=self.group_0_colour,edgecolor='black')
+                    ax1.bar(self.spaced_x_angles[2*i],self.spaced_y_1[2*i]-self.spaced_y_0[2*i],bottom=self.spaced_y_0[2*i],width=self.width,color=self.group_1_colour,edgecolor='black')
+        #Legend
+        legend_labels = {self.group_1_colour: self.group_1, self.group_0_colour: self.group_0}
+        legend_handles = [plt.Line2D([0], [0], marker='o', color='w', label=label, markerfacecolor=color, markersize=10)
+                          for color, label in legend_labels.items()]
+        threshold_line_handle = plt.Line2D([0], [0], color='red', lw=2, linestyle='--', label='quality threshold: '+str(self.quality_threshold))
+        legend_handles.append(threshold_line_handle)
+        ax1.legend(handles=legend_handles,loc='upper center',bbox_to_anchor=(.25 + np.cos(np.deg2rad(247.5))/2, .5 + np.sin(np.deg2rad(247.5))/2),frameon=False)        
+        return ax1
+    
+    def create_IGQR_circular_barplot(self,xmins,xmaxs,ax2):
+        ax2.set_title('IGQR Values',pad=20)
+        #Creation of the red dashed threshold line
+        border_IGQRs = [self.IGQR_threshold for i in range(0,2*self.n)] 
+        ax2.hlines(y=border_IGQRs,xmin=xmins,xmax=xmaxs,color='red',linewidth=2,linestyle='--')
+        #Creation of the IGQR bars and the color encoding
+        for i in range(0,self.n):
+            IGQR_impact = self.IGQRs[i]
+            if IGQR_impact>=0.8:
+                ax2.bar(self.spaced_x_angles[2*i],IGQR_impact,width=self.width,color=self.at_least_t_colour,edgecolor='black')
+            else:
+                #Encoding of invalid values as red and bold ticks; No bar is created
+                if IGQR_impact==-1:
+                    ax2.get_xticklabels()[2*i].set_color('red')
+                    ax2.get_xticklabels()[2*i].set_fontweight('bold')
+
+                else:
+                    ax2.bar(self.spaced_x_angles[2*i],IGQR_impact,width=self.width,color=self.lower_t_colour,edgecolor='black')
+        #Legend
+        legend_labels = {self.at_least_t_colour: 'IGQR ≥ '+ str(self.IGQR_threshold), self.lower_t_colour: 'IGQR < '+str(self.IGQR_threshold)}
+        legend_handles = [plt.Line2D([0], [0], marker='o', color='w', label=label, markerfacecolor=color, markersize=10)
+                          for color, label in legend_labels.items()]
+        threshold_line_handle = plt.Line2D([0], [0], color='red', lw=2, linestyle='--', label='IGQR threshold: '+str(self.IGQR_threshold))
+        legend_handles.append(threshold_line_handle)
+        ax2.legend(handles=legend_handles,loc='upper center',bbox_to_anchor=(.25 + np.cos(np.deg2rad(247.5))/2, .5 + np.sin(np.deg2rad(247.5))/2),frameon=False)
+        return ax2
+    
+    def get_table(self):
+        '''
+        Representation of the visualisation data as table plus the general quality measure values
+        '''
+        table = pd.DataFrame(columns=self.labels,index=['total',self.group_1,self.group_0,'IGQR'])
+        table.loc['total']=[round(self.y[j],2) for j in range(self.n)]
+        table.loc[self.group_1]=[round(self.y_1[j],2) for j in range(self.n)]
+        table.loc[self.group_0]=[round(self.y_0[j],2) for j in range(self.n)]
+        table.loc['IGQR']=[round(IGQR_impact,2) for IGQR_impact in self.IGQRs]
+        return table