docs: def log_to_DataFrame(execution_history_items, data_in_columns=[], data_out_columns=[], scoped_in_columns=[],
                       scoped_out_columns=[], semantic_data_columns=[], throw_on_pickle_error=True):
      """
      Returns all collapsed items in a table-like structure (pandas.DataFrame) with one row per executed 
      state and a set of properties resp. columns (e.g. state_name, outcome, run_id) for this state.
      The data flow (data_in/out, scoped_data_in/out, semantic_data) is omitted from this table
      representation by default, as the different states have different data in-/out-port, scoped_data-
      ports and semantic_data defined. However, you can ask specific data-/scoped_data-ports and semantic
      data to be exported as table column, given they are primitive-valued, by including the port / key
      names in the *_selected-parameters. These table-columns will obviously only be well-defined for
      states having this kind of port-name-/semantic-key and otherwise will contain a None-like value,
      indicating missing data.
  
      The available data per execution item (row in the table) can be printed using pandas.DataFrame.columns.
      """
      try:
          import pandas as pd
      except ImportError:
          raise ImportError("The Python package 'pandas' is required for log_to_DataFrame.")
  
      start, next_, concurrency, hierarchy, gitems = log_to_collapsed_structure(
          execution_history_items, throw_on_pickle_error=throw_on_pickle_error)
      gitems.pop(start['run_id'])
      if len(gitems) == 0:
          return pd.DataFrame()
  
      # remove columns which are not generic over all states (basically the
      # data flow stuff)
      df_keys = list(list(gitems.values())[0].keys())
      df_keys.remove('data_ins')
      df_keys.remove('data_outs')
      df_keys.remove('scoped_data_ins')
      df_keys.remove('scoped_data_outs')
      df_keys.remove('semantic_data')
      df_keys.sort()
  
      df_items = []
  
      for rid, item in gitems.items():
          row_data = [item[k] for k in df_keys]
  
          for key, selected_columns in [('data_ins', data_in_columns),
                                        ('data_outs', data_out_columns),
                                        ('scoped_data_ins', scoped_in_columns),
                                        ('scoped_data_outs', scoped_out_columns),
                                        ('semantic_data', semantic_data_columns)]:
              for column_key in selected_columns:
                  row_data.append(item[key].get(column_key, None))
          df_items.append(row_data)
  
      for key, selected_columns in [('data_ins', data_in_columns),
                                    ('data_outs', data_out_columns),
                                    ('scoped_data_ins', scoped_in_columns),
                                    ('scoped_data_outs', scoped_out_columns),
                                    ('semantic_data', semantic_data_columns)]:
          df_keys.extend([key + '__' + s for s in selected_columns])
      df = pd.DataFrame(df_items, columns=df_keys)
      # convert epoch to datetime
      df.timestamp_call = pd.to_datetime(df.timestamp_call, unit='s')
      df.timestamp_return = pd.to_datetime(df.timestamp_return, unit='s')
  
      # use call timestamp as index
      df_timed = df.set_index(df.timestamp_call)
      df_timed.sort_index(inplace=True)
  
      return df_timed