handwriting-features

Module for the computation of the conventionally used handwriting features from online handwriting with an interface for the Featurizer API.

https://github.com/bdalab/handwriting-features

Science Score: 44.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
    Found CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
  • Committers with academic emails
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (12.4%) to scientific vocabulary

Keywords

handwriting-analysis handwriting-data handwriting-features python
Last synced: 6 months ago · JSON representation ·

Repository

Module for the computation of the conventionally used handwriting features from online handwriting with an interface for the Featurizer API.

Basic Info
Statistics
  • Stars: 12
  • Watchers: 0
  • Forks: 1
  • Open Issues: 7
  • Releases: 3
Topics
handwriting-analysis handwriting-data handwriting-features python
Created over 4 years ago · Last pushed 12 months ago
Metadata Files
Readme License Citation

README.md

Handwriting features

GitHub last commit GitHub issues GitHub code size in bytes PyPI - Python Version GitHub top language GitHub

This package provides a PyPi-installable easy-to-use modern library for the extraction of a variety of common handwriting features focused on the domain of kinematic, dynamic, spatial, and temporal analysis of online handwriting/drawing. It is built on top of the Handwriting sample package for easy class-based manipulation with online handwriting data.

It also provides an interface for the Featurizer API: 1. Server side (RESTful API for feature extraction via injected features extraction library) 2. Client side (lightweight client application)

The full programming sphinx-generated docs can be seen in the official documentation.

Contents: 1. Installation 2. Features 3. Usage 4. Interface 5. Examples 6. License 7. Contributors


Installation

pip install handwriting-features

Features

The following list of handwriting features is supported: 1. kinematic features 1. velocity 2. acceleration 3. jerk 2. dynamic features 1. azimuth 2. tilt 3. pressure 3. spatial features 1. stroke length 2. stroke height 3. stroke width 4. writing length 5. writing height 6. writing width 7. number of intra-stroke intersections 8. relative number of intra-stroke intersections 9. total number of intra-stroke intersections 10. relative total number of intra-stroke intersections 11. number of inter-stroke intersections 12. relative number of inter-stroke intersections 13. vertical peaks indices 14. vertical valleys indices 15. vertical peaks values 16. vertical valleys values 17. vertical peaks velocity 18. vertical valleys velocity 19. vertical peaks distance 20. vertical valleys distance 21. vertical peaks duration 22. vertical valleys duration 4. temporal features 1. stroke duration 2. ratio of stroke durations (on-surface / in-air strokes) 3. writing duration 4. writing duration overall 5. ratio of writing durations (on-surface / in-air writing) 6. number of interruptions 7. number of interruptions relative 5. composite features 1. writing tempo 2. writing stops 3. number of changes in x profile 4. number of changes in y profile 5. number of changes in azimuth 6. number of changes in tilt 7. number of changes in pressure 8. number of changes in velocity profile 9. relative number of changes in x profile 10. relative number of changes in y profile 11. relative number of changes in azimuth 12. relative number of changes in tilt 13. relative number of changes in pressure 14. relative number of changes in velocity profile

Usage

The main entry point and the class to be used for the computation of the handwriting features is named HandwritingFeatures. To compute the features, an instance of HandwritingFeatures must be created using valid handwriting data in the form of an instance of the wrapper on top of the HadwritingSample named HandwritingSampleWrapper. The HandwritingSample is a class for the manipulation with online handwriting data installed from this repository. The HandwritingSampleWrapper is used to enrich the HandwritingSample with the capabilities specific to the feature extraction.

To support alternative ways of instantiating the HandwritingFeatures from handwriting data stored in various data/file formats, the HandwritingFeatures provides the following alternative constructor methods: 1. for various data formats 1. from_list 2. from_numpy_array 3. from_pandas_dataframe 2. for various file formats 1. from_json 2. from_svc

