Example#

To be able to run the programm, import all the needed packages first.#

from tabulate import tabulate
import sqlite3
import csv
import geopandas as geopandas
import numpy as np
import pandas as pd
import os
import platform
import sqlite3
import gdal
from gdal import ogr
from shapely.geometry import Point
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[1], line 4
      2 import sqlite3
      3 import csv
----> 4 import geopandas as geopandas
      5 import numpy as np
      6 import pandas as pd

ModuleNotFoundError: No module named 'geopandas'

In this second step, the table plants in the Pflanzendaten database is created.#

connection = sqlite3.connect("Pflanzendaten.db")
cursor = connection.cursor()


sql_command = """
CREATE TABLE IF NOT EXISTS plants (
species VARCHAR(255),
name VARCHAR(255),
nativ BOOLEAN,
endangered VARCHAR(255),
habitat VARCHAR(255),
waterdepthmin INTEGER(255),
waterdepthmax  INTEGER(255),
rootdepth INTEGER(255),
groundwatertablechange VARCHAR(255),
floodheightmax INTEGER(255),
floodloss REAL(255),
floodduration INTEGER(255),
PRIMARY KEY (species, name, habitat)
);"""

cursor.execute(sql_command)
<sqlite3.Cursor at 0x20897235490>

The inputquestion() function is used to insert data into the table#

def inputquestion():
    """function that lets the user put data into the database

    the function provides 2 options for data input, if option 1 is chosen via console input "1", the user can provide the name 
    of a csv file. if option 2 is chosen, the user can add a single row via sql command. If neither of those two options is 
    chosen, the function will print a string in the python console

    Returns:
        string in console if none of the two options above is chosen
    """
    print('Enter 1 to input data from csv file\n Enter 2 to input data via sql command')
    src = int(input('Enter here:'))
    if src == 1:

        with open(input('enter csv-filename')+'.csv') as csvfile:
            csv_reader_object = csv.reader(csvfile, delimiter=',')
            with sqlite3.connect("Pflanzendaten.db") as connection:
                cursor = connection.cursor()
                sql_command = """
                INSERT INTO plants (species,name,nativ,endangered,habitat,waterdepthmin,waterdepthmax,rootdepth,groundwatertablechange,floodheightmax,floodloss,floodduration)
                VALUES (:species, :name, :nativ, :endangered, :habitat, :waterdepthmin, :waterdepthmax, :rootdepth, :groundwatertablechange, :floodheightmax, :floodloss, :floodduration)
                """
                cursor.executemany(sql_command, csv_reader_object)
    elif src == 2:
        connection = sqlite3.connect("Pflanzendaten.db")
        cursor = connection.cursor()
        sql_command = (input("""Insert sql command"""))
        cursor.execute(sql_command)
        cursor.execute("COMMIT")
    else:
        print('only able to import data to table using csv file or sql command')

search_db_via_query() is allowing the usage of querys to search in the database for information#

def search_db_via_query(query):
    """Function that checks database for matching entries with user input.

    The function takes the user input and adds it to the used sql command to search for matching entries in the provided database
    if there are matching entries these will be printed in the python console

    Args:
        query (string): habitat name in sql, provided by the user

    Returns:
        table entries matching with user input
    """
    connection = sqlite3.connect("Pflanzendaten.db")
    cursor = connection.cursor()
    cursor.execute("SELECT * FROM plants WHERE " + query)
    content = cursor.fetchall()
    print(tabulate((content), headers=['species', 'name', 'nativ', 'endangered', 'habitat', 'waterdepthmin', 'waterdepthmax', 'rootdepth', 'groundwatertablechange', 'floodheightmax', 'floodloss', 'floodduration']))
    print('Status 1 equals nativ')

    connection.close()

To fill the table with data, run inputquestion() and select which option you want to chose. Note: the name of the provided csv file is “plantdata”, if you want to try inserting data by using an sql command, just type it directly without using quotation marks.#

inputquestion()
Enter 1 to input data from csv file
 Enter 2 to input data via sql command
Enter here:3
only able to import data to table using csv file or sql command

After successfully inserting data into the database, you can search for plants by running search_db_via_query() and providing it with an habitat name (Alpenvorland, Niederrheinisches Tiefland or Oberrheinisches Tiefland). Note: unfortunately, due to jupyter notebook the output is overlapping and as a result looks a bit rough.#

