diff --git a/python_scripts/add_trees_to_open_street_map/.gitignore b/python_scripts/add_trees_to_open_street_map/.gitignore
index bb0616adeb338f3eb3b31ced518c351e137c46c4..5e465967597634a36431f328ace95378a202ff27 100644
--- a/python_scripts/add_trees_to_open_street_map/.gitignore
+++ b/python_scripts/add_trees_to_open_street_map/.gitignore
@@ -1,4 +1 @@
-cache
-*.html
-*.csv
-*.png
\ No newline at end of file
+cache
\ No newline at end of file
diff --git a/python_scripts/add_trees_to_open_street_map/add_trees.py b/python_scripts/add_trees_to_open_street_map/add_trees.py
index 8442b290f672b558a9a19ee0b91cefcad731ac3d..551e22de85ee5532508dc1364eb99c743c775825 100644
--- a/python_scripts/add_trees_to_open_street_map/add_trees.py
+++ b/python_scripts/add_trees_to_open_street_map/add_trees.py
@@ -17,6 +17,8 @@ import overpy
 from pyproj import Transformer
 from shapely import LineString, geometry, wkt
 from shapely.ops import transform
+import pandas as pd
+import geopandas as gpd
 
 from tree import Forest
 from import_existing_trees import get_existing_forest
@@ -47,11 +49,13 @@ IGNORE_ROADS = set(['primary', 'unclassified', 'secondary',
 
 
 SCRIPT_DIR = Path(__file__).resolve().parent
+OUTPUT_DIR = SCRIPT_DIR / 'output'
+Bounds = namedtuple("Bounds", "W S E N")
 
 
 def load_region(wkt_polygon):
     region = wkt.loads(wkt_polygon)
-    bounds = namedtuple("Bounds", "W S E N")(*region.bounds)
+    bounds = Bounds(*region.bounds)
     return region, bounds
 
 
@@ -140,22 +144,23 @@ def place_trees(forest, ways, region, to_local, tree_distance, min_distance_2) -
                                             color='#DFFF00',
                                             type='Fake Tree',
                                             description='Tilia tomentosa',
-                                            diameter=6
+                                            diameter=6,
+                                            source='add_trees.py'
                                             )
 
     return forest
 
 
-def plot_trees(bounds, forest, tree_distance) -> None:
+def plot_trees(bounds: Bounds, forest: Forest, tree_distance: float) -> None:
     print("Exporting diagram...")
-    tree_xs, tree_ys, colors = forest.xs_ys_c6
+    tree_xs, tree_ys, colors = forest.xs_ys_cs
     plt.scatter(tree_xs, tree_ys, s=2, c=colors)
 
     plt.grid(True)
     plt.title(f"{bounds}\nTree distance : {tree_distance} m")
     plt.gcf().set_size_inches(15, 10)
     plt.savefig(
-        SCRIPT_DIR / f"{get_basename(bounds)}.png", bbox_inches='tight', dpi=300)
+        OUTPUT_DIR / f"{get_basename(bounds)}.png", bbox_inches='tight', dpi=300)
     print("  DONE!")
 
 
@@ -188,27 +193,49 @@ def export_map(bounds, forest, epsg_id) -> None:
         control=True
     ).add_to(interactive_map)
 
-    interactive_map.save(f"{get_basename(bounds)}_trees.html")
+    interactive_map.save(OUTPUT_DIR / f"{get_basename(bounds)}_trees.html")
     print("  DONE!")
 
 
 def export_csv(bounds, forest, wkt_polygon, tree_distance, min_distance, epsg_id) -> None:
     print("Exporting CSV...")
-    with open(SCRIPT_DIR / f"{get_basename(bounds)}_trees.csv", "w") as csv:
+    with open(OUTPUT_DIR / f"{get_basename(bounds)}_trees.csv", "w") as csv:
         csv.write(f"# Fake trees for; {wkt_polygon}\n")
         csv.write(f"# Tree distance along roads; {tree_distance}; [m]\n")
         csv.write(f"# Minimum allowed distance between trees; {min_distance}; [m]\n")
         csv.write(f"# EPSG; {epsg_id}\n")
