XplainClient Enhancements
The enhanced XplainClient improves usability for relative time dimensions and sequence analysis operations through better parameter handling, convenience methods, and client-side validation.
Note
The enhanced client is available as xplain.session_client_enhanced.XplainClient and is fully backward compatible with the standard XplainClient.
Quick Start
Import the enhanced client:
from xplain import Xsession
from xplain.session_client_enhanced import XplainClient
from xplain.relative_time_helpers import TimeUnit, RelativeTimeType
s = Xsession(...)
client = XplainClient(s)
Key Features
1. Tuple and String Dimension Paths
Use concise tuple or string format instead of verbose dicts:
# Old (verbose)
client.add_relative_time_dimensions(
time_dimensions=[{"object": "Prescriptions", "dimension": "Date"}],
reference_time_dimension={"object": "Diagnoses", "dimension": "DiagDate"},
)
# New (concise)
client.add_relative_time_dimensions(
time_dimensions=[("Prescriptions", "Date")],
reference_time_dimension=("Diagnoses", "DiagDate"),
)
# Also works with strings
client.add_relative_time_dimensions(
time_dimensions=["Prescriptions.Date"],
reference_time_dimension="Diagnoses.DiagDate",
)
2. Enum Constants with IDE Autocomplete
Use constants that provide IDE guidance:
from xplain.relative_time_helpers import TimeUnit, RelativeTimeType
# IDE autocomplete guides valid values
client.calculate_time_since(
event_dimension=("Prescriptions", "Date"),
reference=("Diagnoses", "DiagDate"),
name="DaysSinceDiag",
since=RelativeTimeType.TO_FIRST, # or use "first"
unit=TimeUnit.DAY,
)
3. Convenience Method: calculate_time_since()
Simplified relative time dimension creation with intuitive parameters:
# Creates days since first diagnosis for prescriptions
client.calculate_time_since(
event_dimension=("Prescriptions", "Date"),
reference=("Diagnoses", "DiagDate"),
name="DaysSinceDiag",
since="first", # or "last", "nearest", "next", "previous"
unit=TimeUnit.DAY,
base_object="Patients",
)
4. Client-Side Validation
Fail fast with clear error messages before server round-trip:
# Invalid enum value → immediate error
try:
client.add_relative_time_dimensions(
time_dimensions=[("Prescriptions", "Date")],
reference_time_dimension=("Diagnoses", "DiagDate"),
time_unit="INVALID", # Not valid!
)
except ValueError as e:
print(e) # "Invalid time_unit: 'INVALID'. Must be one of {...}"
# Mismatched parameters → caught immediately
try:
client.add_relative_time_dimensions(
time_dimensions=[dim1, dim2],
names=["OnlyOne"], # Should have 2 names!
)
except ValueError as e:
print(e) # "names cardinality mismatch..."
Relative Time Dimensions
Enhanced add_relative_time_dimensions() with tuple/string support:
from xplain.relative_time_helpers import TimeUnit, RelativeTimeType
# Measure time of prescriptions relative to first diagnosis
client.add_relative_time_dimensions(
time_dimensions=[("Prescriptions", "Date")],
reference_time_dimension=("Diagnoses", "DiagDate"),
base_object="Patients",
relative_time_type=RelativeTimeType.TO_FIRST,
names=["DaysSinceFirstDiag"],
time_unit=TimeUnit.DAY,
)
Reference Types
The relative_time_type parameter controls which event becomes the zero point:
TO_FIRST— Time relative to the first matching reference eventTO_LAST— Time relative to the last matching reference eventTO_NEAREST— Time relative to the nearest reference event (either direction)TO_NEXT— Time relative to the next (future) reference eventTO_PREVIOUS— Time relative to the previous (past) reference event
Time Units
- TimeUnit
Available time units for relative time calculations:
NANOSECOND,MILLISECOND,SECONDMINUTE,HOUR,DAY,WEEKMONTH,QUARTER,HALFYEAR,YEARDECADE,CENTURY
Examples
Days since first hospitalization:
client.calculate_time_since(
event_dimension=("Hospitalizations", "DateFrom"),
reference=("Hospitalizations", "DateFrom"),
name="DaysSinceFirstHosp",
since="first",
unit=TimeUnit.DAY,
base_object="Patients",
)
Months until next visit (calendar-based):
client.calculate_time_since(
event_dimension=("Visits", "ScheduledDate"),
reference=("Visits", "ActualDate"),
name="MonthsUntilNextVisit",
since="next",
unit=TimeUnit.MONTH,
calendar_based=True,
)
Hours to nearest lab result:
client.calculate_time_since(
event_dimension=("LabResults", "Time"),
reference=("Treatments", "StartTime"),
name="HoursToNearestLab",
since="nearest",
unit=TimeUnit.HOUR,
)
Sequence Operations
Enhanced build_sorted_sequence() with tuple/string support:
# Rank prescriptions by date
client.build_sorted_sequence(
base_object="Patients",
target_object="Patients",
sort_dimension=("Prescriptions", "Date"), # tuple format
dimensions_to_replicate=[("Prescriptions", "PZN")],
ranks=[1, 2, 3],
names=[["1st Rx", "2nd Rx", "3rd Rx"]],
)
# Or open directly for analysis
client.open_sequence(
sequence_names=["RxJourney"],
base_object="Patients",
sort_dimension=("Prescriptions", "Date"),
dimensions_to_replicate=[("Prescriptions", "PZN")],
ranks=[1, 2, 3],
names=[["1st Rx", "2nd Rx", "3rd Rx"]],
open_marginal_queries=True,
)
Helper Modules
Constants and validation utilities for relative time operations.
The Enhanced XplainClient Class
- class xplain.session_client_enhanced.XplainClient(xsession)
Bases:
xplain.session_client.XplainClientEnhanced XplainClient with improved UX for longitudinal analysis.
- Extends the auto-generated XplainClient with:
Tuple/string support for dimension paths (via normalize_element_path)
Convenience methods for common workflows
Client-side validation with better error messages
Enum constants for valid string values
- Parameters
xsession (Xsession) –
- Return type
None
Relative Time Methods
- XplainClient.add_relative_time_dimensions(reference_time_dimension, time_dimensions=None, interval_end_time_dimension=None, base_object=None, relative_time_type=None, names=None, reference_event_selections=None, fix_explicit_selections=None, time_unit=None, calendar_based=False, cache_reference_time=False, selection_set=None, floating_semantics=None)
Construct relative time dimension(s) based on reference events.
- Enhanced version with:
Tuple and string support for dimension paths
Client-side validation
Better error messages
- Parameters
reference_time_dimension (Union[Dict, Tuple, str]) – XElementPath (dict, tuple, or “object.dimension”)
time_dimensions (Optional[Union[List[Dict], List[Tuple], List[str]]]) – List of XElementPath (dict, tuple, or string format)
interval_end_time_dimension (Optional[Union[Dict, Tuple, str]]) – XElementPath for interval coding
base_object (str) – Base object name for the relative time axis
relative_time_type (str) – TO_FIRST|TO_LAST|TO_NEAREST|TO_NEXT|TO_PREVIOUS
names (List[str]) – Names for new relative time dimensions
reference_event_selections (List) – Selections defining the reference event
fix_explicit_selections (str) – none|all|only_propagate_upward
time_unit (str) – DAY|WEEK|MONTH|YEAR|HOUR|… (see TimeUnit)
calendar_based (bool) – Use calendar-based time differences (default False)
cache_reference_time (bool) – Enable caching (default False)
selection_set (str) – Selection set for floating semantics
floating_semantics (bool) – DEPRECATED (use selection_set instead)
- Returns
Session state after the operation
- Raises
ValueError – If parameter combinations are invalid
TypeError – If dimension paths have invalid format
- Return type
dict
- XplainClient.calculate_time_since(event_dimension, reference, name, since='first', unit='DAY', base_object=None, reference_filter=None, calendar_based=False, **kwargs)
Calculate time of events relative to a reference event (convenience method).
Simplifies the common case of measuring time since/until a reference event. This is a high-level wrapper around add_relative_time_dimensions().
- Parameters
event_dimension (Union[Dict, Tuple, str]) – Dimension to measure relative time for (tuple/dict/string)
reference (Union[Dict, Tuple, str]) – Reference event dimension (tuple/dict/string)
name (str) – Name for the new relative time dimension
since (str) –
Which event to use as zero point. Options:
”first” (default): first matching reference event
”last”: last matching reference event
”nearest”: nearest reference event (in either direction)
”next”: next (future) reference event
”previous”: previous (past) reference event
unit (str) – Time unit (default: DAY). See TimeUnit for all options.
base_object (str) – Base object for the relative time axis
reference_filter (List) – Selections defining which event is the reference
calendar_based (bool) – Use calendar-based time differences (default False)
**kwargs – Pass-through for advanced parameters
- Returns
Session state after the operation
- Return type
dict
Examples
Days since first hospitalization for all prescriptions:
client.calculate_time_since( event_dimension=("Prescriptions", "Date"), reference=("Hospitalizations", "DateFrom"), name="DaysSinceFirstHosp", since="first", unit=TimeUnit.DAY, base_object="Patients", )
- Raises
ValueError – If ‘since’ value is invalid
- Parameters
event_dimension (Union[Dict, Tuple, str]) –
reference (Union[Dict, Tuple, str]) –
name (str) –
since (str) –
unit (str) –
base_object (str) –
reference_filter (List) –
calendar_based (bool) –
- Return type
dict
- XplainClient.remove_relative_time_dimensions(names, base_object=None)
Remove multiple relative time dimensions (batch cleanup).
Convenience for cleaning up temporary dimensions created by add_relative_time_dimensions() in bulk.
- Parameters
names (List[str]) – List of dimension names to remove
base_object (str) – Base object containing the dimensions (tries all known objects if not specified)
- Return type
None
Sequence Methods
- XplainClient.build_sorted_sequence(target_object=None, ranks=None, reverse=False, names=None, name_postfixes=None, dimensions_to_replicate=None, sort_dimension=None, base_object=None, zero_point_dimension=None, selections=None, fix_explicit_selections=None, selection_set=None, selection_set_defining_rank=None, floating_semantics=None, attributes_to_copy=None, sequence_names=None, rank_dimension_name=None, rank_zero_is_first_instance_equal_or_greater_zero_point=False, transition_attribute=None, only_segment_starts=False, transition_level=1)
Build a sorted sequence from time-ordered events (enhanced).
- Enhanced version with:
Tuple and string support for dimension paths
Client-side validation
Better error messages
All parameters as in the parent XplainClient class.
- Parameters
target_object (str) –
ranks (list) –
reverse (bool) –
names (list) –
name_postfixes (list) –
dimensions_to_replicate (list) –
sort_dimension (Optional[Union[Dict, Tuple, str]]) –
base_object (str) –
zero_point_dimension (Optional[Union[Dict, Tuple, str]]) –
selections (list) –
fix_explicit_selections (str) –
selection_set (str) –
selection_set_defining_rank (str) –
floating_semantics (bool) –
attributes_to_copy (list) –
sequence_names (list) –
rank_dimension_name (str) –
rank_zero_is_first_instance_equal_or_greater_zero_point (bool) –
transition_attribute (Optional[Union[Dict, Tuple, str]]) –
only_segment_starts (bool) –
transition_level (int) –
- Return type
dict
- XplainClient.open_sequence(sequence_names, dimensions_to_replicate=None, sort_dimension=None, ranks=None, target_object=None, base_object=None, zero_point_dimension=None, reverse=False, names=None, name_postfixes=None, selections=None, fix_explicit_selections=None, selection_set=None, selection_set_defining_rank=None, floating_semantics=None, rank_dimension_name=None, rank_zero_is_first_instance_equal_or_greater_zero_point=False, attributes_to_copy=None, transition_attribute=None, only_segment_starts=False, transition_level=1, open_marginal_queries=True, open_transition_queries=False)
Open a sequence for interactive exploration
Open a previously built sequence in the session for interactive analysis. The opened sequence computes and returns aggregated sequence results. Accepts all parameters of buildSortedSequence combined with those of openSequenceQueries.
- Parameters
sequence_names (list) – Names of the sequences to build and immediately open.
dimensions_to_replicate (list, optional) – The dimensions which should be replicated (“unfolded” in time). Those need to be from the same source object. XElementPath
sort_dimension (dict, optional) – The dimension which defines the sorting (typically a time dimension, but could be any numeric dimension). XElementPath
ranks (list, optional) – The ranks of the new dimension (position when sorted according to sortDimension).
target_object (str, optional) – Name of the target object (optional - if not given the root object is assumed, or guessed otherwise). In case of a RankDimension this parameter is irrelevant. (The object of the sortDimension is used.)
base_object (str, optional) – The embracing object within which events are sorted (if not given the target object is assumed if this not in a different object branch, otherwise the root object).
zero_point_dimension (dict, optional) – An optional dimension relative to which the sorting / ranking is done. XElementPath
reverse (bool, optional, default=False) – For the case of reverse sorting / counting.
names (list, optional) – Names of the new dimensions - if not given a name will be generated. There needs to be one array of names for each dimensionToReplicate, and each array needs to be of same size as the number of given ranks (or a null array).
name_postfixes (list, optional) – When given instead of names, the names will be generated based on those post-fixes.
selections (list, optional) – The set of selections that will be applied as the “where” clause to the to be sorted/ranked events. SelectionUIModel
fix_explicit_selections (str, optional) – This parameter may have one of the three values “none” (the default), “all” or “only_propagate_upward”. See buildSortedSequence for full description. One of:
none,all,only_propagate_upward.selection_set (str, optional) – If specified, the selections from the given set will be used as the selections, thereby implementing a “floating semantics” concept.
selection_set_defining_rank (str, optional) – An old deprecated parameter which may be used instead of selectionSet.
floating_semantics (bool, optional) – Deprecated. If false when a selectionSet is specified, the current selections are copied and kept fixed.
rank_dimension_name (str, optional) – If this parameter is given, an additional “rank dimension” is added to the source object (the object where the dimensionsToReplicate come from), which assigns a number (the rank) to each instance.
rank_zero_is_first_instance_equal_or_greater_zero_point (bool, optional, default=False) – If true this means that the first instance in the array of sorted instances which is >= zero point receives the rank 0.
attributes_to_copy (list, optional) – A list of attribute names amongst the attributes attached to the dimensionsToReplicate which are copied to the new dimensions. If not given all attributes will be copied.
transition_attribute (dict, optional) – If non-null, only the transitions will be coded in the sequence, i.e. only if the value of this attribute on the given transitionLevel changes a new entry in the ranked sequence is made. XElementPath
only_segment_starts (bool, optional, default=False) – If set to true, only the first occurrence of a segment is assigned a rank, i.e. only if a new value of the transitionAttribute appears, whereby new is defined by the transitionLevel.
transition_level (int, optional, default=1) – See the parameter transitionAttribute: the hierarchy level of the attribute which is used to detect transitions.
open_marginal_queries (bool, optional, default=True) – If true, queries for the marginal distributions for each sequence step will be opened (one-dimensional).
open_transition_queries (bool, optional, default=False) – If true, queries which describe the transitions between each step will be opened (two-dimensional).
- Returns
The session state after the operation.
- Return type
dict
Migration Guide
From Standard to Enhanced Client
The enhanced client is a drop-in replacement:
# Before
from xplain.session_client import XplainClient
client = XplainClient(session)
# After (with new features)
from xplain.session_client_enhanced import XplainClient
client = XplainClient(session)
All existing code continues to work. New code can use the convenience methods and shorter syntax.
From Old Xplainapi to Enhanced Client
The enhanced client maintains compatibility with the old Xplainapi style:
# Old Xplainapi (deprecated)
from xplainapi import Xplainapi
xapi = Xplainapi(...)
xapi.build_sorted_sequence(
dimensions_to_replicate=[("Prescriptions", "Rx PCN")],
sort_dimension=("Prescriptions", "Rx Order date"),
)
# New Enhanced Client (recommended)
from xplain import Xsession
from xplain.session_client_enhanced import XplainClient
s = Xsession(...)
client = XplainClient(s)
client.build_sorted_sequence(
dimensions_to_replicate=[("Prescriptions", "Rx PCN")],
sort_dimension=("Prescriptions", "Rx Order date"),
)
Backward Compatibility
✓ Old dict syntax still works:
# Dict format (always supported)
client.add_relative_time_dimensions(
time_dimensions=[{"object": "Prescriptions", "dimension": "Date"}],
reference_time_dimension={"object": "Diagnoses", "dimension": "DiagDate"},
)
✓ Can mix styles:
# Mix tuple and dict formats in same session
client.add_relative_time_dimensions(
time_dimensions=[("Prescriptions", "Date")], # tuple
reference_time_dimension={"object": "Diagnoses", "dimension": "DiagDate"}, # dict
)
Performance
Client-side validation adds minimal overhead:
Enum validation: O(1) set membership checks
Cardinality checks: O(n) list length comparisons
All validation runs before sending to server
Validation prevents unnecessary server round-trips for obviously incorrect parameters.
Testing
The enhancements are thoroughly tested:
# Run all enhancement tests
pytest test/xoedevtest/openapi_client/test_session_client_10_enhanced_relatives.py -v
# Helper functions only (no server required)
pytest test/xoedevtest/openapi_client/test_session_client_10_enhanced_relatives.py::TestHelperFunctions -v
See IMPLEMENTATION_SUMMARY.md in the docs/ directory for detailed test results.
Additional Resources
For more detailed analysis and recommendations, see the following markdown documents
in the docs/ directory:
relative_time_dimensions_analysis.md — Complete analysis of relative time API
build_sorted_sequence_analysis.md — Analysis of sequence operations
IMPLEMENTATION_SUMMARY.md — Implementation details and test results
ENHANCEMENTS_README.md — User guide with examples
Troubleshooting
ValueError: Invalid time_unit
The time unit is not recognized. Use constants from TimeUnit:
from xplain.relative_time_helpers import TimeUnit
client.calculate_time_since(..., unit=TimeUnit.DAY)
ValueError: cardinality mismatch
The number of names doesn’t match the number of dimensions. Each dimension needs a corresponding name:
# Wrong
client.add_relative_time_dimensions(
time_dimensions=[dim1, dim2],
names=["OnlyOne"], # 2 dimensions, 1 name
)
# Correct
client.add_relative_time_dimensions(
time_dimensions=[dim1, dim2],
names=["Name1", "Name2"], # 2 dimensions, 2 names
)
ValueError: Invalid relative_time_type
The reference type is not valid. Use one of:
RelativeTimeType.TO_FIRST
RelativeTimeType.TO_LAST
RelativeTimeType.TO_NEAREST
RelativeTimeType.TO_NEXT
RelativeTimeType.TO_PREVIOUS
Or use strings:
client.calculate_time_since(..., since="first") # Instead of TO_FIRST