handwriting-features
Module for the computation of the conventionally used handwriting features from online handwriting with an interface for the Featurizer API.
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
Repository
Module for the computation of the conventionally used handwriting features from online handwriting with an interface for the Featurizer API.
Basic Info
- Host: GitHub
- Owner: BDALab
- License: mit
- Language: Python
- Default Branch: main
- Homepage: https://handwriting-features.readthedocs.io/en/latest/
- Size: 993 KB
Statistics
- Stars: 12
- Watchers: 0
- Forks: 1
- Open Issues: 7
- Releases: 3
Topics
Metadata Files
README.md
Handwriting features
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
- Website: https://bdalab.utko.feec.vutbr.cz/
- Twitter: BDALab_
- Repositories: 5
- Profile: https://github.com/BDALab
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 | 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
- Homepage: https://github.com/BDALab/handwriting-features
- Documentation: https://handwriting-features.readthedocs.io/
- License: MIT
-
Latest release: 1.0.9
published 12 months ago
Rankings
Maintainers (1)
Dependencies
- handwriting-sample *
- numpy *
- pandas *