-        csv.write("# X; Y; Type; Description; Radius\n")
-        csv.write("# [m]; [m]; [?]; [?]; [m]\n")
+        csv.write("# X; Y; Type; Description; Radius; Source\n")
+        csv.write("# [m]; [m]; [-]; [-]; [m]; [-]\n")
         for tree in forest:
-            csv.write(f"{tree.x};{tree.y};{tree.type};{tree.description};{tree.radius}\n")
+            csv.write(f"{tree.x};{tree.y};{tree.type};{tree.description};{tree.radius};{tree.source}\n")
 
     print("  DONE!")
 
 
-def export_shapefile(bounds, forest, tree_distance, epsg_id):
+def export_shapefile(bounds: Bounds, forest: Forest, tree_distance: float, epsg_id: str) -> None:
     print("Exporting shapefile")
+
+    data = [{
+        'x': t.x, 'y': t.y,
+        'Bezeichnun': t.description, 'Baumart': t.type,
+        'Baumhöhe': t.height, 'Kronenbrei': t.diameter,
+        'Quelle': t.source,
+        }
+        for t in forest]
+
+    df = pd.DataFrame.from_dict(data)
+    gdf = gpd.GeoDataFrame(
+        df.drop(columns=['x', 'y']),
+        geometry=gpd.points_from_xy(df.x, df.y), crs=epsg_id
+    )
+
+    print(gdf)
+
+    basename = get_basename(bounds)
+    shp_dir = OUTPUT_DIR / basename
+    shp_dir.mkdir(exist_ok=True)
+    gdf.to_file(shp_dir / f"trees.shp")
+
     print("  DONE!")
 
 
diff --git a/python_scripts/add_trees_to_open_street_map/import_existing_trees.py b/python_scripts/add_trees_to_open_street_map/import_existing_trees.py
index 883b7a1b20405d1fcb82c6f620a9a791ab11b39b..71342290cacadc1a6e1c87f158fcb9ebbf4392ae 100644
--- a/python_scripts/add_trees_to_open_street_map/import_existing_trees.py
+++ b/python_scripts/add_trees_to_open_street_map/import_existing_trees.py
@@ -1,3 +1,4 @@
+from pathlib import Path
 import geopandas as gpd
 from tree import Tree, Forest
 
@@ -11,7 +12,8 @@ def get_existing_forest(shp_input):
                           description=tree_row.Bezeichnun,
                           diameter=tree_row.Kronenbrei,
                           type=tree_row.Baumart,
-                          trunk_diameter=tree_row.Stammumfan
+                          trunk_diameter=tree_row.Stammumfan,
+                          source=Path(shp_input).name
                           ))
     return Forest(trees)
 
diff --git a/python_scripts/add_trees_to_open_street_map/output/.gitignore b/python_scripts/add_trees_to_open_street_map/output/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..37c1c348800c3fd63c849b81ec3a71fc5407e7cb
--- /dev/null
+++ b/python_scripts/add_trees_to_open_street_map/output/.gitignore
@@ -0,0 +1,9 @@
+*.png
+*.html
+*.csv
+*.cpg
+*.dbf
+*.shp
+*.prj
+*.shx
+*.geojson
\ No newline at end of file
diff --git a/python_scripts/add_trees_to_open_street_map/tree.py b/python_scripts/add_trees_to_open_street_map/tree.py
index 2dd775a77dc928b8327a290c9146b61fb141c2e5..412a0198c361d5d53b3d51c000f9bdeba840b6ce 100644
--- a/python_scripts/add_trees_to_open_street_map/tree.py
+++ b/python_scripts/add_trees_to_open_street_map/tree.py
@@ -13,6 +13,7 @@ class Tree:
     trunk_diameter: float = None
     type: str = None
     description: str = '?'
+    source: str = '?'
     color: str = 'green'
 
     def __len__(self):
@@ -26,7 +27,7 @@ class Tree:
         return self.diameter / 2
 
     def __str__(self):
-        return f"{self.type} ({self.description}), {self.radius or '?'} m (X={self.x:.1f}, Y={self.y:.1f})"
+        return f"{self.type} ({self.description}), {self.radius} m (X={self.x:.1f}, Y={self.y:.1f})"
 
 
 class Forest(UserList):