After the HandwritingFeatures object is instantiated, the supported handwriting features can be computed using the following methods: 1. kinematic features 1. velocity 2. acceleration 3. jerk 2. dynamic features 1. azimuth 2. tilt 3. pressure 3. spatial features 1. stroke_length 2. stroke_height 3. stroke_width 4. writing_length 5. writing_height 6. writing_width 7. number_of_intra_stroke_intersections 8. relative_number_of_intra_stroke_intersections 9. total_number_of_intra_stroke_intersections 10. relative_total_number_of_intra_stroke_intersections 11. number_of_inter_stroke_intersections 12. relative_number_of_inter_stroke_intersections 13. vertical_peaks_indices 14. vertical_valleys_indices 15. vertical_peaks_values 16. vertical_valleys_values 17. vertical_peaks_velocity 18. vertical_valleys_velocity 19. vertical_peaks_distance 20. vertical_valleys_distance 21. vertical_peaks_duration 22. vertical_valleys_duration 4. temporal features 1. stroke_duration 2. ratio_of_stroke_durations 3. writing_duration 4. writing_duration_overall 5. ratio_of_writing_durations 6. number_of_interruptions 7. number_of_interruptions_relative 5. composite features 1. writing_tempo 2. writing_stops 3. number_of_changes_in_x_profile 4. number_of_changes_in_y_profile 5. number_of_changes_in_azimuth 6. number_of_changes_in_tilt 7. number_of_changes_in_pressure 8. number_of_changes_in_velocity_profile 9. relative_number_of_changes_in_x_profile 10. relative_number_of_changes_in_y_profile 11. relative_number_of_changes_in_azimuth 12. relative_number_of_changes_in_tilt 13. relative_number_of_changes_in_pressure 14. relative_number_of_changes_in_velocity_profile

For more information, see the Examples section.

Interface

Besides, the convenient use of the HandwritingFeatures interface class, the library also provides an interface for the Featurizer API at src/handwriting_features/interface/featurizer/. The Featurizer API supports the feature extraction from handwriting data of 1-M subjects given the pipeline of features. This offers an additional option to extract a variety of handwriting features via a micro-service type of architecture via injecting the handwriting features library into the API as the feature extractor to be used. For more information, see the official documentation of the Featurizer API.

Examples

The package comes with examples showing how to compute/plot the handwriting features. For this purpose, it also provides example data from a subset of 4 writers coming from the Parkinson's Disease Handwriting Database (PaHaW): 2 healthy controls (HC; 1 male, 1 female) and 2 patients with Parkinson's disease (PD; 1 male, 1 female).

For more information about the example data, see the info file at examples/data/info.json or visit the official website of Brain Diseases Analysis Laboratory.

1. compute handwriting features

```python import os from handwriting_features.features import HandwritingFeatures

Prepare the path to example data

datapath = os.path.join(os.path.dirname(os.path.realpath(file_)), "..", "data")

Prepare the subject group

subject_group = "HC-female"

subject_group = "HC-male"

subject_group = "PD-female"

subject_group = "PD-male"

Prepare the filename of the signal to be used

signalname = "00026w.cz.fnusa.1_1.svc"

Prepare the handwriting variables

variables = ["y", "x", "time", "pen_status", "azimuth", "tilt", "pressure"]

Instantiate the handwriting features object from an example signal

featurepath = str(os.path.join(datapath, subjectgroup, signalname)) featuredata = HandwritingFeatures.fromsvc(feature_path, variables)

Prepare the sampling frequency

fs = 133

Handwriting features:

1. Kinematic features

a) velocity

b) acceleration

c) jerk

2. Dynamic features

a) azimuth

b) tilt

c) pressure

3. Spatial features

a) stroke length

b) stroke height

c) stroke width

d) writing length

e) writing height

f) writing width

g) number of intra-stroke intersections

h) relative number of intra-stroke intersections

i) total number of intra-stroke intersections

j) relative total number of intra-stroke intersections

k) number of inter-stroke intersections

l) relative number of inter-stroke intersections

m) vertical peaks indices

n) vertical valleys indices

o) vertical peaks values

p) vertical valleys values

q) vertical peaks velocity

r) vertical valleys velocity

s) vertical peaks distance

t) vertical valleys distance

u) vertical peaks duration

v) vertical valleys duration

4. Temporal features

a) stroke duration

b) ratio of stroke durations (on-surface / in-air strokes)

c) writing duration

d) writing duration overall

e) ratio of writing durations (on-surface / in-air writing)

f) number of interruptions

g) number of interruptions_relative

5. Composite features

a) writing tempo

b) writing stops

c) number of changes in x profile

d) number of changes in y profile

e) number of changes in azimuth

f) number of changes in tilt

g) number of changes in pressure

h) number of changes in velocity profile

i) relative number of changes in x profile

j) relative number of changes in y profile

k) relative number of changes in azimuth

l) relative number of changes in tilt

m) relative number of changes in pressure

n) relative number of changes in velocity profile

1. Kinematic features

featuredata.velocity(axis="x", inair=False, statistics=["mean", "std"]) featuredata.acceleration(axis="y", inair=True, statistics=["median", "iqr"]) featuredata.jerk(axis="xy", inair=False)

2. Dynamic features

featuredata.azimuth(inair=False, statistics=["cvparametric"]) featuredata.tilt(inair=True, statistics=["cvnonparametric"]) feature_data.pressure(statistics=())

3. Spatial features

featuredata.strokelength(inair=False, statistics=["quartile1", "quartile3"]) featuredata.strokeheight(inair=True, statistics=["slopeoflinearregression"]) featuredata.strokewidth(inair=False, statistics=())

...

4. Temporal features

featuredata.strokeduration(inair=False, statistics=["percentile5", "percentile95"]) featuredata.ratioofstrokedurations(statistics=()) featuredata.writingduration(inair=True) featuredata.ratioofwritingdurations()

...

5. Composite features

featuredata.writingtempo(inair=False) featuredata.writing_stops(statistics=["mean", "std"])

...

```

