Storylib
ipyvizzustory.storylib
Environment independent modules.
ipyvizzustory.storylib.animation
A module for working with chart animations.
DataFilter
Bases: Data
A class for representing a data filter.
Source code in src/ipyvizzustory/storylib/animation.py
class DataFilter(Data):
"""A class for representing a data filter."""
def build(self) -> dict:
"""
A method for overwriting [Data.build][ipyvizzu.animation.Data.build] method.
Data initialized with a `DataFilter` must contain only a filter.
Returns:
A dictionary contains the filter key with the filter expression.
Raises:
ValueError: If `DataFilter` does not contain a filter or contains anything else.
"""
if len(self.keys()) != 1 or "filter" not in self:
raise KeyError("Data must contain filter and only that.")
return {"filter": self["filter"]}
build()
A method for overwriting Data.build method.
Data initialized with a DataFilter
must contain only a filter.
Returns:
Type | Description |
---|---|
dict
|
A dictionary contains the filter key with the filter expression. |
Raises:
Type | Description |
---|---|
ValueError
|
If |
Source code in src/ipyvizzustory/storylib/animation.py
def build(self) -> dict:
"""
A method for overwriting [Data.build][ipyvizzu.animation.Data.build] method.
Data initialized with a `DataFilter` must contain only a filter.
Returns:
A dictionary contains the filter key with the filter expression.
Raises:
ValueError: If `DataFilter` does not contain a filter or contains anything else.
"""
if len(self.keys()) != 1 or "filter" not in self:
raise KeyError("Data must contain filter and only that.")
return {"filter": self["filter"]}
ipyvizzustory.storylib.story
A module for working with presentation stories.
Step
Bases: dict
A class for representing a step of a slide.
Source code in src/ipyvizzustory/storylib/story.py
class Step(dict):
"""A class for representing a step of a slide."""
def __init__(
self,
*animations: Union[Data, Style, Config],
**anim_options: Optional[Union[str, int, float, dict]],
):
"""
Step constructor.
Args:
*animations: List of [Data][ipyvizzu.Data],
[Config][ipyvizzu.Config] and [Style][ipyvizzu.Style] objects.
A `Step` can contain each of the above once.
**anim_options: Animation options such as duration.
Raises:
ValueError: If `animations` are not set.
Example:
Initialize a step with a [Config][ipyvizzu.Config] object:
step = Step(
Config({"x": "Foo", "y": "Bar"})
)
"""
super().__init__()
if not animations:
raise ValueError("No animation was set.")
self._update(*animations)
if anim_options:
self["animOptions"] = anim_options
def _update(self, *animations: Union[Data, Style, Config]) -> None:
for animation in animations:
if not animation or type(animation) not in [
Data,
Style,
Config,
]: # pylint: disable=unidiomatic-typecheck
raise TypeError("Type must be Data, Style or Config.")
if type(animation) == Data: # pylint: disable=unidiomatic-typecheck
animation = DataFilter(animation)
builded_animation = animation.build()
common_keys = set(builded_animation).intersection(set(self))
if common_keys:
raise ValueError(f"Animation is already merged: {common_keys}")
self.update(builded_animation)
__init__(*animations, **anim_options)
Step constructor.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
*animations |
Union[Data, Style, Config]
|
()
|
|
**anim_options |
Optional[Union[str, int, float, dict]]
|
Animation options such as duration. |
{}
|
Raises:
Type | Description |
---|---|
ValueError
|
If |
Source code in src/ipyvizzustory/storylib/story.py
def __init__(
self,
*animations: Union[Data, Style, Config],
**anim_options: Optional[Union[str, int, float, dict]],
):
"""
Step constructor.
Args:
*animations: List of [Data][ipyvizzu.Data],
[Config][ipyvizzu.Config] and [Style][ipyvizzu.Style] objects.
A `Step` can contain each of the above once.
**anim_options: Animation options such as duration.
Raises:
ValueError: If `animations` are not set.
Example:
Initialize a step with a [Config][ipyvizzu.Config] object:
step = Step(
Config({"x": "Foo", "y": "Bar"})
)
"""
super().__init__()
if not animations:
raise ValueError("No animation was set.")
self._update(*animations)
if anim_options:
self["animOptions"] = anim_options
Slide
Bases: list
A class for representing a slide of a presentation story.
Source code in src/ipyvizzustory/storylib/story.py
class Slide(list):
"""A class for representing a slide of a presentation story."""
def __init__(self, step: Optional[Step] = None):
"""
Slide constructor.
Args:
step: The first step can also be added to the slide in the constructor.
Example:
Initialize a slide without step:
slide = Slide()
Initialize a slide with a step:
slide = Slide(
Step(
Config({"x": "Foo", "y": "Bar"})
)
)
"""
super().__init__()
if step:
self.add_step(step)
def add_step(self, step: Step) -> None:
"""
A method for adding a step for the slide.
Args:
step: The next step of the slide.
Raises:
TypeError: If the type of the `step` is not
[Step][ipyvizzustory.storylib.story.Step].
Example:
Add steps to a slide:
slide = Slide()
slide.add_step(
Step(
Config({"x": "Foo", "y": "Bar"})
)
)
slide.add_step(
Step(
Config({"color": "Foo", "x": "Baz", "geometry": "circle"})
)
)
"""
if not step or type(step) != Step: # pylint: disable=unidiomatic-typecheck
raise TypeError("Type must be Step.")
self.append(step)
__init__(step=None)
Slide constructor.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
step |
Optional[Step]
|
The first step can also be added to the slide in the constructor. |
None
|
Example
Initialize a slide without step:
slide = Slide()
Initialize a slide with a step:
slide = Slide(
Step(
Config({"x": "Foo", "y": "Bar"})
)
)
Source code in src/ipyvizzustory/storylib/story.py
def __init__(self, step: Optional[Step] = None):
"""
Slide constructor.
Args:
step: The first step can also be added to the slide in the constructor.
Example:
Initialize a slide without step:
slide = Slide()
Initialize a slide with a step:
slide = Slide(
Step(
Config({"x": "Foo", "y": "Bar"})
)
)
"""
super().__init__()
if step:
self.add_step(step)
add_step(step)
A method for adding a step for the slide.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
step |
Step
|
The next step of the slide. |
required |
Raises:
Type | Description |
---|---|
TypeError
|
If the type of the |
Example
Add steps to a slide:
slide = Slide()
slide.add_step(
Step(
Config({"x": "Foo", "y": "Bar"})
)
)
slide.add_step(
Step(
Config({"color": "Foo", "x": "Baz", "geometry": "circle"})
)
)
Source code in src/ipyvizzustory/storylib/story.py
def add_step(self, step: Step) -> None:
"""
A method for adding a step for the slide.
Args:
step: The next step of the slide.
Raises:
TypeError: If the type of the `step` is not
[Step][ipyvizzustory.storylib.story.Step].
Example:
Add steps to a slide:
slide = Slide()
slide.add_step(
Step(
Config({"x": "Foo", "y": "Bar"})
)
)
slide.add_step(
Step(
Config({"color": "Foo", "x": "Baz", "geometry": "circle"})
)
)
"""
if not step or type(step) != Step: # pylint: disable=unidiomatic-typecheck
raise TypeError("Type must be Step.")
self.append(step)
StorySize
A class for representing the size of a presentation story.
Source code in src/ipyvizzustory/storylib/story.py
class StorySize:
"""A class for representing the size of a presentation story."""
ERROR_MSG_WIDTH_AND_HEIGHT = "width and height should be in pixels"
ERROR_MSG_WIDTH_OR_HEIGHT = "width or height should be in pixels"
ERROR_MSG_ASPECT_RATIO = "aspect_ratio should be a float"
def __init__(
self,
width: Optional[Union[int, float, str]] = None,
height: Optional[Union[int, float, str]] = None,
aspect_ratio: Optional[Union[int, float, str]] = None,
):
"""
StorySize constructor.
Args:
width: The width of a presentation story.
height: The height of a presentation story.
aspect_ratio: The aspect ratio of a presentation story.
Raises:
ValueError: If width, height and aspect_ratio are set together.
"""
width = self._convert_to_pixel_or_return(width)
height = self._convert_to_pixel_or_return(height)
self._width = width
self._height = height
self._aspect_ratio = aspect_ratio
self._style = ""
if None not in [width, height, aspect_ratio]:
raise ValueError(
"width, height and aspect ratio cannot be set at the same time"
)
if all([height is not None, aspect_ratio is not None]):
width = "unset"
if any([width is not None, height is not None, aspect_ratio is not None]):
_width = "" if width is None else f"width: {width};"
_height = "" if height is None else f"height: {height};"
_aspect_ratio = (
""
if aspect_ratio is None
else f"aspect-ratio: {aspect_ratio} !important;"
)
self._style = f"vp.style.cssText = '{_aspect_ratio}{_width}{_height}'"
@staticmethod
def _convert_to_pixel_or_return(value: Any) -> Optional[str]:
if StorySize._is_int(value) or StorySize._is_float(value):
return str(value) + "px"
return value
@staticmethod
def _is_int(value: Any) -> bool:
if isinstance(value, int):
return True
if isinstance(value, str):
if re.search(r"^[-+]?[0-9]+$", value):
return True
return False
@staticmethod
def _is_float(value: Any) -> bool:
if isinstance(value, float):
return True
if isinstance(value, str):
if re.search(r"^[+-]?[0-9]+\.[0-9]+$", value):
return True
return False
@property
def width(self) -> Optional[str]:
"""
A property for storing the width of a presentation story.
Returns:
The width of a presentation story.
"""
return self._width
@property
def height(self) -> Optional[str]:
"""
A property for storing the height of a presentation story.
Returns:
The height of a presentation story.
"""
return self._height
@property
def aspect_ratio(self) -> Optional[Union[int, float, str]]:
"""
A property for storing the aspect ratio of a presentation story.
Returns:
The aspect ratio of a presentation story.
"""
return self._aspect_ratio
@property
def style(self) -> str:
"""
A property for storing the style of a presentation story.
Note:
If neither `width`, `height` nor `aspect_ratio` is set, it returns an empty string.
Returns:
The cssText width and height of a presentation story.
"""
return self._style
@staticmethod
def is_pixel(value: Any) -> bool:
"""
A static method for checking the type of the given value.
Args:
value: The value to check.
Returns:
`True` if the value is pixel, `False` otherwise.
"""
if StorySize._is_int(value) or StorySize._is_float(value):
return True
if isinstance(value, str) and value.endswith("px"):
if StorySize._is_int(value[0:-2]) or StorySize._is_float(value[0:-2]):
return True
return False
def get_width_height_in_pixels(self) -> Tuple[int, int]:
"""
A method for returning the width and height in pixels.
Raises:
ValueError: If width and height are not in pixels when aspect_ratio is not set.
ValueError: If width or height is not in pixel when aspect_ratio is set.
ValueError: If aspect_ratio is not a float when aspect_ratio is set.
Returns:
The width and height in pixels as int.
"""
if self.aspect_ratio is None:
if any(
[
not StorySize.is_pixel(self.width),
not StorySize.is_pixel(self.height),
]
):
raise ValueError(StorySize.ERROR_MSG_WIDTH_AND_HEIGHT)
_width = int(float(self.width[:-2])) # type: ignore
_height = int(float(self.height[:-2])) # type: ignore
else:
if not any(
[
StorySize._is_int(self.aspect_ratio),
StorySize._is_float(self.aspect_ratio),
]
):
raise ValueError(StorySize.ERROR_MSG_ASPECT_RATIO)
if not any(
[StorySize.is_pixel(self.width), StorySize.is_pixel(self.height)]
):
raise ValueError(StorySize.ERROR_MSG_WIDTH_OR_HEIGHT)
_aspect_ratio = float(self.aspect_ratio)
if StorySize.is_pixel(self.width):
_width = float(self.width[:-2]) # type: ignore
_height = int(_width / _aspect_ratio)
_width = int(_width)
else:
_height = float(self.height[:-2]) # type: ignore
_width = int(_height * _aspect_ratio)
_height = int(_height)
return (_width, _height)
width: Optional[str]
property
height: Optional[str]
property
aspect_ratio: Optional[Union[int, float, str]]
property
style: str
property
A property for storing the style of a presentation story.
Note
If neither width
, height
nor aspect_ratio
is set, it returns an empty string.
Returns:
Type | Description |
---|---|
str
|
The cssText width and height of a presentation story. |
__init__(width=None, height=None, aspect_ratio=None)
StorySize constructor.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
width |
Optional[Union[int, float, str]]
|
The width of a presentation story. |
None
|
height |
Optional[Union[int, float, str]]
|
The height of a presentation story. |
None
|
aspect_ratio |
Optional[Union[int, float, str]]
|
The aspect ratio of a presentation story. |
None
|
Raises:
Type | Description |
---|---|
ValueError
|
If width, height and aspect_ratio are set together. |
Source code in src/ipyvizzustory/storylib/story.py
def __init__(
self,
width: Optional[Union[int, float, str]] = None,
height: Optional[Union[int, float, str]] = None,
aspect_ratio: Optional[Union[int, float, str]] = None,
):
"""
StorySize constructor.
Args:
width: The width of a presentation story.
height: The height of a presentation story.
aspect_ratio: The aspect ratio of a presentation story.
Raises:
ValueError: If width, height and aspect_ratio are set together.
"""
width = self._convert_to_pixel_or_return(width)
height = self._convert_to_pixel_or_return(height)
self._width = width
self._height = height
self._aspect_ratio = aspect_ratio
self._style = ""
if None not in [width, height, aspect_ratio]:
raise ValueError(
"width, height and aspect ratio cannot be set at the same time"
)
if all([height is not None, aspect_ratio is not None]):
width = "unset"
if any([width is not None, height is not None, aspect_ratio is not None]):
_width = "" if width is None else f"width: {width};"
_height = "" if height is None else f"height: {height};"
_aspect_ratio = (
""
if aspect_ratio is None
else f"aspect-ratio: {aspect_ratio} !important;"
)
self._style = f"vp.style.cssText = '{_aspect_ratio}{_width}{_height}'"
is_pixel(value)
staticmethod
A static method for checking the type of the given value.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
value |
Any
|
The value to check. |
required |
Returns:
Type | Description |
---|---|
bool
|
|
Source code in src/ipyvizzustory/storylib/story.py
@staticmethod
def is_pixel(value: Any) -> bool:
"""
A static method for checking the type of the given value.
Args:
value: The value to check.
Returns:
`True` if the value is pixel, `False` otherwise.
"""
if StorySize._is_int(value) or StorySize._is_float(value):
return True
if isinstance(value, str) and value.endswith("px"):
if StorySize._is_int(value[0:-2]) or StorySize._is_float(value[0:-2]):
return True
return False
get_width_height_in_pixels()
A method for returning the width and height in pixels.
Raises:
Type | Description |
---|---|
ValueError
|
If width and height are not in pixels when aspect_ratio is not set. |
ValueError
|
If width or height is not in pixel when aspect_ratio is set. |
ValueError
|
If aspect_ratio is not a float when aspect_ratio is set. |
Returns:
Type | Description |
---|---|
Tuple[int, int]
|
The width and height in pixels as int. |
Source code in src/ipyvizzustory/storylib/story.py
def get_width_height_in_pixels(self) -> Tuple[int, int]:
"""
A method for returning the width and height in pixels.
Raises:
ValueError: If width and height are not in pixels when aspect_ratio is not set.
ValueError: If width or height is not in pixel when aspect_ratio is set.
ValueError: If aspect_ratio is not a float when aspect_ratio is set.
Returns:
The width and height in pixels as int.
"""
if self.aspect_ratio is None:
if any(
[
not StorySize.is_pixel(self.width),
not StorySize.is_pixel(self.height),
]
):
raise ValueError(StorySize.ERROR_MSG_WIDTH_AND_HEIGHT)
_width = int(float(self.width[:-2])) # type: ignore
_height = int(float(self.height[:-2])) # type: ignore
else:
if not any(
[
StorySize._is_int(self.aspect_ratio),
StorySize._is_float(self.aspect_ratio),
]
):
raise ValueError(StorySize.ERROR_MSG_ASPECT_RATIO)
if not any(
[StorySize.is_pixel(self.width), StorySize.is_pixel(self.height)]
):
raise ValueError(StorySize.ERROR_MSG_WIDTH_OR_HEIGHT)
_aspect_ratio = float(self.aspect_ratio)
if StorySize.is_pixel(self.width):
_width = float(self.width[:-2]) # type: ignore
_height = int(_width / _aspect_ratio)
_width = int(_width)
else:
_height = float(self.height[:-2]) # type: ignore
_width = int(_height * _aspect_ratio)
_height = int(_height)
return (_width, _height)
Story
Bases: dict
A class for representing a presentation story.
Source code in src/ipyvizzustory/storylib/story.py
class Story(dict):
"""A class for representing a presentation story."""
# pylint: disable=too-many-instance-attributes
def __init__(self, data: Data, style: Optional[Style] = None):
"""
Presentation Story constructor.
Args:
data: Data set for the whole presentation story.
After initialization `data` can not be modified,
but it can be filtered.
style: Style settings for the presentation story.
`style` can be changed at each presentation step.
Raises:
TypeError: If the type of the `data` is not `ipyvizzu.Data`.
TypeError: If the type of the `style` is not `ipyvizzu.Style`.
Example:
Initialize a story with data and without style:
data = Data()
data.add_series("Foo", ["Alice", "Bob", "Ted"])
data.add_series("Bar", [15, 32, 12])
data.add_series("Baz", [5, 3, 2])
story = Story(data=data)
"""
super().__init__()
self._analytics = True
self._vizzu: Optional[str] = None
self._vizzu_story: str = VIZZU_STORY
self._start_slide: Optional[int] = None
self._size: StorySize = StorySize()
self._features: List[str] = []
self._events: List[str] = []
self._plugins: List[str] = []
if not data or type(data) != Data: # pylint: disable=unidiomatic-typecheck
raise TypeError("Type must be Data.")
self.update(data.build())
if style:
if type(style) != Style: # pylint: disable=unidiomatic-typecheck
raise TypeError("Type must be Style.")
self.update(style.build())
self["slides"] = []
@property
def analytics(self) -> bool:
"""
A property for enabling/disabling the usage statistics feature.
The usage statistics feature allows aggregate usage data collection
using Plausible's algorithm.
Enabling this feature helps us follow the progress and overall trends of our library,
allowing us to focus our resources effectively and better serve our users.
We do not track, collect, or store any personal data or personally identifiable information.
All data is isolated to a single day, a single site, and a single device only.
Please note that even when this feature is enabled,
publishing anything made with `ipyvizzu-story` remains GDPR compatible.
Returns:
The value of the property (default `True`).
"""
return self._analytics
@analytics.setter
def analytics(self, analytics: Optional[bool]):
self._analytics = bool(analytics)
@property
def vizzu(self) -> Optional[str]:
"""
A property for changing `vizzu` url.
Note:
If `None`, vizzu url is set by `vizzu-story`.
Returns:
`Vizzu` url.
"""
return self._vizzu
@vizzu.setter
def vizzu(self, url: str) -> None:
self._vizzu = url
@property
def vizzu_story(self) -> str:
"""
A property for changing `vizzu-story` url.
Returns:
`Vizzu-story` url.
"""
return self._vizzu_story
@vizzu_story.setter
def vizzu_story(self, url: str) -> None:
self._vizzu_story = url
@property
def start_slide(self) -> Optional[int]:
"""
A property for setting the starter slide.
Returns:
Number of the starter slide.
"""
return self._start_slide
@start_slide.setter
def start_slide(self, number: int) -> None:
self._start_slide = number
def add_slide(self, slide: Slide) -> None:
"""
A method for adding a slide for the story.
Args:
slide: The next slide of the story.
Raises:
TypeError: If the type of the `slide` is not
[Slide][ipyvizzustory.storylib.story.Slide].
Example:
Add a slide to the story:
story.add_slide(
Slide(
Step(
Config({"x": "Foo", "y": "Bar"})
)
)
)
"""
if not slide or type(slide) != Slide: # pylint: disable=unidiomatic-typecheck
raise TypeError("Type must be Slide.")
self["slides"].append(slide)
def set_feature(self, name: str, enabled: bool) -> None:
"""
A method for enabling or disabling a feature of the story.
Args:
name: The name of the feature.
enabled: `True` if enabled or `False` if disabled.
Example:
Set a feature of the story, for example enable the tooltip:
story.set_feature("tooltip", True)
"""
self._features.append(f"chart.feature('{name}', {json.dumps(enabled)});")
def add_event(self, event: str, handler: str) -> None:
"""
A method for creating and turning on an event handler.
Args:
event: The type of the event.
handler: The handler `JavaScript` expression as string.
Example:
Add an event handler to the story:
story.add_event("click", "alert(JSON.stringify(event.detail));")
"""
self._events.append(
f"chart.on('{event}', event => {{{' '.join(handler.split())}}});"
)
def add_plugin(
self, plugin: str, options: Optional[dict] = None, name: str = "default"
) -> None:
"""
A method for register plugins of the chart.
Args:
plugin: The package name or the url of the plugin.
options: The plugin constructor options.
name: The name of the plugin (default `default`).
"""
if options is None:
options = {}
self._plugins.append(
"plugins.push({"
+ f"plugin: '{plugin}', "
+ f"options: {json.dumps(options, cls=RawJavaScriptEncoder)}, "
+ f"name: '{name}'"
+ "})"
)
def set_size(
self,
width: Optional[Union[int, float, str]] = None,
height: Optional[Union[int, float, str]] = None,
aspect_ratio: Optional[Union[int, float, str]] = None,
) -> None:
"""
A method for setting width/height settings.
Args:
width: The width of the presentation story.
height: The height of the presentation story.
aspect_ratio: The aspect ratio of the presentation story.
Example:
Change the size of the story:
story.set_size("100%", "400px")
"""
self._size = StorySize(width=width, height=height, aspect_ratio=aspect_ratio)
def _repr_html_(self) -> str:
return self.to_html()
def to_html(self) -> str:
"""
A method for assembling the `HTML` code.
Returns:
The assembled `HTML` code as string.
"""
vizzu_player_data = f"{json.dumps(self, cls=RawJavaScriptEncoder)}"
return DISPLAY_TEMPLATE.format(
id=uuid.uuid4().hex[:7],
version=__version__,
analytics=str(self._analytics).lower(),
vizzu=f'vizzu-url="{self._vizzu}"' if self._vizzu else "",
vizzu_story=self._vizzu_story,
vizzu_player_data=vizzu_player_data,
start_slide=f'start-slide="{self._start_slide}"'
if self._start_slide
else "",
chart_size=self._size.style,
chart_features=f"\n{DISPLAY_INDENT * 3}".join(self._features),
chart_events=f"\n{DISPLAY_INDENT * 3}".join(self._events),
chart_plugins=f"\n{DISPLAY_INDENT * 3}".join(self._plugins),
)
def export_to_html(self, filename: PathLike) -> None:
"""
A method for exporting the story into `HTML` file.
Args:
filename: The path of the target `HTML` file.
"""
with open(filename, "w", encoding="utf8") as file_desc:
file_desc.write(self.to_html())
analytics: bool
property
writable
A property for enabling/disabling the usage statistics feature.
The usage statistics feature allows aggregate usage data collection using Plausible's algorithm. Enabling this feature helps us follow the progress and overall trends of our library, allowing us to focus our resources effectively and better serve our users.
We do not track, collect, or store any personal data or personally identifiable information. All data is isolated to a single day, a single site, and a single device only.
Please note that even when this feature is enabled,
publishing anything made with ipyvizzu-story
remains GDPR compatible.
Returns:
Type | Description |
---|---|
bool
|
The value of the property (default |
vizzu: Optional[str]
property
writable
vizzu_story: str
property
writable
start_slide: Optional[int]
property
writable
__init__(data, style=None)
Presentation Story constructor.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
data |
Data
|
Data set for the whole presentation story.
After initialization |
required |
style |
Optional[Style]
|
Style settings for the presentation story.
|
None
|
Raises:
Type | Description |
---|---|
TypeError
|
If the type of the |
TypeError
|
If the type of the |
Example
Initialize a story with data and without style:
data = Data()
data.add_series("Foo", ["Alice", "Bob", "Ted"])
data.add_series("Bar", [15, 32, 12])
data.add_series("Baz", [5, 3, 2])
story = Story(data=data)
Source code in src/ipyvizzustory/storylib/story.py
def __init__(self, data: Data, style: Optional[Style] = None):
"""
Presentation Story constructor.
Args:
data: Data set for the whole presentation story.
After initialization `data` can not be modified,
but it can be filtered.
style: Style settings for the presentation story.
`style` can be changed at each presentation step.
Raises:
TypeError: If the type of the `data` is not `ipyvizzu.Data`.
TypeError: If the type of the `style` is not `ipyvizzu.Style`.
Example:
Initialize a story with data and without style:
data = Data()
data.add_series("Foo", ["Alice", "Bob", "Ted"])
data.add_series("Bar", [15, 32, 12])
data.add_series("Baz", [5, 3, 2])
story = Story(data=data)
"""
super().__init__()
self._analytics = True
self._vizzu: Optional[str] = None
self._vizzu_story: str = VIZZU_STORY
self._start_slide: Optional[int] = None
self._size: StorySize = StorySize()
self._features: List[str] = []
self._events: List[str] = []
self._plugins: List[str] = []
if not data or type(data) != Data: # pylint: disable=unidiomatic-typecheck
raise TypeError("Type must be Data.")
self.update(data.build())
if style:
if type(style) != Style: # pylint: disable=unidiomatic-typecheck
raise TypeError("Type must be Style.")
self.update(style.build())
self["slides"] = []
add_slide(slide)
A method for adding a slide for the story.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
slide |
Slide
|
The next slide of the story. |
required |
Raises:
Type | Description |
---|---|
TypeError
|
If the type of the |
Example
Add a slide to the story:
story.add_slide(
Slide(
Step(
Config({"x": "Foo", "y": "Bar"})
)
)
)
Source code in src/ipyvizzustory/storylib/story.py
def add_slide(self, slide: Slide) -> None:
"""
A method for adding a slide for the story.
Args:
slide: The next slide of the story.
Raises:
TypeError: If the type of the `slide` is not
[Slide][ipyvizzustory.storylib.story.Slide].
Example:
Add a slide to the story:
story.add_slide(
Slide(
Step(
Config({"x": "Foo", "y": "Bar"})
)
)
)
"""
if not slide or type(slide) != Slide: # pylint: disable=unidiomatic-typecheck
raise TypeError("Type must be Slide.")
self["slides"].append(slide)
set_feature(name, enabled)
A method for enabling or disabling a feature of the story.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
name |
str
|
The name of the feature. |
required |
enabled |
bool
|
|
required |
Example
Set a feature of the story, for example enable the tooltip:
story.set_feature("tooltip", True)
Source code in src/ipyvizzustory/storylib/story.py
def set_feature(self, name: str, enabled: bool) -> None:
"""
A method for enabling or disabling a feature of the story.
Args:
name: The name of the feature.
enabled: `True` if enabled or `False` if disabled.
Example:
Set a feature of the story, for example enable the tooltip:
story.set_feature("tooltip", True)
"""
self._features.append(f"chart.feature('{name}', {json.dumps(enabled)});")
add_event(event, handler)
A method for creating and turning on an event handler.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
event |
str
|
The type of the event. |
required |
handler |
str
|
The handler |
required |
Example
Add an event handler to the story:
story.add_event("click", "alert(JSON.stringify(event.detail));")
Source code in src/ipyvizzustory/storylib/story.py
def add_event(self, event: str, handler: str) -> None:
"""
A method for creating and turning on an event handler.
Args:
event: The type of the event.
handler: The handler `JavaScript` expression as string.
Example:
Add an event handler to the story:
story.add_event("click", "alert(JSON.stringify(event.detail));")
"""
self._events.append(
f"chart.on('{event}', event => {{{' '.join(handler.split())}}});"
)
add_plugin(plugin, options=None, name='default')
A method for register plugins of the chart.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
plugin |
str
|
The package name or the url of the plugin. |
required |
options |
Optional[dict]
|
The plugin constructor options. |
None
|
name |
str
|
The name of the plugin (default |
'default'
|
Source code in src/ipyvizzustory/storylib/story.py
def add_plugin(
self, plugin: str, options: Optional[dict] = None, name: str = "default"
) -> None:
"""
A method for register plugins of the chart.
Args:
plugin: The package name or the url of the plugin.
options: The plugin constructor options.
name: The name of the plugin (default `default`).
"""
if options is None:
options = {}
self._plugins.append(
"plugins.push({"
+ f"plugin: '{plugin}', "
+ f"options: {json.dumps(options, cls=RawJavaScriptEncoder)}, "
+ f"name: '{name}'"
+ "})"
)
set_size(width=None, height=None, aspect_ratio=None)
A method for setting width/height settings.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
width |
Optional[Union[int, float, str]]
|
The width of the presentation story. |
None
|
height |
Optional[Union[int, float, str]]
|
The height of the presentation story. |
None
|
aspect_ratio |
Optional[Union[int, float, str]]
|
The aspect ratio of the presentation story. |
None
|
Example
Change the size of the story:
story.set_size("100%", "400px")
Source code in src/ipyvizzustory/storylib/story.py
def set_size(
self,
width: Optional[Union[int, float, str]] = None,
height: Optional[Union[int, float, str]] = None,
aspect_ratio: Optional[Union[int, float, str]] = None,
) -> None:
"""
A method for setting width/height settings.
Args:
width: The width of the presentation story.
height: The height of the presentation story.
aspect_ratio: The aspect ratio of the presentation story.
Example:
Change the size of the story:
story.set_size("100%", "400px")
"""
self._size = StorySize(width=width, height=height, aspect_ratio=aspect_ratio)
to_html()
A method for assembling the HTML
code.
Returns:
Type | Description |
---|---|
str
|
The assembled |
Source code in src/ipyvizzustory/storylib/story.py
def to_html(self) -> str:
"""
A method for assembling the `HTML` code.
Returns:
The assembled `HTML` code as string.
"""
vizzu_player_data = f"{json.dumps(self, cls=RawJavaScriptEncoder)}"
return DISPLAY_TEMPLATE.format(
id=uuid.uuid4().hex[:7],
version=__version__,
analytics=str(self._analytics).lower(),
vizzu=f'vizzu-url="{self._vizzu}"' if self._vizzu else "",
vizzu_story=self._vizzu_story,
vizzu_player_data=vizzu_player_data,
start_slide=f'start-slide="{self._start_slide}"'
if self._start_slide
else "",
chart_size=self._size.style,
chart_features=f"\n{DISPLAY_INDENT * 3}".join(self._features),
chart_events=f"\n{DISPLAY_INDENT * 3}".join(self._events),
chart_plugins=f"\n{DISPLAY_INDENT * 3}".join(self._plugins),
)
export_to_html(filename)
A method for exporting the story into HTML
file.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
filename |
PathLike
|
The path of the target |
required |
Source code in src/ipyvizzustory/storylib/story.py
def export_to_html(self, filename: PathLike) -> None:
"""
A method for exporting the story into `HTML` file.
Args:
filename: The path of the target `HTML` file.
"""
with open(filename, "w", encoding="utf8") as file_desc:
file_desc.write(self.to_html())
ipyvizzustory.storylib.template
A module for storing the HTML
templates.
VIZZU_STORY: str = 'https://cdn.jsdelivr.net/npm/vizzu-story@0.7/dist/vizzu-story.min.js'
module-attribute
A variable for storing the default url of the vizzu-story
package.
DISPLAY_INDENT: str = ' '
module-attribute
A variable for storing the default indent in the HTML
template.
DISPLAY_TEMPLATE: str = '\n<div>\n <vizzu-player id="{id}" {vizzu} {start_slide} controller></vizzu-player>\n <script type="module">\n import VizzuPlayer from "{vizzu_story}";\n\n class IpyvizzuStory {{\n static version = "{version}";\n static analytics = undefined;\n\n static changeAnalyticsTo(analytics) {{\n if (IpyvizzuStory.analytics !== analytics) {{\n console.log("ipyvizzu-story gather usage stats:", analytics);\n IpyvizzuStory.analytics = analytics;\n }}\n if (analytics) {{\n IpyvizzuStory._addHeadScript();\n }} else {{\n IpyvizzuStory._removeScript("ipyvizzu-story-analytics-head");\n }}\n }}\n\n static _addHeadScript() {{\n const scriptId = "ipyvizzu-story-analytics-head";\n if (!IpyvizzuStory._isScriptAppended(scriptId)) {{\n const script = document.createElement("script");\n script.defer = true;\n script.src = "https://plausible.io/js/script.local.js";\n script.dataset.domain = "usage.ipyvizzu-story.com";\n script.id = scriptId;\n document.getElementsByTagName("head")[0].appendChild(script);\n }}\n }}\n\n static _isScriptAppended(id) {{\n return document.querySelector(`script[id="${{id}}"]`) !== null;\n }}\n\n static _removeScript(id) {{\n const script = document.getElementById(id);\n if (script) script.remove();\n }}\n }}\n\n if (IpyvizzuStory.version !== window.IpyvizzuStory?.version) {{\n window.IpyvizzuStory = IpyvizzuStory;\n console.log(`ipyvizzu-story ${{IpyvizzuStory.version}}`);\n }}\n\n window.IpyvizzuStory?.changeAnalyticsTo({analytics});\n\n class Plugins {{\n static _resolveVizzuVersion(vp) {{\n const url = vp.vizzuUrl;\n const versionMatch = url.match(/vizzu@([^\\/]+)\\//);\n return versionMatch[1];\n }}\n\n static _resolveUrl(plugin, tag) {{\n if (!plugin.includes(\'/\')) {{\n const jsdelivr = "https://cdn.jsdelivr.net/npm/@vizzu";\n return `${{jsdelivr}}/${{plugin}}@${{tag}}/dist/mjs/index.min.js`;\n }}\n return plugin;\n }}\n\n static register(vp, chart, plugins) {{\n const tag = `vizzu-${{Plugins._resolveVizzuVersion(vp)}}`;\n const pluginsRegistered = [];\n for (const plugin of plugins) {{\n const pluginUrl = Plugins._resolveUrl(plugin.plugin, tag);\n const pluginRegistered = import(pluginUrl).then(pluginModule => {{\n const pluginInstance = new pluginModule[plugin.name](plugin.options);\n chart.feature(pluginInstance, true);\n }}).catch((error) => {{\n console.error(\'Error importing plugin:\', pluginUrl, error)\n }});\n pluginsRegistered.push(pluginRegistered);\n }}\n return Promise.all(pluginsRegistered);\n }}\n }}\n\n const vp = document.getElementById("{id}");\n vp.initializing.then(chart => {{\n const lib = vp.Vizzu;\n\n // story.set_size()\n {chart_size}\n\n // story.add_plugin()\n const plugins = [];\n {chart_plugins}\n Plugins.register(vp, chart, plugins).then(() => {{\n // story.set_feature()\n {chart_features}\n // story.add_event()\n {chart_events}\n\n const vizzuPlayerData = {vizzu_player_data};\n vp.slides = vizzuPlayerData;\n }});\n }});\n </script>\n</div>\n'
module-attribute
A variable for storing the vizzu-story
HTML
template.