habitat = input('Enter name of habitat\n')
query = "habitat = '" + habitat + "'"
search_db_via_query(query)
Enter name of habitat
Oberrheinisches Tiefland
species                                        name                             nativ  endangered           habitat                   waterdepthmin    waterdepthmax    rootdepth    groundwatertablechange    floodheightmax    floodloss    floodduration
---------------------------------------------  -----------------------------  -------  -------------------  ------------------------  ---------------  ---------------  -----------  ------------------------  ----------------  -----------  ---------------
Groenlandia densa (L.) Fourr.                  Fischkraut                           1  strongly endangered  Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Potamogeto pectinatus                          Kamm Laichkraut                      1  not endangered       Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Potamogeton perfoliatus                        Durchwachsenes Laichkraut            1  pre warning          Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Hippuris vulgaris                              Gewöhnlicher Tannenwedel            1  pre warning          Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Epilobium dodonaei                             Rosmarin Weidenroeschen              1  not endangered       Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Scrophularia canina                            Hunds Braunwurz                      1  not endangered       Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Calamagrostis pseudophragmites                 Ufer Reitgras                        1  strongly endangered  Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Gypsophila repens                              Kriechendes Gipskraut                1  not endangered       Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Salix nigricans                                Schwarz Weide                        1  not listed           Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Hippophae rhamnoides subsp. fluviatilis Soest  Fluss Sanddorn                       1  endangered           Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    NoData            Nodata       NoData
Ulmus minor                                    Feld Ulme                            1  not endangered       Oberrheinisches Tiefland  NoData           NoData           NoData       50-280                    270               NoData       90
Quercus robur                                  Stiel Eiche                          1  not endangered       Oberrheinisches Tiefland  NoData           70               NoData       30-150                    349               NoData       113
Alnus glutinosa                                Schwarzerle                          1  not endangered       Oberrheinisches Tiefland  NoData           70               NoData       0-80                      312               50.0         29-45
Populus nigra                                  Schwarzpappel                        1  not endangered       Oberrheinisches Tiefland  NoData           NoData           NoData       50-280                    160               NoData       NoData
Populus alba                                   Silberpappel                         1  not endangered       Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    180               NoData       NoData
Salix purpurea                                 Purpur Weide                         1  not endangered       Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    210               NoData       170
Salix alba                                     Silber Weide                         1  not endangered       Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    350               NoData       169
Salix eleagnos                                 Lavendel Weide                       1  pre warning          Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Fraxinus excelsior                             Gewoehnliche Esche                   1  not endangered       Oberrheinisches Tiefland  NoData           70               NoData       NoData                    340               25.0         45
Rhamnus cathartica                             Purgier Kreuzdorn                    1  not endagnered       Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    190-200           50.0         NoData
pinus sylvestris                               Gewoehnliche Kiefer                  1  not endangered       Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
cornus sanguinea                               Blutroter Hartriegel                 1  not endangered       Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    200               50.0         120
sambucus nigra                                 Schwarzer Holunder                   1  not endangered       Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    250               >50          NoData
prunus spinosa                                 Schlehe                              1  not endangered       Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    250               50.0         NoData
Euonymus europaeus                             Europaeisches Pfaffenhuetchen        1  not endangered       Oberrheinisches Tiefland  NoData           NoData           NoData       NoData                    190               NoData       117
Status 1 equals nativ

Defining the class “Plant” is enabling the usage of the habitat_search() function#