2. plot handwriting features

```python import os import matplotlib.pyplot as plt from pprint import pprint from handwriting_features.features import HandwritingFeatures

Prepare the path to example data

datapath = os.path.join(os.path.dirname(os.path.realpath(file_)), "..", "data")

Prepare the subject group

subject_group = "HC-female"

subject_group = "HC-male"

subject_group = "PD-female"

subject_group = "PD-male"

Prepare the filename of the signal to be used

signalname = "00026w.cz.fnusa.1_1.svc"

Prepare the handwriting variables

variables = ["y", "x", "time", "pen_status", "azimuth", "tilt", "pressure"]

Instantiate the handwriting features object from an example signal

featurepath = str(os.path.join(datapath, subjectgroup, signalname)) featuredata = HandwritingFeatures.fromsvc(feature_path, variables)

Extract the loaded data (wrapped handwriting sample)

loadeddata = featuredata.wrapper

Prepare the sampling frequency

fs = 133

Handwriting features:

1. Kinematic features

a) velocity

b) acceleration

c) jerk

2. Dynamic features

a) azimuth

b) tilt

c) pressure

3. Spatial features

a) stroke length

b) stroke height

c) stroke width

d) writing length

e) writing height

f) writing width

g) number of intra-stroke intersections

h) relative number of intra-stroke intersections

i) total number of intra-stroke intersections

j) relative total number of intra-stroke intersections

k) number of inter-stroke intersections

l) relative number of inter-stroke intersections

m) vertical peaks indices

n) vertical valleys indices

o) vertical peaks values

p) vertical valleys values

q) vertical peaks velocity

r) vertical valleys velocity

s) vertical peaks distance

t) vertical valleys distance

u) vertical peaks duration

v) vertical valleys duration

4. Temporal features

a) stroke duration

b) ratio of stroke durations (on-surface / in-air strokes)

c) writing duration

d) writing duration overall

e) ratio of writing durations (on-surface / in-air writing)

f) number of interruptions

g) number of interruptions_relative

5. Composite features

a) writing tempo

b) writing stops

c) number of changes in x profile

d) number of changes in y profile

e) number of changes in azimuth

f) number of changes in tilt

g) number of changes in pressure

h) number of changes in velocity profile

i) relative number of changes in x profile

j) relative number of changes in y profile

k) relative number of changes in azimuth

l) relative number of changes in tilt

m) relative number of changes in pressure

n) relative number of changes in velocity profile

Prepare the features computation

axis = "x" in_air = False statistics = ()

1. Compute the kinematic features

feature = featuredata.velocity(axis=axis, inair=in_air, statistics=statistics)

feature = featuredata.acceleration(axis=axis, inair=in_air, statistics=statistics)

feature = featuredata.jerk(axis=axis, inair=in_air, statistics=statistics)

2. Compute the dynamic features

feature = featuredata.azimuth(inair=in_air, statistics=statistics)

feature = featuredata.tilt(inair=in_air, statistics=statistics)

feature = feature_data.pressure(statistics=statistics)

3. Compute the spatial features

feature = featuredata.strokelength(inair=inair, statistics=statistics)

feature = featuredata.strokeheight(inair=inair, statistics=statistics)

feature = featuredata.strokewidth(inair=inair, statistics=statistics)

...

4. Compute the temporal features

feature = featuredata.strokeduration(inair=inair, statistics=statistics)

feature = featuredata.ratioofstrokedurations(statistics=statistics)

feature = featuredata.writingduration(inair=inair)

feature = featuredata.ratioofwritingdurations()

...

5. Compute the composite features

featuredata.writingtempo(in_air=False)

featuredata.writingstops(statistics=["mean", "std"])

...

pprint(feature)

Plot the original data and the computed feature

if not statistics:

fig = plt.figure(figsize=(16, 10))

# Plot the original data
ax = fig.add_subplot(1, 2, 1)
ax.plot(loaded_data.sample_x, loaded_data.sample_y, "-", color="blue", linewidth=2, alpha=0.7)
ax.yaxis.grid(True)
ax.xaxis.grid(True)

# Plot the original data
ax = fig.add_subplot(1, 2, 2)
ax.plot(feature, "-", color="red", linewidth=2, alpha=0.7)
ax.yaxis.grid(True)
ax.xaxis.grid(True)

# Adjust the figure
fig.tight_layout()

# Store the graphs
# plt.savefig(f"{signal_name}.pdf", bbox_inches="tight")

# Show the graphs
plt.get_current_fig_manager().window.state("zoomed")
plt.show()

```

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributors

