import os
from datetime import datetime
from handwriting_sample.base import LoggableObject
from handwriting_sample.writer.writers import JSONFileWriter, SVCFileWriter
[docs]class HandwritingSampleWriter(LoggableObject):
"""Class implementing handwriting data writer"""
# --------------- #
# Writing methods #
# --------------- #
# TODO: idea: there is some common functionality in store_... methods that may be taken out into a common method
[docs] def write_to_json(self, sample, save_path, file_name=None, store_original_data=False, verbose=False):
"""
Stores HandwritingSample data to a JSON file.
:param sample: instance of handwriting sample
:type sample: HandwritingSample
:param save_path: save path
:type save_path: str
:param file_name: file name (optional if meta data), defaults to None
:type file_name: str, optional
:param store_original_data: store original data, defaults to False
:type store_original_data: bool, optional
:param verbose: verbosity of the logging, defaults to False
:type verbose: bool, optional
:return: True if stored, False otherwise
:rtype: bool
"""
# Get the data and meta data from the handwriting sample
data = sample.original_data_pandas_dataframe if store_original_data else sample.data_pandas_dataframe
meta = sample.meta
# Prepare and validate the data and meta data
data = sample.validator.validate_data(data, verbose=verbose)
meta = self._prepare_meta_data(sample, meta)
# If the filename is not set, create a default one
if not file_name and meta:
file_name = self._collect_file_name(meta)
# Update the save_path
save_path = os.path.join(save_path, f"{file_name}.json")
# Prepare the data to be stored
data = data.to_dict("list")
# Write the data
return JSONFileWriter.write(save_path, data, meta=meta, verbose=verbose)
[docs] def write_to_svc(self, sample, save_path, file_name=None, store_original_data=False, verbose=False):
"""
Stores HandwritingSample data to an SVC file.
:param sample: instance of handwriting sample
:type sample: HandwritingSample
:param save_path: save path
:type save_path: str
:param file_name: file name (optional if meta data), defaults to None
:type file_name: str, optional
:param store_original_data: store original data, defaults to False
:type store_original_data: bool, optional
:param verbose: verbosity of the logging, defaults to False
:type verbose: bool, optional
:return: True if stored, False otherwise
:rtype: bool
"""
# Get the data and meta data from the handwriting sample
data = sample.original_data_pandas_dataframe if store_original_data else sample.data_pandas_dataframe
meta = sample.meta
# Prepare and validate the data and meta data
data = sample.validator.validate_data(data)
meta = self._prepare_meta_data(sample, meta)
# If the filename is not set, create a default one
if not file_name and meta:
file_name = self._collect_file_name(meta)
# Update the save_path
save_path = os.path.join(save_path, f"{file_name}.svc")
# Prepare the data to be stored
data = data.to_dict("r")
data = [
f"{row[sample.AXIS_X]} {row[sample.AXIS_Y]} "
f"{row[sample.TIME]} {row[sample.PEN_STATUS]} "
f"{row[sample.AZIMUTH]} {row[sample.TILT]} "
f"{row[sample.PRESSURE]}\n" for row in data
]
# Write the data
return SVCFileWriter.write(save_path, data, meta=meta, verbose=verbose)
# --------------- #
# Utility methods #
# --------------- #
@classmethod
def _prepare_meta_data(cls, sample, meta_data=None):
"""Prepares the meta data before writing"""
# Handle no meta data
meta_data = meta_data if meta_data else {}
# Create or update the timestamps
meta_data["written_on"] = datetime.utcnow().strftime(sample.DATE_FORMAT)
meta_data["created_on"] = datetime.utcnow().strftime(sample.DATE_FORMAT) \
if not meta_data.get("created_on", None) \
else meta_data.get("created_on", None)
# Return the prepared meta data
return meta_data
@classmethod
def _collect_file_name(cls, meta_data):
"""Collects information from meta data and creates a filename"""
# Handle "old" data
if meta_data.get("participant", None) is None:
raise ValueError(f"No proper meta data for this sample, please select filename manually")
# Collect the information
subject_info = {
"participant_id": meta_data.get("participant", {}).get("id", None),
"birth_date": meta_data.get("participant", {}).get("birth_date", None),
"sex": meta_data.get("participant", {}).get("sex", None),
"task_id": meta_data.get("task_id", None),
"admin": meta_data.get("administrator", None),
"created_on": meta_data.get("created_on", None)
}
# Collect the filename
file_name = ""
last_value = list(subject_info.values())[-1]
for value in subject_info.values():
if value:
file_name += f"{value}_" if value not in last_value else f"{value}"
# Return the filename
return file_name