diff --git a/.github/workflows/deply_docs.yml b/.github/workflows/deply_docs.yml index 1d81c1e..028630d 100644 --- a/.github/workflows/deply_docs.yml +++ b/.github/workflows/deply_docs.yml @@ -3,6 +3,9 @@ name: Deploy Documentation on: push: branches: [ main ] + paths: + - 'docs/**' + - '.github/workflows/deply_docs.yml' permissions: contents: write diff --git a/docs/source/introduction.rst b/docs/source/introduction.rst index f8640f6..213c052 100644 --- a/docs/source/introduction.rst +++ b/docs/source/introduction.rst @@ -7,7 +7,36 @@ This project aims to analyze user interaction with web applications by processin It provides tools to compute various interaction related metrics (like velocity, acceleration, auc, etc.) and other useful functionalities to facilitate the analysis of user behavior, such as stroke visualization or video generation of user sessions. +Rationale +============= +... +The analyisis of mouse interaction has been widely used in HCI to infer in several aspects of the users interaction with the system. +This mouse dynamics have been proven useful for analysing bheavioral patterns :cite:p:`Katerina2018-ch,Cepeda2018-kn`, +cognitive and physicial conditions affecting the user :cite:p:`Seelye2015-yxm, Khan2008-is, Rhim2023-uz` +or even for user identification :cite:p:`Karim2020-ss` and authentication :cite:p:`Monrose-2000-oc`. + +One could enumerate hundreads of research works in this field that have analyzed mouse interaction data to extract meaningful insights about user behavior. +However, there is a lack of dedicated tools and libraries to facilitate this analysis, which is a gap that **pywib** aims to address. + +As of 2026, there are no other Python libraries specifically designed for analyzing web interaction behavior in HCI research. +While there are libraries for this same purpose in other programming languages, such as R's `mousemove` :cite:p:`Wulff2025-bt`, +they may not be as accessible to researchers who primarily use Python for data analysis and machine learning tasks, limiting as well +the integration with other Python-based tools and libraries commonly used in HCI research or the automation of analysis pipelines using Python based APIs. + +Validity of Metrics +-------------------- +One of the main problems when dealing with a library that aims to cover computation of, at most, the most common metrics in HCI research is the validity of such ones. +For this reason, **pywib** has been developed taking into account the most relevant metrics used in research works, that have been proven to be representative of user behavior in different contexts. +This does not mean that the developer team will not expand the library with new metrics in the future, if there is a given need for them, but rather that the initial set of metrics that have been included are those that could be initialy proven to be mathematically and experimentally valid. + +Context Specific Metrics +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It is important to note that not all metrics are equally valid in all contexts. +For example, metrics that are valid for analyzing mouse movements in a desktop web application may not be valid for analyzing touch interactions on mobile devices. +Therefore, it is crucial to consider the context in which the metrics will be applied and to validate them accordingly. + +Moreover, the setup of an experiment itself can influence the validity of certain metrics :cite:p:`Schoemann2019-vv,Kuric2024-wc`, which is why **pywib** encourages users to validate the metrics they compute in their specific context and experiment setup. Installation ------------- @@ -32,3 +61,9 @@ Small Example v = velocity(df_all_sessions) v_metrics = velocity_metrics(None, v) + +References +============= + +.. bibliography:: references.bib + :style: apa \ No newline at end of file diff --git a/docs/source/references.bib b/docs/source/references.bib index f7ccb6a..b3c242f 100644 --- a/docs/source/references.bib +++ b/docs/source/references.bib @@ -391,3 +391,116 @@ @ARTICLE{Vizer2009-sg @phdthesis{Dijkstra_2013, title={The diagnosis of self-efficacy using mouse and keyboard input}, author={Dijkstra, Maarten}, year={2013}, school={Utrecht University} } + +@ARTICLE{Kuric2024-wc, + title = "Is mouse dynamics information credible for user behavior + research? An empirical investigation", + author = "Kuric, Eduard and Demcak, Peter and Krajcovic, Matus and Nemcek, + Peter", + journal = "Comput. Stand. Interfaces", + publisher = "Elsevier BV", + volume = 90, + number = 103849, + pages = "103849", + month = aug, + year = 2024, + copyright = "http://creativecommons.org/licenses/by/4.0/", + language = "en" +} + +@ARTICLE{Wulff2025-bt, + title = "Movement tracking of psychological processes: A tutorial using + mousetrap", + author = "Wulff, Dirk U and Kieslich, Pascal J and Henninger, Felix and + Haslbeck, Jonas M B and Schulte-Mecklenbeck, Michael", + abstract = "Movement tracking is a novel process-tracing method that + promises unique access to the temporal dynamics of psychological + processes. The method involves high-resolution tracking of a + hand or handheld device (e.g., a computer mouse) while it is + used to make a choice. In contrast to other process-tracing + methods, which mostly focus on information acquisition, movement + tracking focuses on the processes of information integration and + preference formation. In this article, we present a tutorial on + movement tracking of psychological processes with the mousetrap + R package. We address all steps of the research process, from + design to interpretation, with a particular focus on data + processing and analysis and featuring both established and novel + approaches. Using a representative working example, we + demonstrate how the various steps of movement-tracking analysis + can be implemented with mousetrap and provide thorough + explanations of their theoretical background and interpretation. + Finally, we present a list of recommendations to assist + researchers in addressing their own research questions using + movement tracking of psychological processes.", + journal = "Behav. Res. Methods", + publisher = "Springer Science and Business Media LLC", + volume = 57, + number = 11, + pages = "307", + month = oct, + year = 2025, + keywords = "Cognitive processes; Decision making; Movement tracking; Process + tracing", + copyright = "https://creativecommons.org/licenses/by/4.0", + language = "en" +} + +@ARTICLE{Schoemann2019-vv, + title = "Validating mouse-tracking: How design factors influence action + dynamics in intertemporal decision making", + author = "Schoemann, Martin and L{\"u}ken, Malte and Grage, Tobias and + Kieslich, Pascal J and Scherbaum, Stefan", + abstract = "Mouse-tracking is an increasingly popular process-tracing + method. It builds on the assumption that the continuity of + cognitive processing leaks into the continuity of mouse + movements. Because this assumption is the prerequisite for + meaningful reverse inference, it is an important question + whether the assumed interaction between continuous processing + and movement might be influenced by the methodological setup of + the measurement. Here we studied the impacts of three commonly + occurring methodological variations on the quality of + mouse-tracking measures, and hence, on the reported cognitive + effects. We used a mouse-tracking version of a classical + intertemporal choice task that had previously been used to + examine the dynamics of temporal discounting and the date-delay + effect (Dshemuchadse, Scherbaum, \& Goschke, 2013). The data + from this previous study also served as a benchmark condition in + our experimental design. Between studies, we varied the starting + procedure. Within the new study, we varied the response + procedure and the stimulus position. The starting procedure had + the strongest influence on common mouse-tracking measures, and + therefore on the cognitive effects. The effects of the response + procedure and the stimulus position were weaker and less + pronounced. The results suggest that the methodological setup + crucially influences the interaction between continuous + processing and mouse movement. We conclude that the + methodological setup is of high importance for the validity of + mouse-tracking as a process-tracing method. Finally, we discuss + the need for standardized mouse-tracking setups, for which we + provide recommendations, and present two promising lines of + research toward obtaining an evidence-based gold standard of + mouse-tracking.", + journal = "Behav. Res. Methods", + publisher = "Springer Science and Business Media LLC", + volume = 51, + number = 5, + pages = "2356--2377", + month = oct, + year = 2019, + keywords = "Action dynamics; Boundary conditions; Intertemporal choice; + Mouse-tracking; Process-tracing", + language = "en" +} + +@ARTICLE{Karim2020-ss, + title = "A study on mouse movement features to identify user", + author = "Karim, Masud and Hasanuzzaman, Md", + journal = "Sci. Res. J.", + publisher = "Scientific Research Journal SCIRJ", + volume = 08, + number = 04, + pages = "77--82", + month = apr, + year = 2020 +} + diff --git a/src/pywib/core/keyboard.py b/src/pywib/core/keyboard.py index afd9c6b..d097863 100644 --- a/src/pywib/core/keyboard.py +++ b/src/pywib/core/keyboard.py @@ -8,7 +8,7 @@ import numpy as np from pywib.utils.segmentation import extract_keystroke_traces_by_session from pywib.utils.validation import validate_dataframe_keyboard -from pywib.constants import EventTypes, ColumnNames, KeyCodeEvents +from pywib.constants import EventTypes, ColumnNames from pywib.utils.keyboard import (backspace_usage_df, backspace_usage_traces, typing_durations_df, typing_durations_traces, typing_speed_df, typing_speed_traces) def typing_durations(df: pd.DataFrame = None, traces: dict[str, list[pd.DataFrame]] = None, per_traces: bool = True) -> list: diff --git a/src/pywib/core/movement.py b/src/pywib/core/movement.py index fd8908b..fdf176f 100644 --- a/src/pywib/core/movement.py +++ b/src/pywib/core/movement.py @@ -8,7 +8,7 @@ auc_ratio_traces, auc_ratio_df) from pywib.constants import ColumnNames -def velocity(df: pd.DataFrame = None, traces: dict[str, list[pd.DataFrame]] = None, per_traces: bool = False) -> dict[str, list[pd.DataFrame]]: +def velocity(df: pd.DataFrame = None, traces: dict[str, list[pd.DataFrame]] = None, per_traces: bool = False, parallel:bool = False, n_jobs: int = 2) -> dict[str, list[pd.DataFrame]]: """ Function to calculate velocity for either a single DataFrame or a traces dictionary. @@ -34,6 +34,10 @@ def velocity(df: pd.DataFrame = None, traces: dict[str, list[pd.DataFrame]] = No validate_dataframe(df) traces = extract_traces_by_session(df) + if parallel: + # Compute velocity for each trace in parallel + return velocity_traces_parallel(traces, n_jobs=n_jobs) + # Compute velocity for each trace return velocity_traces(traces) diff --git a/src/pywib/utils/keyboard.py b/src/pywib/utils/keyboard.py index b1ac9fb..fa24c7a 100644 --- a/src/pywib/utils/keyboard.py +++ b/src/pywib/utils/keyboard.py @@ -1,6 +1,5 @@ import pandas as pd -import numpy as np from pywib.constants import ColumnNames, EventTypes, KeyCodeEvents from pywib.utils.validation import validate_dataframe_keyboard diff --git a/src/pywib/utils/movement.py b/src/pywib/utils/movement.py index 758578a..44775b3 100644 --- a/src/pywib/utils/movement.py +++ b/src/pywib/utils/movement.py @@ -37,7 +37,29 @@ def velocity_traces(traces: dict[str, list[pd.DataFrame]]) -> dict[str, list[pd. traces[session_id] = session_traces return traces -import pandas as pd +def velocity_traces_parallel(traces: dict[str, list[pd.DataFrame]], n_jobs: int = 2) -> dict[str, list[pd.DataFrame]]: + """ + Calculate velocity for a dictionary of traces (each a list of DataFrames) in parallel. + + Parameters: + traces (dict[str, list[pd.DataFrame]]): Mapping of sessionId to list of DataFrames. + n_jobs (int): Number of parallel jobs. + + Returns: + dict[str, list[pd.DataFrame]]: Same structure, but with velocity computed in each DataFrame. + """ + from joblib import Parallel, delayed + + def compute_velocity_for_trace(df): + validate_dataframe(df) + return velocity_df(df) + + for session_id, session_traces in traces.items(): + session_traces = Parallel(n_jobs=n_jobs)( + delayed(compute_velocity_for_trace)(df) for df in session_traces + ) + traces[session_id] = session_traces + return traces def acceleration_df(df: pd.DataFrame) -> pd.DataFrame: """