class Plant:
    """

    """

    def __init__(self, species, name, nativ, habitat, endangered, waterdepthmin, waterdepthmax, rootdepth, groundwatertablechange, floodheightmax, floodloss, flooddurationmax):
        """

        Args:
            species (str): scientific plant name
            name (str): common german plant name
            nativ (bool): equals 1 if the plant is nativ, 0 if its not
            habitat (str): habit name of the plant
            endangered (str): information about the endangerment status of the plant
            waterdepthmin (int): minimal required water depth
            waterdepthmax (int): maximum depth to groundwater
            rootdepth (int): average root depth
            groundwatertablechange (varchar): maximum change in groundwater table that the plant can survive
            floodheightmax (int): maximum flood height the plant can survive
            floodloss (float): losses during maximum flood height and flooding days that occured in plant population
            flooddurationmax (int): maximum number of flooding days the plant can survive
        """
        self.species = species
        self.name_german = name
        self.status = nativ
        self.is_endangered = endangered
        self.habitat_in_germany = habitat
        self.minimum_waterdepth = waterdepthmin
        self.maximum_waterdepth = waterdepthmax
        self.average_root_depth = rootdepth
        self.change_of_groundwatertable = groundwatertablechange
        self.critical_flood_height = floodheightmax
        self.plant_mortality_during_critial_flooding = floodloss
        self.critical_flood_duration = flooddurationmax

    def print_habitat(self):
        """
        prints the plant parameters as string in console

        Returns:
            String in console
        """
        print('\nscientific name:\n{0}\ncommon german name:\n{1}\nstatus:\n{2}\nendangered?:\n{3}'.format(self.species,
                                                                                        str(self.name_german),
                                                                                        str(self.status),
                                                                                        str(self.habitat_in_germany),
                                                                                        str(self.is_endangered),
                                                                                        str(self.minimum_waterdepth),
                                                                                        str(self.maximum_waterdepth),
                                                                                        str(self.average_root_depth),
                                                                                        str(self.change_of_groundwatertable),
                                                                                        str(self.critical_flood_height),
                                                                                        str(self.plant_mortality_during_critial_flooding),
                                                                                        str(self.critical_flood_duration)))

habitat_search() is used to search the csv file for data#

def habitat_search(column, entry):
    """Function searches in csv file for vegetation matching the user input.

    The function uses the console input to search for matching entries in the provided csv file,
    if there are matching entries the function print_habitat gets called to print the information in the python console.

    Args:
        column(int): column in the .csv file
        entry(int): entry in the .csv file

    Returns:
        String in console
    """
    df = pd.read_csv('plantdata.csv', encoding='unicode_escape')
    if platform.system() == 'Linux':
        df = pd.read_csv('plantdata.csv')
    else:
        df = pd.read_csv('plantdata.csv', encoding='unicode_escape')
    df1 = df.dropna()

    def search(column, entry, df):
        df2 = df1.to_numpy()
        column = df[column]
        for i in range(len(column)):
            if column[i] == entry:
                plant = Plant(df2[i, 0], df2[i, 1], df2[i, 2], df2[i, 3], df2[i, 4], df2[i, 5], df2[i, 6], df2[i, 7], df2[i, 8], df2[i, 9], df2[i, 10], df2[11])
                plant.print_habitat()
        else:
            print('')

    search(column, entry, df1)

To search for vegetation in the csv file, run search_by_habitat() and provide it with a habitat name (Alpenvorland, Niederrheinisches Tiefland or Oberrheinisches Tiefland).#

search_by_habitat()
Enter name of habitat
Niederrheinisches Tiefland

scientific name:
Betula pendula
common german name:
Haenge Birke
status:
1
endangered?:
not endangered

scientific name:
Quercus robur
common german name:
Stieleiche
status:
1
endangered?:
not endangered

scientific name:
Betula pubescens s.str.
common german name:
Moor Birke
status:
1
endangered?:
not endangered

scientific name:
Alnus glutinosa
common german name:
Schwarzerle
status:
1
endangered?:
not endangered

scientific name:
Fraxinus excelsior
common german name:
Gemeine Esche
status:
1
endangered?:
not endangered

scientific name:
Frangula alnus
common german name:
Echter Faulbaum
status:
1
endangered?:
not endangered

scientific name:
Ribes rubrum
common german name:
Rote Johannisbeere
status:
1
endangered?:
not endangered

scientific name:
Ribes nigrum
common german name:
Schwarze Johannisbeere
status:
1
endangered?:
not endangered

scientific name:
Rubus caesius
common german name:
Kratzbeere
status:
1
endangered?:
not endangered

scientific name:
Populus nigra
common german name:
Schwarzpappel
status:
1
endangered?:
edangered

scientific name:
Viburnum opulus
common german name:
Gewoehnlicher Schneeball
status:
1
endangered?:
not endangered

scientific name:
Prunus padus
common german name:
Gewoehnliche Traubenkirsche
status:
1
endangered?:
not endangered

scientific name:
Ulmus laevis
common german name:
Flatterulme
status:
1
endangered?:
pre warning

scientific name:
Salix fragilis
common german name:
Bruchweide
status:
1
endangered?:
not endangered

scientific name:
Salix viminalis
common german name:
Korbweide
status:
1
endangered?:
not endangered

