In [1]:
#Imports
import pandas as pd
import matplotlib.pyplot as plt
from itertools import combinations
import numpy as np
import matplotlib.colors as mcolors
import os
import re
import textwrap
In [2]:
# Excel-Datei einlesen
df = pd.read_excel(r"C:\ .xlsx") #Pfad zu Umfragedaten (Auswertung zu nur KMU/gU mit entsprechedn bereingiter Datei)
df = df.iloc[:, :-1] # Entfernt Interviewfrage
df = df.applymap(lambda x: False if x == '-' else x) # - durch False ersetzen
df = df.applymap(lambda x: True if x == 'true' else x) # true durch True ersetzen
df_roh = df
C:\Users\Marcel\AppData\Local\Temp\ipykernel_15944\2769825339.py:4: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead. df = df.applymap(lambda x: False if x == '-' else x) # - durch False ersetzen C:\Users\Marcel\AppData\Local\Temp\ipykernel_15944\2769825339.py:5: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead. df = df.applymap(lambda x: True if x == 'true' else x) # true durch True ersetzen
In [3]:
#Codierung der Fragen für besseres Handling
#Mapping aus der zweiten Zeile erstellen
F_Codes = df_roh.columns # codierte Spaltennamen
F_Fragen = df_roh.iloc[0] # Langtexte der Fragen
F_mapping = dict(zip(F_Codes, F_Fragen))
# DataFrame bereinigen: nur ab der dritten Zeile, Spalten = Codes
df = df_roh.iloc[1:].copy()
df.columns = F_Codes
df.reset_index(drop=True, inplace=True)
#Func: Rückbenennung
def decode(df, mapping, chop=False):
new_mapping = {}
for col, new_name in mapping.items():
if chop and "=" in new_name:
new_name = new_name.split("=", 1)[0].strip() # Alles nach '=' entfernen
new_mapping[col] = new_name
return df.rename(columns=new_mapping)
# Darstellung mit Langtexten
#df_display = decode(df, F_mapping)
In [110]:
#Farbtöne für Darstellung
colors_TUHH_base = [
"#00C1D4",
"#7200FE",
"#143BFF",
"#5AFFC5",
"#D0D0CE",
"#000000",
"#FF4F4F",
"#FF7E15",
"#FFDE36",
"#FFAEA2",
"#A8968C"
]
colors_TUHH_green_3 = ["#aae5ec", "#5dafb3", "#11797b"]
colors_TUHH_green_4 = ["#A8E6ED", "#5FD3DF", "#5dafb3", "#007A7C"]
colors_TUHH_green_6 = ["#A8E6ED", "#5FD3DF", "#00C1D4", "#00AFC2", "#009E8F", "#008976"]
colors_TUHH_green_7 = ["#A8E6ED", "#5FD3DF", "#00C1D4", "#00AFC2", "#008F9F", "#009E8F", "#008976"]
colors_green_ESG = {"E": "#11797b","S": "#00919f","G": "#00c1d4"}
colors_TUHH_ESG = {"E": "#00C1D4","S": "#FF7E15","G": "#7200FE"}
In [66]:
#Darstellungsqualität
plt.rcParams['figure.dpi'] = 150
#Ordner zum abspeichern
ordner = r"C:\Users\Marcel\plots_Kieserling"
def save_plot(ax, ordner=ordner, dpi=300):
# Titel auslesen
titel = ax.get_title()
if not titel:
titel = "plot"
# Ungültige Zeichen für Dateinamen entfernen
titel_sauber = re.sub(r'[\\/*?:"<>|]', "", titel)
dateiname = titel_sauber.replace(" ", "_") + ".png"
# Ordner erstellen, falls nicht vorhanden
os.makedirs(ordner, exist_ok=True)
# Vollständiger Pfad
pfad = os.path.join(ordner, dateiname)
# Speichern
plt.savefig(pfad, dpi=dpi)
print(f"Diagramm gespeichert unter: {pfad}")
return pfad
In [6]:
### Frageblock 1 Strukturfragen
In [91]:
# Frage 1 - Transportbezug
# Idee: Worte in Diagrammbezeichnungen sollen nach coloermap eingefärbt werden - noch keine Lösung gefunden
# Spalten, die ausgewertet werden sollen
columns_to_analyze = ["A1", "A2", "A3"]
# Mapping für Bezeichnungen
custom_labels = {
("A3",): "Unternehmen ist ein Logistikdienstleister",
("A2",): "Unternehmen führt Transporte für Dritte durch",
("A1",): "Unternehmen führt Transporte selbst durch",
("A1","A2","A3"): "Logistikdienstleister & Dritte & selbst",
("A2","A3"): "Logistikdienstleister & Dritte",
("A1","A2"): "Dritte & selbst",
("A1","A3"): "Logistikdienstleister & selbst",
}
# Alle Kombinationen von 1 bis n Spalten
all_combinations = []
for r in range(1, len(columns_to_analyze)+1):
all_combinations.extend(combinations(columns_to_analyze, r))
# Anzahl der True-Werte pro Kombination
comb_counts = {}
for comb in all_combinations:
other_cols = [c for c in columns_to_analyze if c not in comb]
mask = df[list(comb)].all(axis=1) & (~df[other_cols].any(axis=1))
label = custom_labels.get(comb, "+".join(comb))
comb_counts[label] = mask.sum()
# Horizontale Balken, in der Reihenfolge der custom_labels
series = pd.Series({label: comb_counts[label] for label in custom_labels.values()})
series = series.sort_values(ascending=True)
fig, ax = plt.subplots(figsize=(10, 4))
# Farben exakt in der Reihenfolge der Serie
series.plot(
kind="barh",
color=colors_TUHH_green_7[::-1][:len(series)],
ax=ax,
width=0.8,
edgecolor="black",
linewidth=0.7,
)
ax.tick_params(axis='y', colors='black')
for i, (label, v) in enumerate(series.items()):
offset = 0.9 if v < 10 else 1.3
ax.text(v - offset, i-0.05, str(v), va='center', ha='left', color="black")
ax.set_xticks([0, 5, 10, 15, 20])
plt.xlabel(f'\n"Wie werden Gütertransporte in Ihrem Unternehmen überwiegend behandelt?" (n={df.shape[0]})', fontweight='normal', fontsize=10)
plt.title("Transportbezug", fontweight='bold')
plt.tight_layout()
plt.show()
In [46]:
# Spalten, die ausgewertet werden sollen
columns_to_analyze = ["L1", "L2", "L3", "L4", "L5"]
# Optional: Mapping für eigene Bezeichnungen
custom_labels = {
"L1+L2": "< 50",
"L3": "50 bis 249",
"L4+L5": "> 249",
}
# L1+L2 und L4+L5 zusammenfassen
sums = df[columns_to_analyze].sum()
sums_combined = pd.Series({
"L1+L2": sums["L1"] + sums["L2"],
"L3": sums["L3"],
"L4+L5": sums["L4"] + sums["L5"]
})
n = sums_combined.sum()
# Series mit Labels
series = pd.Series({custom_labels[k]: v for k, v in sums_combined.items()})
# Plot
fig, ax = plt.subplots(figsize=(6, 3.5))
series.plot(kind="bar", color="#00C1D4", ax=ax, width=0.8, edgecolor="black", linewidth=0.7, color=colors_TUHH_green_3)
ax.tick_params(axis='y', colors='black')
for i, v in enumerate(series):
ax.text(i, v + 0.2, str(v), ha='center', va='bottom', fontsize=10, color='black')
ax.set_ylim(0, series.max() * 1.2)
ax.set_xticklabels(ax.get_xticklabels(), rotation=0, ha='center')
plt.xlabel(f'\n "Wie viele Mitarbeitende beschäftigt Ihr Unternehmen?" (n={n})', fontweight='normal', fontsize=10)
plt.title("Größe des Unternehmens", fontweight='bold')
plt.tight_layout()
plt.show()
In [47]:
# Spalten, die ausgewertet werden sollen
columns_to_analyze = ["M1", "M2", "M3", "M4"]
# Optional: Mapping für eigene Bezeichnungen
custom_labels = {
"M1": "≤ 2 Mio. €",
"M2+M3": "2 bis 50 Mio. €",
"M4": "> 50 Mio. €",
}
# L1+L2 und L4+L5 zusammenfassen
sums = df[columns_to_analyze].sum()
sums_combined = pd.Series({
"M1": sums["M1"],
"M2+M3": sums["M2"] + sums["M3"],
"M4": sums["M4"]
})
n = sums_combined.sum()
# Series mit Labels
series = pd.Series({custom_labels[k]: v for k, v in sums_combined.items()})
# Plot
fig, ax = plt.subplots(figsize=(6, 3.5))
series.plot(kind="bar", color=colors_TUHH_green_3, ax=ax, width=0.8, edgecolor="black", linewidth=0.7)
ax.tick_params(axis='y', colors='black')
for i, v in enumerate(series):
ax.text(i, v + 0.2, str(v), ha='center', va='bottom', fontsize=10, color='black')
ax.set_ylim(0, series.max() * 1.2)
ax.set_xticklabels(ax.get_xticklabels(), rotation=0, ha='center')
plt.xlabel(f'\n "Wie hoch ist der Jahresumsatz Ihres Unternehmens?" (n={n})', fontweight='normal', fontsize=10)
plt.title("Umsatzerlös", fontweight='bold')
plt.tight_layout()
plt.show()
In [11]:
# Zählen, wie oft beide Spalten True sind
count = (df['M4'] & (df['L4'] | df['L5'])).sum()
print("Anzahl der Unternehmen welche keine KMU sind (EU-Definition):")
print(count)
Anzahl der Unternehmen welche keine KMU sind (EU-Definition): 17
In [109]:
import pandas as pd
import matplotlib.pyplot as plt
# Spalte, die ausgewertet werden soll
column_to_analyze = "O1"
# Eigene Suchbegriffe und deren Labels für das Diagramm
define_labels = {
"Geschäftsführung": "Geschäfts-\nführung",
"höheres Management": "höheres\nManagement",
"Nachhaltigkeitsmanagement": "Nachhaltigkeits-\nmanagement",
"*": "Facharbeiter/-in",
}
# Zähle die Vorkommen der definierten Namen
counts = {label: df[column_to_analyze].eq(name).sum() for name, label in define_labels.items()}
series = pd.Series(counts)
# Gesamtzahl für Anzeige
n = series.sum()
# Plot
fig, ax = plt.subplots(figsize=(6, 3.5))
series.plot(kind="bar", color=colors_TUHH_green_4, ax=ax, width=0.8, edgecolor="black", linewidth=0.7)
ax.tick_params(axis='y', colors='black')
for i, v in enumerate(series):
ax.text(i, v + 0.2, str(v), ha='center', va='bottom', fontsize=10, color='black')
ax.set_ylim(0, series.max() * 1.2)
ax.set_xticklabels(ax.get_xticklabels(), rotation=0, ha='center')
plt.xlabel(f'\n"Welche Position haben Sie innerhalb Ihres Unternehmens?" (n={n})', fontweight='normal', fontsize=10)
plt.title("Position im Unternehmen", fontweight='bold')
plt.tight_layout()
plt.show()
In [88]:
# Spalten, die ausgewertet werden sollen
columns_to_analyze = ["N1", "N2", "N3", "N4", "N5", "N6"]
ID_ignore=[74,64,58,30,15,14]
# Optional: Mapping für eigene Bezeichnungen
custom_labels = {
"N1": "Rohrleitungen",
"N2": "Luft",
"N3": "See",
"N4": "Straße",
"N5": "Schiene",
"N6": "Binnen-\nwasserstraßen",
}
df_filtered = df[~df["ID"].isin(ID_ignore)].copy()
df_filtered[columns_to_analyze] = df_filtered[columns_to_analyze].apply(pd.to_numeric, errors='coerce')
sums = df_filtered[columns_to_analyze].sum()
n = sums.sum()
share = sums / n
# Series mit Labels
series = pd.Series({custom_labels[k]: v for k, v in share.items()})
series = series.sort_values(ascending=False)
# Plot
fig, ax = plt.subplots(figsize=(6, 3.5))
series.plot(kind="bar", color=colors_TUHH_green_6, ax=ax, width=0.8, edgecolor="black", linewidth=0.7)
ax.tick_params(axis='y', colors='black')
# Feste Y-Ticks 10% bis 60%
yticks = [i/100 for i in range(10, 70, 10)] # 0.1, 0.2, ..., 0.6
ax.set_yticks(yticks)
ax.set_yticklabels([f"{int(i*100)}%" for i in yticks])
for i, v in enumerate(series):
ax.text(i, v + 0.01, f"{v:.0%}", ha='center', va='bottom', fontsize=10)
ax.set_ylim(0, series.max() * 1.2)
ax.set_xticklabels(ax.get_xticklabels(), rotation=0, ha='center')
plt.ylabel("Anteil Stichprobe")
plt.xlabel(f'\n "Wie hoch ist der Anteil der jeweiligen Verkehrsträger \nam Gütertransport Ihres Unternehmens?" (n={int(n / 100)})\n', fontsize=10)
plt.title("Anteil der Verkehrsträger am Gütertransport der Unternehmen", fontweight='bold')
plt.tight_layout()
plt.show()
In [92]:
# Spalten, die ausgewertet werden sollen
columns_to_analyze = ["N1", "N2", "N3", "N4", "N5", "N6"]
ID_ignore = []
#ID_ignore = [74, 64, 58, 30, 15, 14] # auch welche die nicht auf 100% summiert sind können hier beachtet werden
# Optional: Mapping für eigene Bezeichnungen
custom_labels = {
"N1": "Rohrleitungen",
"N2": "Luft",
"N3": "See",
"N4": "Straße",
"N5": "Schiene",
"N6": "Binnen-\nwasserstraßen",
}
# Filterung der IDs
df_filtered = df[~df["ID"].isin(ID_ignore)].copy()
df_filtered[columns_to_analyze] = df_filtered[columns_to_analyze].apply(pd.to_numeric, errors='coerce')
# Funktion, um die dominanten Verkehrsträger pro Zeile zu bestimmen
def dominant_transport(row):
if row.isnull().all() or row.sum() == 0:
return None
max_val = row.max()
max_cols = row[row == max_val].index.tolist()
if len(max_cols) > 1:
return "mehrere\n gleichbeteiligt"
else:
return custom_labels[max_cols[0]]
# Neue Spalte mit dem dominanten Verkehrsträger
df_filtered["dominant"] = df_filtered[columns_to_analyze].apply(dominant_transport, axis=1)
# Zeilen ohne dominante Verkehrsträger entfernen
df_filtered = df_filtered.dropna(subset=["dominant"])
# Zählen der Kategorien
counts = df_filtered["dominant"].value_counts()
total = counts.sum() # n = Anzahl der Unternehmen mit Daten
# Plot absolute Zahlen
fig, ax = plt.subplots(figsize=(6, 3.5))
counts.plot(kind="bar", color=colors_TUHH_green_6, ax=ax, width=0.8, edgecolor="black", linewidth=0.7)
ax.tick_params(axis='y', colors='black')
for i, v in enumerate(counts):
ax.text(i, v + 0.3, f"{v}", ha='center', va='bottom', fontsize=10)
ax.set_ylim(0, counts.max() * 1.2)
ax.set_xticklabels(ax.get_xticklabels(), rotation=0, ha='center')
plt.ylabel("Anzahl der Unternehmen")
plt.xlabel(f'\n "Wie hoch ist der Anteil der jeweiligen Verkehrsträger \nam Gütertransport Ihres Unternehmens?" (n={total})', fontsize=10)
plt.title("Überwiegend für den Gütertransport\ngenutzter Verkehrsträger", fontweight='bold')
plt.tight_layout()
plt.show()
In [15]:
### Frageblock 2 Nachhaltigkeitsstellenwert ###
In [16]:
# Spalten, die ausgewertet werden sollen
columns_to_analyze = ["B1", "B2", "B3", "B4"]
# Optional: Mapping für eigene Bezeichnungen
custom_labels = {
"B1": "sehr hoch",
"B2": "eher hoch",
"B3": "eher gering",
"B4": "sehr gering",
}
sums = df[columns_to_analyze].sum()
series = pd.Series({custom_labels[col]: sums[col] for col in columns_to_analyze})
fig, ax = plt.subplots(figsize=(6, 3.5))
colors = ["#aae5ec", "#5dafb3", "#11797b", "#C00000"]
# Balken zeichnen
series.plot(
kind="bar",
color=colors,
ax=ax,
width=0.8,
edgecolor="black",
linewidth=0.7,
)
for i, v in enumerate(series):
ax.text(i, v + 0.2, str(v), ha='center', va='bottom', fontsize=10, color='black')
ax.set_ylim(0, series.max() * 1.2)
ax.tick_params(axis='y', colors='black')
plt.xlabel(f"\nAnzahl der Nennungen (n={series.sum()})", fontweight='normal', fontsize=10)
ax.set_xticklabels(ax.get_xticklabels(), rotation=0, ha='center')
ax.set_title("Welchen Stellenwert hat das Thema Nachhaltigkeit in Ihrem Unternehmen?", fontweight='bold')
plt.tight_layout()
plt.show()
In [17]:
# Spalten, die ausgewertet werden sollen
columns_to_analyze = ["B1", "B2", "B3", "B4"]
# Optional: Mapping für eigene Bezeichnungen
custom_labels = {
"B1": "sehr hoch",
"B2": "eher hoch",
"B3": "eher gering",
"B4": "sehr gering",
}
sums = df[columns_to_analyze].sum()
total = sums.sum() # Gesamtanzahl für Prozentberechnung
# Prozentwerte berechnen
percent_series = pd.Series({custom_labels[col]: (sums[col] / total) * 100 for col in columns_to_analyze})
fig, ax = plt.subplots(figsize=(6, 3.5))
colors = ["#aae5ec", "#5dafb3", "#11797b", "#C00000"]
# Balken zeichnen
percent_series.plot(
kind="bar",
color=colors,
ax=ax,
width=0.8,
edgecolor="black",
linewidth=0.7,
)
ax.yaxis.set_major_formatter(plt.FuncFormatter(lambda y, _: f'{y:.0f}%'))
# Prozentwerte auf den Balken anzeigen
for i, v in enumerate(percent_series):
ax.text(i, v + 0.5, f"{v:.0f}%", ha='center', va='bottom', fontsize=10, color='black')
ax.set_ylim(0, percent_series.max() * 1.2)
ax.tick_params(axis='y', colors='black')
plt.xlabel(f'\n"Welchen Stellenwert hat das Thema Nachhaltigkeit in Ihrem Unternehmen? (n={total})"', fontweight='normal', fontsize=8)
ax.set_xticklabels(ax.get_xticklabels(), rotation=0, ha='center')
ax.set_title("Stellenwert der Nachhaltigkeit im Unternehmen\n", fontweight='bold')
plt.tight_layout()
plt.show()
In [107]:
# NH-Aspekt auf Platz 1
# Spalten, die ausgewertet werden sollen
columns_to_analyze = ["C1", "C2", "C3"]
colors_TUHH_green_3_sp = colors_TUHH_green_3 #["#aae5ec", "#00C1D4", "#007A7C"]
custom_labels = {
"C1": "Langfristiger \nUnternehmenserfolg",
"C2": "Schutz \nder Umwelt",
"C3": "Verantwortung \nfür Mitarbeitende",
}
# Platz 1 zählen, NaNs ignorieren
counts = {col: df[col].eq("1").sum() for col in columns_to_analyze}
# Anzahl gültiger Werte pro Spalte
valid_counts = {col: df[col].notna().sum() for col in columns_to_analyze}
n=int(sum(valid_counts.values())/3)
# Prozentuale Anteile berechnen, NaNs vermeiden
percent_series = pd.Series({custom_labels[col]: (counts[col] / valid_counts[col] * 100 if valid_counts[col] > 0 else 0)
for col in columns_to_analyze})
# Balkendiagramm
fig, ax = plt.subplots(figsize=(6, 3.5))
colors = "#00C1D4"
percent_series.plot(
kind="bar",
color=colors_TUHH_green_3_sp,
ax=ax,
width=0.8,
edgecolor="black",
linewidth=0.7,
)
ax.yaxis.set_major_formatter(plt.FuncFormatter(lambda y, _: f'{y:.0f}%'))
for i, v in enumerate(percent_series):
ax.text(i, v + 1, f"{v:.0f}%", ha='center', va='bottom', fontsize=10, color='black')
# Achsenlimits nur setzen, wenn es gültige Werte gibt
if not percent_series.empty and percent_series.max() > 0:
ax.set_ylim(0, percent_series.max() * 1.2)
else:
ax.set_ylim(0, 1)
ax.tick_params(axis='y', colors='black')
plt.xlabel(f'\n"Ordnen Sie durch Anklicken die folgenden drei Ansatzpunkte \neiner Nachhaltigkeitsstrategie nach deren Stellenwert für Ihr Unternehmen." \n(n={n})', fontweight='normal', fontsize=10)
ax.set_xticklabels(ax.get_xticklabels(), rotation=0, ha='center')
ax.set_title('Dimension der "Nachhaltigkeit" mit \ndem höchsten Stellenwert für die Unternehmen', fontweight='bold')
plt.tight_layout()
plt.show()
In [19]:
# wie oft waren Soz >/< Öko
# Spalten, die verglichen werden sollen
columns_to_analyze = ["C2", "C3"]
custom_labels = {
"C2": "Schutz \nder Umwelt",
"C3": "Verantwortung \nfür Mitarbeitende",
}
# Nur gültige Zeilen betrachten (beide Werte vorhanden)
subset = df[columns_to_analyze].dropna()
# Zählen, wie oft C2 besser (kleinerer Rang), C3 besser oder gleich
better_c2 = (subset["C2"] < subset["C3"]).sum()
better_c3 = (subset["C3"] < subset["C2"]).sum()
# Ergebnisse als Series
comparison = pd.Series({
custom_labels["C2"]: better_c2,
custom_labels["C3"]: better_c3,
})
# Gesamtanzahl gültiger Vergleiche
n = len(subset)
# Kuchendiagramm
fig, ax = plt.subplots(figsize=(5, 5))
colors = ["#00C1D4", "#007A7C"]
comparison.plot(
kind="pie",
autopct='%1.1f%%',
startangle=90,
colors=colors,
ax=ax,
legend=False,
labels=comparison.index
)
ax.set_ylabel("")
ax.set_title('Welche der beiden Dimension\n ist für die Unternhemen wichtiger?', fontweight='bold')
plt.xlabel(f'\nWie oft wurde die jeweilige Dimension höher eingeordnet\n(n={n})', fontweight='normal', fontsize=10)
#plt.figtext(0.5, 0.15, f'"WSDSD" (n={n})', ha='center', fontsize=10)
plt.tight_layout()
plt.show()
In [20]:
# Beispielhafte Spalten
columns_to_analyze = ["D1", "D2", "D3", "D4"]
# Optional: Mapping für eigene Bezeichnungen
custom_labels = {
"D1": "Organisation",
"D2": "Umfeld",
"D3": "Mensch",
"D4": "Technik",
}
ID_ignore=[123,117,94,70,58,14] #Haben nicht 100 Punkte verteilt
df_filtered = df[~df["ID"].isin(ID_ignore)].copy()
df_filtered[columns_to_analyze] = df_filtered[columns_to_analyze].apply(pd.to_numeric, errors='coerce')
# Summe je Spalte
sums = df_filtered[columns_to_analyze].apply(pd.to_numeric, errors='coerce').sum()
n = sums.sum()
share = sums / n
n=int(n/100)
# Series mit Labels
series = pd.Series({custom_labels[k]: v for k, v in share.items()})
# Sortieren von groß nach klein
series = series.sort_values(ascending=True)
# Farben für die vier Segmente
colors = ["#A8E6ED", "#5FD3DF", "#00C1D4", "#007A7C"]
# Kuchendiagramm
fig, ax = plt.subplots(figsize=(5, 5))
series.plot(
kind="pie",
autopct='%1.0f%%',
startangle=90,
colors=colors,
ax=ax,
legend=False,
labels=series.index
)
ax.set_ylabel("")
ax.set_title('Verteilung der Nachhaltigkeitsinvestitionen', fontweight='bold')
plt.xlabel(f'\n"Wie verteilen sich die Investitionen in Nachhaltigkeitsmaßnahmen \nIhres Unternehmens über die folgenden Handlungsfelder?" \n(Schätzwert in Prozent)? " (n={n})', fontweight='normal', fontsize=8)
plt.tight_layout()
plt.show()
In [21]:
'''
# Maßnahmenverteilung
data = {
"umgegesetzt": [0.66, 0.17, 0.17, 0.41, 0.07, 0.03, 0.07, 0.07, 0.17, None, 0.17],
"Geplant": [0.61, 0.17, 0.22, 0.46, 0.05, 0.05, 0.05, None, 0.15, 0.02, 0.22]
}
# Index / Zeilenbezeichnungen
index = [
"E", "S", "G",
"E1 – Klimawandel",
"E2 – Verschmutzung",
"E3 – Wasser- & Meeresressourcen",
"E4 – Biodiversität & Ökosysteme",
"E5 – Ressourcennutzung & Kreislaufwirtschaft",
"S1 – Eigene Belegschaft",
"S2 – Beschäftigte in der Wertschöpfungskette",
"G1 – Unternehmensführung & Compliance"
]
df_Massnahmen = pd.DataFrame(data, index=index)
'''
Out[21]:
' \n# Maßnahmenverteilung\ndata = {\n "umgegesetzt": [0.66, 0.17, 0.17, 0.41, 0.07, 0.03, 0.07, 0.07, 0.17, None, 0.17],\n "Geplant": [0.61, 0.17, 0.22, 0.46, 0.05, 0.05, 0.05, None, 0.15, 0.02, 0.22]\n}\n\n# Index / Zeilenbezeichnungen\nindex = [\n "E", "S", "G",\n "E1 – Klimawandel",\n "E2 – Verschmutzung",\n "E3 – Wasser- & Meeresressourcen",\n "E4 – Biodiversität & Ökosysteme",\n "E5 – Ressourcennutzung & Kreislaufwirtschaft",\n "S1 – Eigene Belegschaft",\n "S2 – Beschäftigte in der Wertschöpfungskette",\n "G1 – Unternehmensführung & Compliance"\n]\n\ndf_Massnahmen = pd.DataFrame(data, index=index)\n'
In [122]:
# Maßnahmenverteilung # Zahlen aus exceldatei zur Maßnahmenclusterung
data = {
"umgegesetzt": [0.70, 0.13, 0.17 ],#, 0.41, 0.07, 0.03, 0.07, 0.07, 0.17, None, 0.17],
"Geplant": [0.80, 0.06, 0.14] #, 0.46, 0.05, 0.05, 0.05, None, 0.15, 0.02, 0.22]
}
# Index / Zeilenbezeichnungen
index = [
"E", "S", "G",
#"E1 – Klimawandel",
#"E2 – Verschmutzung",
#"E3 – Wasser- & Meeresressourcen",
#"E4 – Biodiversität & Ökosysteme",
#"E5 – Ressourcennutzung & Kreislaufwirtschaft",
#"S1 – Eigene Belegschaft",
#"S2 – Beschäftigte in der Wertschöpfungskette",
#"S3 - Betroffene Gemeinschaften",
#"S4 - Verbraucher und Endnutzer",
#"G1 – Unternehmensführung & Compliance"
]
df_Massnahmen = pd.DataFrame(data, index=index)
In [128]:
# Optional: fehlende Werte auf 0 setzen
df_filled = df_Massnahmen.fillna(0)
# Reihenfolge ESG fix
categories = ["E", "S", "G"]
# Hauptkategorien auswählen in fester Reihenfolge
df_main = df_filled.loc[categories]
# Farben von dunkel nach hell
colors = ["#11797b","#00919f", "#00c1d4"]
# Zwei nebeneinander liegende Tortendiagramme
fig, axes = plt.subplots(1, 2, figsize=(12, 6))
# Umgesetzt
axes[0].pie(
df_main["umgegesetzt"],
labels=df_main.index,
autopct='%1.0f%%',
colors=colors,
startangle=90,
textprops={'fontsize': 18, 'fontweight': 'light'}
)
axes[0].pie(
df_main["umgegesetzt"],
labels=df_main.index,
autopct='%1.0f%%',
colors=colors,
startangle=90,
textprops={
'fontsize': 18,
'fontweight': 'light',
'color': 'black'
}
)
# Geplant
axes[1].pie(
df_main["Geplant"],
labels=df_main.index,
autopct='%1.0f%%',
colors=colors,
startangle=90,
textprops={'fontsize': 18, 'fontweight': 'light', 'color': 'black'}
)
axes[1].set_title("Geplant", fontsize=14, fontweight='light')
# Gesamtbeschriftung unter den Diagrammen mit Anführungszeichen
fig.text(0.5, -0.05,
'"Welche wichtigen Nachhaltigkeitsmaßnahmen haben Sie bereits umgesetzt / geplant?" (n=28 / 17)',
ha='center', fontsize=12)
# Beschriftung oben
fig.text(0.5, 1.05,
"Verteilung der Maßnahmen über die ESG-Dimensionen",
ha='center', fontsize=14, fontweight='bold')
plt.tight_layout()
ax.set_title("erteilung der Maßnahmen über die ESG-Dimensionen")
save_plot(ax)
plt.show()
Diagramm gespeichert unter: C:\Users\Marcel\plots_Kieserling\erteilung_der_Maßnahmen_über_die_ESG-Dimensionen.png
In [24]:
#### Ranglisten ###
In [25]:
# --- Nachhaltigkeitsthemen ---
### Was soll ausgeweret werden? ###
# --- Spalten & Labels ---
columns_to_analyze = ["E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8"]
custom_labels = {
"E1": "Abfallaufkommen und -bewirtschaftung",
"E2": "Beitrag zum Klimaschutz",
"E3": "Arbeitsbedingungen\nin der eigenen Belegschaft",
"E4": "Gleichbehandlung und Chancengleichheit\nin der eigenen Belegschaft",
"E5": "Energieverbrauch und -quellen",
"E6": "Nachhaltige Unternehmenskultur\nund Führungsverhalten",
"E7": "Korruptions- und Bestechungsbekämpfung",
"E8": "Anpassung an Auswirkungen\ndes Klimawandels",
}
### Ab hier für alle Orderrank-Fragen gleich ####
# --- Daten vorbereiten ---
df_filtered = df[["ID"] + columns_to_analyze].apply(pd.to_numeric, errors="coerce")
df_filtered = df_filtered[df_filtered[columns_to_analyze].notna().any(axis=1)]
df_filtered = df_filtered.set_index("ID")
# --- Funktion: Dowdall-Gewichte pro Zeile berechnen ---
def dowdall_weights_for_row(row):
return row.map(lambda r: 1/int(r) if not pd.isna(r) else 0)
df_strength_dowdall = df_filtered.apply(dowdall_weights_for_row, axis=1)
# --- Rangstärke pro Kategorie: Summe der Dowdall-Werte geteilt durch Summe der Maximalwerte ---
mean_strength_norm = df_strength_dowdall.sum() / df_filtered.shape[0]
values_list = [mean_strength_norm[col] for col in columns_to_analyze]
# --- Häufigkeiten der Nennungen ---
mention_counts = df_filtered.notna().sum()
# --- Sortieren nach Rangstärke absteigend ---
sorted_indices = np.argsort(values_list)[::-1]
sorted_values = [values_list[i] for i in sorted_indices]
sorted_columns = [columns_to_analyze[i] for i in sorted_indices]
sorted_labels = [
f"{custom_labels[col]}\n(n={int(mention_counts[col])})" for col in sorted_columns
]
# --- Häufigkeiten der Ränge zählen ---
n_col = len(columns_to_analyze)
rank_counts = {rank: [] for rank in range(1, n_col + 1)}
for col in sorted_columns:
counts = df_filtered[col].value_counts().reindex(range(1, n_col + 1), fill_value=0)
total = counts.sum()
for rank in range(1, n_col + 1):
rank_counts[rank].append(counts[rank] / total)
# --- Farbpalette ---
colors = [mcolors.to_hex(c) for c in mcolors.LinearSegmentedColormap.from_list(
"custom_cmap", ["#aae5ec", "#11797B"])(np.linspace(0, 1, n_col))]
# --- Listen invertieren für Plot (bester Wert oben) ---
sorted_labels_rev = sorted_labels[::-1]
sorted_values_rev = sorted_values[::-1]
rank_counts_rev = {rank: rank_counts[rank][::-1] for rank in rank_counts}
# --- Plot ---
fig, ax = plt.subplots(figsize=(11, 6))
# --- Leichte Hilfslinien bei 10%-Schritten (hinter den Balken) ---
for x in np.arange(0.1, 1.0, 0.1):
ax.axvline(x, color="gray", linestyle="--", linewidth=0.5, alpha=0.5, zorder=0)
bottom = np.zeros(len(sorted_labels_rev))
label_text = [f'Rang {rank}' for rank in range(1, n_col + 1)]
for i, rank in enumerate(range(1, n_col + 1)):
values = np.array(rank_counts_rev[rank])
bars = ax.barh(
sorted_labels_rev,
values,
left=bottom,
color=colors[i],
edgecolor="black",
label=label_text[i],
zorder=1 # Balken über Hilfslinien
)
# Rangzahl in der Mitte der Balken einfügen, falls breit genug
for bar, val in zip(bars, values):
if val >= 0.03: # nur anzeigen, wenn >5% der Achse
ax.text(
bar.get_x() + bar.get_width()/2,
bar.get_y() + bar.get_height()/2,
str(rank),
ha="center", va="center",
color="gray", alpha=0.75, fontsize=10, fontweight="bold"
)
bottom += values
# --- Prozentwerte rechts ---
for i, v in enumerate(sorted_values_rev):
ax.text(
1.03, i, f"{round(v * 100)}%",
va="center", ha="left", fontsize=12, fontweight="bold"
)
# --- Achsen & Layout ---
ax.set_xlabel(
f'\n"Von welcher Stakeholdergruppe geht der stärkste Impuls für nachhaltiges Handeln Ihres Unternehmens aus?" (n={df_filtered.shape[0]}) ',
fontsize=10
)
ax.set_xlim(0, 1.0)
ax.set_xticks(np.arange(0, 1.01, 0.2)) # alle 0.2 = 20%
ax.set_xticklabels([f"{int(x*100)}%" for x in np.arange(0, 1.01, 0.2)])
ax.set_title("Priorisierung ausgewählter Nachhaltigkeitsthemen", fontweight="bold")
# --- Legende rechts ---
ax.legend(title="", bbox_to_anchor=(1.15, 1), loc="upper left")
plt.tight_layout()
# --- Zusatz: "Rangstärke"-Box ---
x_anchor = 0.955
y_anchor = -0.6
ax.text(
x_anchor + 0.09, y_anchor, "⬆️ Rangstärke",
va="center", ha="left",
fontsize=11, fontweight="bold",
bbox=dict(boxstyle="round,pad=0.3", fc="white", ec="black", lw=1)
)
save_plot(ax)
plt.show()
Diagramm gespeichert unter: C:\Users\Marcel\plots_Kieserling\Priorisierung_ausgewählter_Nachhaltigkeitsthemen.png
In [26]:
# --- Impulsgeber ---
### Was soll ausgeweret werden? ###
columns_to_analyze = ["I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9"]
custom_labels = {
"I2": "Andere\n(v.a. Steuergremien)",
"I3": "Mitarbeiter(innen)",
"I4": "Zivilgesellschaft",
"I5": "Geschäftsführung",
"I6": "Mitbewerber",
"I7": "Gesetzgeber",
"I8": "Kunde",
"I9": "Verlader",
}
### Ab hier für alle Orderrank-Fragen gleich ####
# --- Daten vorbereiten ---
df_filtered = df[["ID"] + columns_to_analyze].apply(pd.to_numeric, errors="coerce")
df_filtered = df_filtered[df_filtered[columns_to_analyze].notna().any(axis=1)]
df_filtered = df_filtered.set_index("ID")
# --- Funktion: Dowdall-Gewichte pro Zeile berechnen ---
def dowdall_weights_for_row(row):
return row.map(lambda r: 1/int(r) if not pd.isna(r) else 0)
df_strength_dowdall = df_filtered.apply(dowdall_weights_for_row, axis=1)
# --- Rangstärke pro Kategorie: Summe der Dowdall-Werte geteilt durch Summe der Maximalwerte ---
mean_strength_norm = df_strength_dowdall.sum() / df_filtered.shape[0]
values_list = [mean_strength_norm[col] for col in columns_to_analyze]
# --- Häufigkeiten der Nennungen ---
mention_counts = df_filtered.notna().sum()
# --- Sortieren nach Rangstärke absteigend ---
sorted_indices = np.argsort(values_list)[::-1]
sorted_values = [values_list[i] for i in sorted_indices]
sorted_columns = [columns_to_analyze[i] for i in sorted_indices]
sorted_labels = [
f"{custom_labels[col]}\n(n={int(mention_counts[col])})" for col in sorted_columns
]
# --- Häufigkeiten der Ränge zählen ---
n_col = len(columns_to_analyze)
rank_counts = {rank: [] for rank in range(1, n_col + 1)}
for col in sorted_columns:
counts = df_filtered[col].value_counts().reindex(range(1, n_col + 1), fill_value=0)
total = counts.sum()
for rank in range(1, n_col + 1):
rank_counts[rank].append(counts[rank] / total)
# --- Farbpalette ---
colors = [mcolors.to_hex(c) for c in mcolors.LinearSegmentedColormap.from_list(
"custom_cmap", ["#aae5ec", "#11797B"])(np.linspace(0, 1, n_col))]
# --- Listen invertieren für Plot (bester Wert oben) ---
sorted_labels_rev = sorted_labels[::-1]
sorted_values_rev = sorted_values[::-1]
rank_counts_rev = {rank: rank_counts[rank][::-1] for rank in rank_counts}
# --- Plot ---
fig, ax = plt.subplots(figsize=(10, 6))
# --- Leichte Hilfslinien bei 10%-Schritten (hinter den Balken) ---
for x in np.arange(0.1, 1.0, 0.1):
ax.axvline(x, color="gray", linestyle="--", linewidth=0.5, alpha=0.5, zorder=0)
bottom = np.zeros(len(sorted_labels_rev))
label_text = [f'Rang {rank}' for rank in range(1, n_col + 1)]
for i, rank in enumerate(range(1, n_col + 1)):
values = np.array(rank_counts_rev[rank])
bars = ax.barh(
sorted_labels_rev,
values,
left=bottom,
color=colors[i],
edgecolor="black",
label=label_text[i],
zorder=1 # Balken über Hilfslinien
)
# Rangzahl in der Mitte der Balken einfügen, falls breit genug
for bar, val in zip(bars, values):
if val >= 0.03: # nur anzeigen, wenn >5% der Achse
ax.text(
bar.get_x() + bar.get_width()/2,
bar.get_y() + bar.get_height()/2,
str(rank),
ha="center", va="center",
color="gray", alpha=0.75, fontsize=10, fontweight="bold"
)
bottom += values
# --- Prozentwerte rechts ---
for i, v in enumerate(sorted_values_rev):
ax.text(
1.03, i, f"{round(v * 100)}%",
va="center", ha="left", fontsize=12, fontweight="bold"
)
# --- Achsen & Layout ---
ax.set_xlabel(
f'\n"Von welcher Stakeholdergruppe geht der stärkste Impuls für nachhaltiges Handeln Ihres Unternehmens aus?" (n={df_filtered.shape[0]})',
fontsize=10
)
ax.set_xlim(0, 1.0)
ax.set_xticks(np.arange(0, 1.01, 0.2)) # alle 0.2 = 20%
ax.set_xticklabels([f"{int(x*100)}%" for x in np.arange(0, 1.01, 0.2)])
ax.set_title("Platzierungen der Impulsgeber für Nachhaltigkeitsthemen ", fontweight="bold")
# --- Legende rechts ---
ax.legend(title="", bbox_to_anchor=(1.15, 1), loc="upper left")
plt.tight_layout()
# --- Zusatz: "Rangstärke"-Box ---
x_anchor = 0.955
y_anchor = -0.6
ax.text(
x_anchor + 0.09, y_anchor, "⬆️ Rangstärke",
va="center", ha="left",
fontsize=11, fontweight="bold",
bbox=dict(boxstyle="round,pad=0.3", fc="white", ec="black", lw=1)
)
save_plot(ax)
plt.show()
Diagramm gespeichert unter: C:\Users\Marcel\plots_Kieserling\Platzierungen_der_Impulsgeber_für_Nachhaltigkeitsthemen_.png
In [27]:
# --- Impulsgeber ---
columns_to_analyze = ["I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9"]
custom_labels = {
"I2": "Andere\n(v.a. Steuerungsgremien)",
"I3": "Mitarbeiter(innen)",
"I4": "Zivilgesellschaft",
"I5": "Geschäftsführung",
"I6": "Mitbewerber",
"I7": "Gesetzgeber",
"I8": "Kunde",
"I9": "Verlader",
}
# --- Daten vorbereiten ---
df_filtered = df[["ID"] + columns_to_analyze].apply(pd.to_numeric, errors="coerce")
df_filtered = df_filtered[df_filtered[columns_to_analyze].notna().any(axis=1)]
df_filtered = df_filtered.set_index("ID")
n_respondents = df_filtered.shape[0]
# --- Funktion: Dowdall-Gewichte pro Zeile berechnen ---
def dowdall_weights_for_row(row):
return row.map(lambda r: 1/int(r) if not pd.isna(r) else 0)
df_strength_dowdall = df_filtered.apply(dowdall_weights_for_row, axis=1)
# --- Rangstärke pro Kategorie: Summe der Dowdall-Werte geteilt durch Gesamtzahl Respondents ---
mean_strength_norm = df_strength_dowdall.sum() / n_respondents
values_list = [mean_strength_norm[col] for col in columns_to_analyze]
# --- Häufigkeiten der Nennungen ---
mention_counts = df_filtered.notna().sum()
# --- Sortieren nach Rangstärke absteigend ---
sorted_indices = np.argsort(values_list)[::-1]
sorted_values = [values_list[i] for i in sorted_indices]
sorted_columns = [columns_to_analyze[i] for i in sorted_indices]
sorted_labels = [
f"{custom_labels[col]}\n(n={int(mention_counts[col])})" for col in sorted_columns
]
# --- Häufigkeiten der Ränge zählen (relativ zu allen Respondents) ---
n_col = len(columns_to_analyze)
rank_counts = {rank: [] for rank in range(1, n_col + 1)}
no_rank_counts = []
for col in sorted_columns:
counts = df_filtered[col].value_counts().reindex(range(1, n_col + 1), fill_value=0)
for rank in range(1, n_col + 1):
rank_counts[rank].append(counts[rank] / n_respondents)
no_rank_counts.append(df_filtered[col].isna().sum() / n_respondents)
# --- Farbpalette ---
colors = [mcolors.to_hex(c) for c in mcolors.LinearSegmentedColormap.from_list(
"custom_cmap", ["#aae5ec", "#11797B"])(np.linspace(0, 1, n_col))]
# --- Listen invertieren für Plot (bester Wert oben) ---
sorted_labels_rev = sorted_labels[::-1]
rank_counts_rev = {rank: rank_counts[rank][::-1] for rank in rank_counts}
no_rank_counts_rev = no_rank_counts[::-1]
sorted_values_rev = sorted_values[::-1]
# --- Plot ---
fig, ax = plt.subplots(figsize=(10, 6))
# Leichte Hilfslinien bei 10%-Schritten
for x in np.arange(0.1, 1.0, 0.1):
ax.axvline(x, color="gray", linestyle="--", linewidth=0.5, alpha=0.5, zorder=0)
# --- Gestapelte Ränge 1..n ---
bottom = np.zeros(len(sorted_labels_rev))
label_text = [f'Rang {rank}' for rank in range(1, n_col + 1)]
for i, rank in enumerate(range(1, n_col + 1)):
values = np.array(rank_counts_rev[rank])
bars = ax.barh(
sorted_labels_rev,
values,
left=bottom,
color=colors[i],
edgecolor="black",
label=label_text[i],
zorder=1
)
# Rangnummern einfügen
for bar, val in zip(bars, values):
if val >= 0.03:
ax.text(
bar.get_x() + bar.get_width()/2,
bar.get_y() + bar.get_height()/2,
str(rank),
ha="center", va="center",
color="gray", alpha=0.75, fontsize=10, fontweight="bold"
)
bottom += values
# --- "kein Rang"-Balken rechts neben gestapelten Rängen ---
for i, val in enumerate(no_rank_counts_rev):
ax.barh(
sorted_labels_rev[i],
val,
left=bottom[i],
color="lightgray",
edgecolor="black",
label="kein Rang" if i == 0 else "",
zorder=1
)
# --- Prozentwerte rechts (Rangstärke) ---
for i, v in enumerate(sorted_values_rev):
ax.text(
1.03, i, f"{round(v * 100)}%",
va="center", ha="left", fontsize=12, fontweight="bold"
)
# --- Achsen & Layout ---
ax.set_xlabel(
f'\n"Von welcher Stakeholdergruppe geht der stärkste Impuls für nachhaltiges Handeln Ihres Unternehmens aus?" (n={n_respondents})',
fontsize=10
)
ax.set_xlim(0, 1.0)
ax.set_xticks(np.arange(0, 1.01, 0.2))
ax.set_xticklabels([f"{int(x*100)}%" for x in np.arange(0, 1.01, 0.2)])
ax.set_title("Rangreihenfolge der Impulsgeber für Nachhaltigkeitsthemen", fontweight="bold")
# --- Legende rechts ---
ax.legend(title="", bbox_to_anchor=(1.15, 1), loc="upper left")
plt.tight_layout()
# --- Zusatz: "Rangstärke"-Box ---
x_anchor = 0.955
y_anchor = -0.6
ax.text(
x_anchor + 0.09, y_anchor, "⬆️ Rangstärke",
va="center", ha="left",
fontsize=11, fontweight="bold",
bbox=dict(boxstyle="round,pad=0.3", fc="white", ec="black", lw=1)
)
save_plot(ax)
plt.show()
Diagramm gespeichert unter: C:\Users\Marcel\plots_Kieserling\Rangreihenfolge_der_Impulsgeber_für_Nachhaltigkeitsthemen.png
In [28]:
# --- Herausforderungen ---
columns_to_analyze = ["J1", "J2", "J3", "J4", "J5", "J6", "J7", "J8", "J10", "J11", "J12"] #ohne J1 (Andere) und J9 (alle umgesetzt)
custom_labels = {
"J1": "Andere",
"J2": "Begrenzte finanzielle Mittel",
"J3": "Mangel an Know-how",
"J4": "Fehlende personelle Ressourcen",
"J5": "Unklare/unsichere gesetzliche Lage",
"J6": "Konflikte mit anderen Unternehmenszielen",
"J7": "Technische Lösungen fehlen/noch nicht ausgereift",
"J8": "Mangel an Daten bzw. Datenerhebungsmethoden",
"J9": "Es werden bereits alle Ziele/Maßnahmen umgesetzt",
"J10": "Umsetzung findet maßgeblich durch Externe statt",
"J11": "Kein Bedarf am Markt",
"J12": "Interpretation von Anforderungen",
}
# --- Daten vorbereiten ---
df_filtered = df[["ID"] + columns_to_analyze].apply(pd.to_numeric, errors="coerce")
df_filtered = df_filtered[df_filtered[columns_to_analyze].notna().any(axis=1)]
df_filtered = df_filtered.set_index("ID")
n_respondents = df_filtered.shape[0]
# --- Ränge begrenzen --- # da ggf. höher bewertet wurde als nach dem Entfernen von Spalten übrig bleiben
n_max = len(columns_to_analyze)
df_filtered[columns_to_analyze] = df_filtered[columns_to_analyze].clip(upper=n_max)
n_respondents = df_filtered.shape[0]
# --- Funktion: Dowdall-Gewichte pro Zeile berechnen ---
def dowdall_weights_for_row(row):
return row.map(lambda r: 1/int(r) if not pd.isna(r) else 0)
df_strength_dowdall = df_filtered.apply(dowdall_weights_for_row, axis=1)
# --- Rangstärke pro Kategorie: Summe der Dowdall-Werte geteilt durch Gesamtzahl Respondents ---
mean_strength_norm = df_strength_dowdall.sum() / n_respondents
values_list = [mean_strength_norm[col] for col in columns_to_analyze]
# --- Häufigkeiten der Nennungen ---
mention_counts = df_filtered.notna().sum()
# --- Sortieren nach Rangstärke absteigend ---
sorted_indices = np.argsort(values_list)[::-1]
sorted_values = [values_list[i] for i in sorted_indices]
sorted_columns = [columns_to_analyze[i] for i in sorted_indices]
sorted_labels = [
f"{custom_labels[col]}\n(n={int(mention_counts[col])})" for col in sorted_columns
]
# --- Häufigkeiten der Ränge zählen (relativ zu allen Respondents) ---
n_col = len(columns_to_analyze)
rank_counts = {rank: [] for rank in range(1, n_col + 1)}
no_rank_counts = []
for col in sorted_columns:
counts = df_filtered[col].value_counts().reindex(range(1, n_col + 1), fill_value=0)
for rank in range(1, n_col + 1):
rank_counts[rank].append(counts[rank] / n_respondents)
no_rank_counts.append(df_filtered[col].isna().sum() / n_respondents)
# --- Farbpalette ---
colors = [mcolors.to_hex(c) for c in mcolors.LinearSegmentedColormap.from_list(
"custom_cmap", ["#aae5ec", "#11797B"])(np.linspace(0, 1, n_col))]
# --- Listen invertieren für Plot (bester Wert oben) ---
sorted_labels_rev = sorted_labels[::-1]
rank_counts_rev = {rank: rank_counts[rank][::-1] for rank in rank_counts}
no_rank_counts_rev = no_rank_counts[::-1]
sorted_values_rev = sorted_values[::-1]
# --- Plot ---
fig, ax = plt.subplots(figsize=(10, 6))
# Leichte Hilfslinien bei 10%-Schritten
for x in np.arange(0.1, 1.0, 0.1):
ax.axvline(x, color="gray", linestyle="--", linewidth=0.5, alpha=0.5, zorder=0)
# --- Gestapelte Ränge 1..n ---
bottom = np.zeros(len(sorted_labels_rev))
label_text = [f'Rang {rank}' for rank in range(1, n_col + 1)]
for i, rank in enumerate(range(1, n_col + 1)):
values = np.array(rank_counts_rev[rank])
bars = ax.barh(
sorted_labels_rev,
values,
left=bottom,
color=colors[i],
edgecolor="black",
label=label_text[i],
zorder=1
)
# Rangnummern einfügen
for bar, val in zip(bars, values):
if val >= 0.05:
ax.text(
bar.get_x() + bar.get_width()/2,
bar.get_y() + bar.get_height()/2,
str(rank),
ha="center", va="center",
color="gray", alpha=0.75, fontsize=10, fontweight="bold"
)
bottom += values
# --- "kein Rang"-Balken rechts neben gestapelten Rängen ---
for i, val in enumerate(no_rank_counts_rev):
ax.barh(
sorted_labels_rev[i],
val,
left=bottom[i],
color="lightgray",
edgecolor="black",
label="kein Rang" if i == 0 else "",
zorder=1
)
# --- Prozentwerte rechts (Rangstärke) ---
for i, v in enumerate(sorted_values_rev):
ax.text(
1.03, i, f"{round(v * 100)}%",
va="center", ha="left", fontsize=12, fontweight="bold"
)
# --- Achsen & Layout ---
ax.set_xlabel(
f'\n"Welche Herausforderungen erschweren es Ihrem Unternehmen \nNachhaltigkeitsziele oder ‑maßnahmen umzusetzen?" (n={n_respondents})',
fontsize=10
)
ax.set_xlim(0, 1.0)
ax.set_xticks(np.arange(0, 1.01, 0.2))
ax.set_xticklabels([f"{int(x*100)}%" for x in np.arange(0, 1.01, 0.2)])
ax.set_title("", fontweight="bold")
# --- Legende rechts ---
ax.legend(title="", bbox_to_anchor=(1.15, 1), loc="upper left")
plt.tight_layout()
# --- Zusatz: "Rangstärke"-Box ---
x_anchor = 0.955
y_anchor = -0.6
ax.text(
x_anchor + 0.09, y_anchor, "⬆️ Rangstärke",
va="center", ha="left",
fontsize=11, fontweight="bold",
bbox=dict(boxstyle="round,pad=0.3", fc="white", ec="black", lw=1)
)
save_plot(ax)
plt.show()
Diagramm gespeichert unter: C:\Users\Marcel\plots_Kieserling\plot.png
In [29]:
# --- Impulsgeber ---
columns_to_analyze = ["K1", "K2", "K3", "K4", "K5", "K6", "K7", "K8", "K9"]
custom_labels = {
"K1": "Andere",
"K2": "Leitfaden/Handbuch",
"K3": "Webinar oder Schulung (online)",
"K4": "Workshop oder Schulung (vor Ort)",
"K5": "Unternehmensberatung",
"K6": "Finanzielle Förderung",
"K7": "Technische Unterstützung bei Umsetzung",
"K8": "Hilfe bei der Interpretation von Anforderungen",
"K9": "Motivationstraining",
}
# --- Daten vorbereiten ---
df_filtered = df[["ID"] + columns_to_analyze].apply(pd.to_numeric, errors="coerce")
df_filtered = df_filtered[df_filtered[columns_to_analyze].notna().any(axis=1)]
df_filtered = df_filtered.set_index("ID")
n_respondents = df_filtered.shape[0]
# --- Ränge begrenzen --- # da ggf. höher bewertet wurde als nach dem Entfernen von Spalten übrig bleiben
n_max = len(columns_to_analyze)
df_filtered[columns_to_analyze] = df_filtered[columns_to_analyze].clip(upper=n_max)
n_respondents = df_filtered.shape[0]
# --- Funktion: Dowdall-Gewichte pro Zeile berechnen ---
def dowdall_weights_for_row(row):
return row.map(lambda r: 1/int(r) if not pd.isna(r) else 0)
df_strength_dowdall = df_filtered.apply(dowdall_weights_for_row, axis=1)
# --- Rangstärke pro Kategorie: Summe der Dowdall-Werte geteilt durch Gesamtzahl Respondents ---
mean_strength_norm = df_strength_dowdall.sum() / n_respondents
values_list = [mean_strength_norm[col] for col in columns_to_analyze]
# --- Häufigkeiten der Nennungen ---
mention_counts = df_filtered.notna().sum()
# --- Sortieren nach Rangstärke absteigend ---
sorted_indices = np.argsort(values_list)[::-1]
sorted_values = [values_list[i] for i in sorted_indices]
sorted_columns = [columns_to_analyze[i] for i in sorted_indices]
sorted_labels = [
f"{custom_labels[col]}\n(n={int(mention_counts[col])})" for col in sorted_columns
]
# --- Häufigkeiten der Ränge zählen (relativ zu allen Respondents) ---
n_col = len(columns_to_analyze)
rank_counts = {rank: [] for rank in range(1, n_col + 1)}
no_rank_counts = []
for col in sorted_columns:
counts = df_filtered[col].value_counts().reindex(range(1, n_col + 1), fill_value=0)
for rank in range(1, n_col + 1):
rank_counts[rank].append(counts[rank] / n_respondents)
no_rank_counts.append(df_filtered[col].isna().sum() / n_respondents)
# --- Farbpalette ---
colors = [mcolors.to_hex(c) for c in mcolors.LinearSegmentedColormap.from_list(
"custom_cmap", ["#aae5ec", "#11797B"])(np.linspace(0, 1, n_col))]
# --- Listen invertieren für Plot (bester Wert oben) ---
sorted_labels_rev = sorted_labels[::-1]
rank_counts_rev = {rank: rank_counts[rank][::-1] for rank in rank_counts}
no_rank_counts_rev = no_rank_counts[::-1]
sorted_values_rev = sorted_values[::-1]
# --- Plot ---
fig, ax = plt.subplots(figsize=(10, 6))
# Leichte Hilfslinien bei 10%-Schritten
for x in np.arange(0.1, 1.0, 0.1):
ax.axvline(x, color="gray", linestyle="--", linewidth=0.5, alpha=0.5, zorder=0)
# --- Gestapelte Ränge 1..n ---
bottom = np.zeros(len(sorted_labels_rev))
label_text = [f'Rang {rank}' for rank in range(1, n_col + 1)]
for i, rank in enumerate(range(1, n_col + 1)):
values = np.array(rank_counts_rev[rank])
bars = ax.barh(
sorted_labels_rev,
values,
left=bottom,
color=colors[i],
edgecolor="black",
label=label_text[i],
zorder=1
)
# Rangnummern einfügen
for bar, val in zip(bars, values):
if val >= 0.05:
ax.text(
bar.get_x() + bar.get_width()/2,
bar.get_y() + bar.get_height()/2,
str(rank),
ha="center", va="center",
color="gray", alpha=0.75, fontsize=10, fontweight="bold"
)
bottom += values
# --- "kein Rang"-Balken rechts neben gestapelten Rängen ---
for i, val in enumerate(no_rank_counts_rev):
ax.barh(
sorted_labels_rev[i],
val,
left=bottom[i],
color="lightgray",
edgecolor="black",
label="kein Rang" if i == 0 else "",
zorder=1
)
# --- Prozentwerte rechts (Rangstärke) ---
for i, v in enumerate(sorted_values_rev):
ax.text(
1.03, i, f"{round(v * 100)}%",
va="center", ha="left", fontsize=12, fontweight="bold"
)
# --- Achsen & Layout ---
ax.set_xlabel(
f'\n"Welche Art von Unterstützung wäre für Ihr Unternehmen \nbei der Bearbeitung von Nachhaltigkeitsthemen hilfreich?" (n={n_respondents})',
fontsize=10
)
ax.set_xlim(0, 1.0)
ax.set_xticks(np.arange(0, 1.01, 0.2))
ax.set_xticklabels([f"{int(x*100)}%" for x in np.arange(0, 1.01, 0.2)])
ax.set_title("Rangreihenfolge der Unterstützungsbedarfe bei der Erreichung der Nachhaltigkeitsziele", fontweight="bold")
# --- Legende rechts ---
ax.legend(title="", bbox_to_anchor=(1.15, 1), loc="upper left")
plt.tight_layout()
# --- Zusatz: "Rangstärke"-Box ---
x_anchor = 0.955
y_anchor = -0.6
ax.text(
x_anchor + 0.09, y_anchor, "⬆️ Rangstärke",
va="center", ha="left",
fontsize=11, fontweight="bold",
bbox=dict(boxstyle="round,pad=0.3", fc="white", ec="black", lw=1)
)
save_plot(ax)
plt.show()
Diagramm gespeichert unter: C:\Users\Marcel\plots_Kieserling\Rangreihenfolge_der_Unterstützungsbedarfe_bei_der_Erreichung_der_Nachhaltigkeitsziele.png
In [30]:
#Paarweiservergelich einlesen 2
df_PWV = pd.read_csv(
r"C:\ .csv", #Dateipfad zu den Rohdaten aus Paarweisemvergleich
sep=",",
quotechar='"',
encoding="UTF-8"
)
mapping = {
"Transparente Kennzeichnung von Produkten und Dienstleistungen sowie faires Marketing": ("S", "S4"),
"Arbeitsbedingungen (Sicherheit, Arbeitszeiten, Vergütung) in der eigenen Belegschaft": ("S", "S1"),
"Gleichbehandlung und Chancengleichheit in der eigenen Belegschaft": ("S", "S1"),
"Arbeitsbezogene Rechte (Gewerkschaften, Zwangsarbeit, Datenschutz) der eigenen Belegschaft": ("S", "S1"),
"Arbeitsbedingungen (Sicherheit, Arbeitszeiten, Vergütung) in der Wertschöpfungskette": ("S", "S2"),
"Gleichbehandlung und Chancengleichheit in der Wertschöpfungskette": ("S", "S2"),
"Arbeitsbezogene Rechte (Gewerkschaften, Zwangsarbeit, Datenschutz) in der Wertschöpfungskette": ("S", "S2"),
"Wahrung wirtschaftliche, sozialer und kultureller Rechte lokaler Gemeinschaften": ("S", "S3"),
"Wahrung politischer und bürgerlicher Rechte lokaler Gemeinschaften": ("S", "S3"),
"Wahrung der Rechte indigener Völker": ("S", "S3"),
"Abfallaufkommen und -bewirtschaftung": ("E", "E5"),
"Persönliche Sicherheit der Nutzer von Produkten oder Dienstleistungen": ("S", "S4"),
"Gleichberechtigte Nutzung von Produkten und Dienstleistungen durch alle Verbrauchergruppen": ("S", "S4"),
"Nachhaltige Unternehmenskultur und Führungsverhalten": ("G", "G1"),
"Schutz von Hinweisgebern und Hinweisgeberinnen (Whistleblower)": ("G", "G1"),
"Tierschutz": ("G", "G1"),
"Politisches Engagement und Lobbytätigkeit": ("G", "G1"),
"Lieferantenbeziehungen und Zahlungspraktiken": ("G", "G1"),
"Korruptions- und Bestechungsbekämpfung": ("G", "G1"),
"Mikroplastik in Umwelt und Produkten": ("E", "E2"),
"Beitrag zum Klimaschutz (Reduktion CO2-Emissionen)": ("E", "E1"),
"Energieverbrauch und -quellen": ("E", "E1"),
"Luftverschmutzung durch Luftschadstoffe (NOx, SOx, Partikel; kein CO2)": ("E", "E2"),
"Wasserverschmutzung": ("E", "E2"),
"Bodenverschmutzung": ("E", "E2"),
"Verschmutzung von lebenden Organismen und Nahrungsressourcen": ("E", "E2"),
"Umgang mit besorgniserregenden Stoffen": ("E", "E2"),
"Umgang mit besonders besorgniserregenden Stoffen": ("E", "E2"),
"Anpassung an Auswirkungen des Klimawandels": ("E", "E1"),
"Wassermanagement und -verbrauch": ("E", "E3"),
"Schutz und Nutzung von Meeresressourcen (z.B . Fische, Meerwasser)": ("E", "E3"),
"Ursachen für den Verlust der biologischen Vielfalt (Biodiversität)": ("E", "E4"),
"Folgen wirtschaftlicher Tätigkeit auf Tier- und Pflanzenarten": ("E", "E4"),
"Folgen wirtschaftlicher Tätigkeit auf ökologische Lebensräume": ("E", "E4"),
"Abhängigkeit von und Nutzung natürlicher Ressourcen": ("E", "E4"),
"Nachhaltige Ressourcen in der Beschaffung und Nutzung": ("E", "E4"),
"Nachhaltig erzeugte Produkte und Dienstleistungen": ("E", "E4"),
}
In [31]:
#df erstellen
# ausgewertete IDs
ID = [
152, 151, 149, 148, 144, 143, 141, 139, 138, 136, 135, 127, 125, 132, 123, 122,
130, 120, 114, 105, 103, 95, 94, 85, 84, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66,
65, 64, 115, 62, 110, 61, 60, 58, 56, 55, 53, 52, 50, 49, 48, 47, 89, 46, 86,
90, 45, 44, 43, 42, 41, 83, 37, 34, 30, 18, 17, 16, 15, 14, 31, 13, 12, 11, 27,
8, 7, 6, 142, 129, 106, 107, 96, 82, 36]
ID = [f"Participant {i}" for i in ID]
df_PWV = df_PWV[df_PWV['Display Name'].isin(ID)]
#"Überspringen" löschen:
df_PWV = df_PWV[~((df_PWV['Opinion 1 Result'] == 0.5) & (df_PWV['Opinion 2 Result'] == 0.5))].copy()
# KMU und große U
ID_KMU = [152,151,149,143,141,139,136,127,125,123,114,84,75,74,72,71,70,69,66,65,64,62,60,58,56,55,53,52,50,49,48,47,46,86,45,44,43,41,37,34,30,18,17,16,15,14,13,11,6]
ID_gU = [148,144,135,122,120,105,103,95,94,85,68,67,61,42,12,8,7]
ID_KMU = [f"Participant {i}" for i in ID_KMU]
ID_gU = [f"Participant {i}" for i in ID_gU]
# DataFrames erstellen KMUunf Große Unernehen
df_PWV_KMU = df_PWV[df_PWV['Display Name'].isin(ID_KMU)].copy()
df_PWV_gU = df_PWV[df_PWV['Display Name'].isin(ID_gU)].copy()
In [32]:
#Konsistenzcheck
import pandas as pd
import networkx as nx
def check_consistency(df):
konsistenz_ergebnisse = []
for bewerter, df_b in df.groupby('Display Name'):
G = nx.DiGraph()
# Kanten basierend auf Ergebnissen hinzufügen
for _, row in df_b.iterrows():
if row['Opinion 1 Result'] == 1:
G.add_edge(row['Opinion 1'], row['Opinion 2'])
elif row['Opinion 2 Result'] == 1:
G.add_edge(row['Opinion 2'], row['Opinion 1'])
# Zyklus prüfen
try:
zyklus = nx.find_cycle(G, orientation='original')
konsistent = False
except nx.NetworkXNoCycle:
zyklus = None
konsistent = True
konsistenz_ergebnisse.append({
'Bewerter': bewerter,
'Konsistent': konsistent,
'Zyklen': zyklus
})
return pd.DataFrame(konsistenz_ergebnisse)
pd.set_option("display.max_rows", None)
pd.set_option("display.max_columns", None)
pd.set_option("display.max_colwidth", None)
df_konsistenz = check_consistency(df_PWV)
df_inkonsistent = df_konsistenz[df_konsistenz['Konsistent'] == False]
print(df_konsistenz[df_konsistenz['Konsistent'] == False])
Bewerter Konsistent \
65 Participant 72 False
Zyklen
65 [(Verschmutzung von lebenden Organismen und Nahrungsressourcen, Arbeitsbezogene Rechte (Gewerkschaften, Zwangsarbeit, Datenschutz) in der Wertschöpfungskette, forward), (Arbeitsbezogene Rechte (Gewerkschaften, Zwangsarbeit, Datenschutz) in der Wertschöpfungskette, Lieferantenbeziehungen und Zahlungspraktiken, forward), (Lieferantenbeziehungen und Zahlungspraktiken, Verschmutzung von lebenden Organismen und Nahrungsressourcen, forward)]
In [99]:
#Stats zu den PWV estellen
def summarize_pwvs(df, mapping=None):
"""
Berechnet Vergleichsstatistiken für ein PWV-DataFrame.
Parameters:
- df: pd.DataFrame mit den Spalten 'Opinion 1', 'Opinion 2',
'Opinion 1 Result', 'Opinion 2 Result'
- mapping: dict, optional, um Items auf Dimension und Thema zuzuordnen
Returns:
- pd.DataFrame mit Item-Statistiken
"""
# Anzahl der Vergleiche pro Item
comparisons_1 = df.groupby('Opinion 1').size()
comparisons_2 = df.groupby('Opinion 2').size()
total_comparisons = comparisons_1.add(comparisons_2, fill_value=0)
# Anzahl der Siege pro Item
wins_1 = df.groupby('Opinion 1')['Opinion 1 Result'].sum()
wins_2 = df.groupby('Opinion 2')['Opinion 2 Result'].sum()
total_wins = wins_1.add(wins_2, fill_value=0)
# Anzahl der Niederlagen
total_losses = total_comparisons - total_wins
# Standardabweichung der Ergebnisse pro Item
def get_results(item):
results_1 = df.loc[df['Opinion 1'] == item, 'Opinion 1 Result']
results_2 = df.loc[df['Opinion 2'] == item, 'Opinion 2 Result']
return pd.concat([results_1, results_2])
stds = pd.Series({item: get_results(item).std() for item in total_comparisons.index})
# Zusammenfassung
item_stats = pd.DataFrame({
'Item': total_comparisons.index,
'Comparisons': total_comparisons.values,
'Wins': total_wins.values,
'Losses': total_losses.values,
'Win Rate (%)': (total_wins / total_comparisons * 100).values,
'Std': stds.values
})
# Nach Win Rate sortieren
item_stats = item_stats.sort_values(by='Win Rate (%)', ascending=False).reset_index(drop=True)
# Optional: Mapping hinzufügen
if mapping:
item_stats["ESRS_Dimension"] = item_stats["Item"].map(lambda x: mapping.get(x, ("", ""))[0])
item_stats["ESRS_Thema"] = item_stats["Item"].map(lambda x: mapping.get(x, ("", ""))[1])
return item_stats
In [105]:
import matplotlib.pyplot as plt
import textwrap
greens = ["#1B5E20", "#4CAF50", "#C8E6C9"]
def plot_pwv(item_stats, df_name="", color_map=None):
if color_map is None:
color_map = {
"E": "#00C1D4",
"S": "#FF7E15",
"G": "#7200FE"
}
# Labels mit Anzahl der Vergleiche erweitern und umbrechen
labels_wrapped = [
"\n".join(textwrap.wrap(f"{row['Item']} (n={int(row['Comparisons'])})", width=50))
for _, row in item_stats.iterrows()
]
# Farben zuweisen
colors = item_stats["ESRS_Dimension"].map(color_map)
plt.figure(figsize=(15, 8))
bars = plt.bar(
x=labels_wrapped,
height=item_stats["Win Rate (%)"].round(1),
color=colors
)
# Achsenformatierung
plt.xticks(rotation=90, fontsize=8, ha='center', va='top', multialignment='right')
plt.ylabel("Win Rate (%)", fontsize=10)
plt.xlabel(f'\n"Welches der beiden Themen ist für Ihr Unternehmen wichtiger?"')
plt.title(f"Paarweiservergleich von ESRS-Themen ({df_name})", fontsize=14, pad=15, fontweight="bold")
# Wertebeschriftung auf den Balken
for i, bar in enumerate(bars):
score = item_stats.loc[i, "Win Rate (%)"].round(1)
x_pos = bar.get_x() + bar.get_width() / 2
y_pos = bar.get_height()
plt.text(
x=x_pos,
y=y_pos + 0.25,
s=f"{score:.0f}",
va='bottom',
ha='center',
fontsize=8
)
# Rand anpassen
plt.xlim(-0.5, len(item_stats) - 0.5)
plt.tight_layout()
plt.show()
In [113]:
plot_pwv(summarize_pwvs(df_PWV, mapping=mapping), df_name="ALLE", color_map = colors_green_ESG)
plot_pwv(summarize_pwvs(df_PWV_KMU, mapping=mapping), df_name="KMU")
plot_pwv(summarize_pwvs(df_PWV_gU, mapping=mapping), df_name="Grosse")
In [115]:
ausgewählte = {
"Anpassung an Auswirkungen des Klimawandels",
"Beitrag zum Klimaschutz (Reduktion CO2-Emissionen)",
"Energieverbrauch und -quellen",
"Abfallaufkommen und -bewirtschaftung",
"Arbeitsbedingungen (Sicherheit, Arbeitszeiten, Vergütung) in der eigenen Belegschaft",
"Gleichbehandlung und Chancengleichheit in der eigenen Belegschaft",
"Nachhaltige Unternehmenskultur und Führungsverhalten",
"Korruptions- und Bestechungsbekämpfung"
}
df_PWV_ausgew = df_PWV[df_PWV['Opinion 1'].isin(ausgewählte) & df_PWV['Opinion 2'].isin(ausgewählte)].copy()
plot_pwv(summarize_pwvs(df_PWV_ausgew, mapping=mapping), df_name="Ausgewählte")