This package is developed by the members of Brain Diseases Analysis Laboratory. For more information, please contact the head of the laboratory Jiri Mekyska mekyska@vut.cz or the main developer: Zoltan Galaz galaz@vut.cz.

Owner

  • Name: Brain Diseases Analysis Laboratory
  • Login: BDALab
  • Kind: organization
  • Email: mekyska@vut.cz
  • Location: Brno, Czech Republic

BDALab is an international multidisciplinary research group focusing on the objective and quantitative analysis of brain diseases.

Citation (CITATION.cff)

cff-version: 1.9.0
message: "If you use this software, please cite it as below."
authors:
- family-names: "Galaz"
  given-names: "Zoltan"
  orcid: "https://orcid.org/0000-0002-8978-351X"
- family-names: "Mucha"
  given-names: "Jan"
  orcid: "https://orcid.org/0000-0001-5126-440X"
- family-names: "Zvoncak"
  given-names: "Vojtech"
  orcid: "https://orcid.org/0000-0002-1948-4653"
- family-names: "Mekyska"
  given-names: "Jiri"
  orcid: "https://orcid.org/0000-0002-6195-193X"
title: "Handwriting features"
version: 1.0.9
date-released: 2025-3-18
url: "https://github.com/BDALab/handwriting-features/"

GitHub Events

Total
  • Watch event: 3
  • Push event: 3
  • Pull request event: 1
  • Create event: 1
Last Year
  • Watch event: 3
  • Push event: 3
  • Pull request event: 1
  • Create event: 1

Committers

Last synced: almost 3 years ago

All Time
  • Total Commits: 44
  • Total Committers: 3
  • Avg Commits per committer: 14.667
  • Development Distribution Score (DDS): 0.5
Top Committers
Name Email Commits
Zoltán Galáž z****n@g****u 22
Zoltán Galáž x****0@g****m 20
ZvoV v****k@g****m 2
Committer Domains (Top 20 + Academic)

Issues and Pull Requests

Last synced: 6 months ago

All Time
  • Total issues: 0
  • Total pull requests: 8
  • Average time to close issues: N/A
  • Average time to close pull requests: N/A
  • Total issue authors: 0
  • Total pull request authors: 1
  • Average comments per issue: 0
  • Average comments per pull request: 0.0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 0
  • Pull requests: 2
  • Average time to close issues: N/A
  • Average time to close pull requests: N/A
  • Issue authors: 0
  • Pull request authors: 1
  • Average comments per issue: 0
  • Average comments per pull request: 0.0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
Pull Request Authors
  • zgalaz (10)
Top Labels
Issue Labels
Pull Request Labels

Packages

  • Total packages: 1
  • Total downloads:
    • pypi 33 last-month
  • Total dependent packages: 1
  • Total dependent repositories: 1
  • Total versions: 10
  • Total maintainers: 1
pypi.org: handwriting-features

Handwriting features

  • Versions: 10
  • Dependent Packages: 1
  • Dependent Repositories: 1
  • Downloads: 33 Last month
Rankings
Dependent packages count: 4.8%
Average: 17.6%
Stargazers count: 18.5%
Downloads: 20.6%
Dependent repos count: 21.5%
Forks count: 22.6%
Maintainers (1)
Last synced: 6 months ago

Dependencies

docs/requirements.txt pypi
  • handwriting-sample *
  • numpy *
  • pandas *
setup.py pypi