scientific name:
Salix aurita
common german name:
Ohr Weide
status:
1
endangered?:
not endangered

scientific name:
Salix purpurea
common german name:
Purpur Weide
status:
1
endangered?:
not endangered

scientific name:
Ribes uva-crispa
common german name:
Stachelbeere
status:
1
endangered?:
not endangered

scientific name:
Ulmus minor
common german name:
Feldulme
status:
1
endangered?:
not endangered

scientific name:
Salix cinerea
common german name:
Grau Weide
status:
1
endangered?:
not endangered

Status 1 equals nativ

point_in_bound() checks if the provided coordinates are inside of the used shapefile#

def point_in_bound(filename, x, y, area):
    """Function that checks if the coordinates provided by the user are in bound of the shapefile polygon.


    If the provided coordinates are out of bounds, a string will be printed in the console to let the user know,
    if they are matching one of the shapefiles, search_db_via_query() gets called.

    Args:
        filename (str): name of the shapefile
        x (float): x - coordinate
        y (float): y - coordinate
        area (str): name of the study area

    Returns:
        string to console
    """
    file_shape = geopandas.read_file(filename)
    polygon = list(file_shape.geometry)[0]
    point = Point(x, y)
    if polygon.contains(point):
        query = "habitat = '" + area + "'"
        search_db_via_query(query)
        print('Enter 1 if you want elevation data for the coordinates\nEnter 2 if you dont want elevation data')
        src = int(input('Enter here:'))

        if src == 1:
            elevation(x, y)
        elif src == 2:
            print('done')
    else:
        print('\ncoordinates out of \n' + area + '\nplease check provided shapefile for suitable coordinates\n')

The elevation() function transforms the coordinates into rasterdata to provide information about the elevation#

def elevation(x, y):
    """Function used to get information about elevation at the provided coordinates.

    Args:
        x (float): x - coordinate
        y (float): y - coordinate

    Returns:
        elevation data for coordinate input in console
    """
    file = os.path.abspath("..") + "\Shape\Shape.vrt"
    layer = gdal.Open(file)
    gt = layer.GetGeoTransform()
    rasterx = int((x - gt[0]) / gt[1])
    rastery = int((y - gt[3]) / gt[5])
    print('elevation =', layer.GetRasterBand(1).ReadAsArray(rasterx, rastery, 1, 1)[0][0], 'm above sea level')

search_by_coordinates() enables the user to provide coordinates and transforms them into float values, afterwards point_in_bound() gets called for all 3 shapefiles#

def search_by_coordinates():
    """Function that lets the user input coordinates.

    After asking the user to input x and y coordinates, point_in_bound(..) gets called for the 3 provided shapefiles.
    Afterwards the user gets asked if he wants to receive elevation data for the input coordinates.

    Returns:
    """
    print('CRS used is EPSG:3857 \n for reference check https://epsg.io/3857 ')
    x = float(input('Enter x coordinate\n'))
    y = float(input('Enter y coordinate\n'))
    point_in_bound(os.path.abspath("..")+"\Shape\prealpinebavaria.shp", x, y, 'Alpenvorland')
    point_in_bound(os.path.abspath("..")+"\Shape\oberrheinmaintiefland.shp", x, y, 'Oberrheinisches Tiefland')
    point_in_bound(os.path.abspath("..")+"\Shape\Tiefland.shp", x, y, 'Niederrheinisches Tiefland')

The function question() provides the option for an easy usage of the tool, asking directly which search option you want to choose#

def question():
    """Function to let the user decide if he wants to search by habitat in csv file, search by habitat in database or search by coordinates.

    The function prints a string in the console to ask the user if he wants to search by putting in coordinates or the name of the habitat,
    furthermore it is asking the user if he wants to search by the name of the habitat in the provided csv file or database.
    If option 1 is chosen, user is asked for an habitat name before calling search_db_via_query()

    Args:
        1 (int): calls search_db_via_query()
        2 (int): calls search_by_coordinates()
        3 (int): calls search_by_habitat()

    Returns:
        text string 'no data' if the input is anything else then 1, 2 or 3
    """
    print('Enter 1 to search database by habitat with detailed information\nEnter 2 to search database by coordinates \nEnter 3 to search by habitat in csv file for a quick overview without detail')
    print('habitat search options so far:\n Alpenvorland, Niederrheinisches Tiefland, Oberrheinisches Tiefland')
    src = int(input('Enter here:'))

    if src == 1:
        habitat = input('Enter name of habitat\n')
        query = "habitat = '" + habitat + "'"
        search_db_via_query(query)
    elif src == 2:
        search_by_coordinates()
    elif src == 3:
        search_by_habitat()
    else:
        print('no data')

Run question() if you want to choose for one of the search functions.#

question()
Enter 1 to search database by habitat with detailed information
Enter 2 to search database by coordinates 
Enter 3 to search by habitat in csv file for a quick overview without detail
habitat search options so far:
 Alpenvorland, Niederrheinisches Tiefland, Oberrheinisches Tiefland
Enter here:2
CRS used is EPSG:3857 
 for reference check https://epsg.io/3857 
Enter x coordinate
1242560.331804
Enter y coordinate
6056258.625091
species                         name                           nativ  endangered                  habitat       waterdepthmin    waterdepthmax    rootdepth    groundwatertablechange    floodheightmax    floodloss    floodduration
------------------------------  ---------------------------  -------  --------------------------  ------------  ---------------  ---------------  -----------  ------------------------  ----------------  -----------  ---------------
Alnus incana                    Grauerle                           1  not endangered              Alpenvorland  NoData           NoData           Nodata       NoData                    282               25.0         NoData
Carex sylvatica                 Wald Segge                         1  not endangered              Alpenvorland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
carex acuta                     Schlanke Segge                     1  not endangered              Alpenvorland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
circae lutetiana                Grosses hexenkraut                 1  not endangered              Alpenvorland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
clematis vitalba                Gewoehnliche Waldrebe              1  not endangered              Alpenvorland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
fraxinus excelsior              Gemeine Esche                      1  not endangered              Alpenvorland  NoData           70               NoData       NoData                    340               25.0         45
Hydrocharis morsus ranae        Froschbiss                         1  pre warning                 Alpenvorland  20               40               NoData       NoData                    NoData            NoData       NoData
Humulus lupulus                 Hopfen                             1  not endangered              Alpenvorland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Myricaria germanica             Deutsche Tamariske                 1  threatened with extinction  Alpenvorland  NoData           180              NoData       NoData                    NoData            NoData       NoData
Phalaris arundinacea            Rohrglanzgras                      1  not endangered              Alpenvorland  NoData           130              NoData       NoData                    NoData            NoData       NoData
Phragmites australis            Schilfrohr                         1  not endangered              Alpenvorland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Populus nigra                   Schwarzpappel                      1  endangered                  Alpenvorland  NoData           NoData           NoData       50-280                    160               NoData       NoData
Populus alba                    Silberpappel                       1  not endangered              Alpenvorland  NoData           NoData           NoData       NoData                    180               NoData       NoData
Potamogeton pectinatus          Kamm Laichkraut                    1  not endangered              Alpenvorland  20               350              NoData       NoData                    NoData            NoData       NoData
Salix purpurea                  Purpur Weide                       1  not endangered              Alpenvorland  NoData           NoData           NoData       NoData                    210               NoData       170
Salix alba                      Silber Weide                       1  not endangered              Alpenvorland  NoData           NoData           NoData       NoData                    350               NoData       169
Salix fragilis                  Bruch Weide                        1  not endangered              Alpenvorland  NoData           NoData           NoData       50-280                    351               NoData       170
Salix eleagnos                  Lavendel Weide                     1  pre warning                 Alpenvorland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Solanum Dulcamara               Bittersuesser Nachtschatten        1  not endangered              Alpenvorland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Sparganium erectum              Aestiger Igelkolben                1  not endangered              Alpenvorland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Typha latifolia                 Breitblaettriger Rohrkolben        1  not endangered              Alpenvorland  NoData           NoData           NoData       NoData                    200               NoData       NoData
Calamagrostis pseudophragmites  Ufer Reitgras                      1  strongly endangered         Alpenvorland  NoData           NoData           NoData       NoData                    NoData            NoData       NoData
Status 1 equals nativ
Enter 1 if you want elevation data for the coordinates
Enter 2 if you dont want elevation data
Enter here:1
elevation = 647 m above sea level

coordinates out of 
Oberrheinisches Tiefland
please check provided shapefile for suitable coordinates


coordinates out of 
Niederrheinisches Tiefland
please check provided shapefile for suitable coordinates