vizzuhq / ipyvizzu Goto Github PK
View Code? Open in Web Editor NEWBuild animated charts in Jupyter Notebook and similar environments with a simple Python syntax.
Home Page: https://ipyvizzu.vizzuhq.com
License: Apache License 2.0
Build animated charts in Jupyter Notebook and similar environments with a simple Python syntax.
Home Page: https://ipyvizzu.vizzuhq.com
License: Apache License 2.0
Mode.com notebook won't show output div for the display_javascript call.
The vizzu div should be created manually using display_html when show() called.
Would be good to optionally have the possibility to automatically store the chart at the end of the cell and restore at the beginning of the cell, like in the tutorial, configurable by a parameter.
if display = "actual"
Put links to demos in online notebook services:
it would be better to validate the json data
from jsonschema import validate
NAMED_VALUES_SCHEMA = {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"values": {
"type": "array"
}
},
"required": ["name", "values"]
}
}
SCHEMA = {
"type": "object",
"properties": {
"records": {
"type": "array",
},
"series": NAMED_VALUES_SCHEMA,
"measures": NAMED_VALUES_SCHEMA,
"dimensions": NAMED_VALUES_SCHEMA,
}
}
class Data(Animation):
@classmethod
def from_json(cls, filename):
with open(filename) as file_desc:
data = json.load(file_desc)
validate(data, SCHEMA)
return cls(data)
The validation does not have to be jsonschema. We could use typing.NamedTuple
, dataclasses
or attrs
, but they unfortunately don't have from_dict
method .
Originally posted by @nyirog in #37 (comment)
https://lib.vizzuhq.com/latest/#chapter-0.16
proposal: js functions passed as string
clickHandler = chart.on("click", "alert(JSON.stringify(event.data));");
chart.off('click', clickHandler);
generate JS code:
let eventHandler1231245 = event => { alert(JSON.stringify(event.data)); };
chart.on("click", eventHandler1231245);
chart.off('click', eventHandler1231245);
I should set chart.scroll_into_view = False
here explicitly, or autoscrolling would not stop on manual scroll.
Wouldn't be better to have some preset value for vizzu source instead of a free style str?
import enum
class VizzuSource(str, enum.Enum):
latest = "https://cdn.jsdelivr.net/npm/vizzu@latest/dist/vizzu.min.js"
...
class Chart:
def set_vizzu(self, source: VizzuSource):
self._vizzu_url = source
Originally posted by @nyirog in #40 (comment)
Chart presets for commonly used chart types with same API as mathplotlib.
https://matplotlib.org/stable/plot_types/index.html
The problem seems to be, that this environment creates separate HTML documents for each cell including them into the notebook using iframe, also creates separate js files for all script tag inside a cell.
catch promise errors, after than; after send beck to ipython display javascript
If it is possible, data verification by schema can be removed from ipyvizzu.
Example:
In tutorial/sorting.ipynb change chart.scroll_into_view = False to True.
Press Run All
Scroll up after the first chart appears.
Ipyvizzu will scroll back.
Make ipyvizzu work in mercury: https://github.com/mljar/mercury
When ipyvizzu relocates (animate) vizzu's div, empty jp-OutputPrompt jp-OutputArea-prompt fields are created.
These fields are invisible in the jupyter notebook, but they are visible and not well formatted in the html doc.
The style params of these fields depends on the html template (default lab), so a hot fix can be the create the doc with a custom ipyvizzu template.
But if someone will use ipyvizzu in a project, and use nbconvert to generate htmls from the notebooks, the problem still be there.
I think the adequate solutions can be if ipyvizzu remove this empty fields if it is possible.
There is a scroll bar below the chart in the generated documentation.
The Push doumentation to gh-pages
action should detect pull request phase and skip push.
With the new separated js class in the generated htmls the chart displayed after the first cell, and not moved (display="actual")
Even with manually saved ipynb output, even if nbconvert generated it.
Example:
cd tools/html-generator
with execute flag *if output not created and saved manually:
../../.venv/bin/jupyter nbconvert --Exporter.preprocessors=preprocessor.NbPreprocessor --to html --execute ../../docs/tutorial/sorting.ipynb
without execute flag *if output created and saved manually:
../../.venv/bin/jupyter nbconvert --Exporter.preprocessors=preprocessor.NbPreprocessor --to html ../../docs/tutorial/sorting.ipynb
Also solve interactivity (streamlit buttons -> vizzu animations)
If the notebook is running and the user scrolls, then auto scrolling should switch off for that run.
It is inconvenient for the user that they couldn't scroll during running.
Something like this would be the solution:
global scope:
let inhibitScroll = false;
document.addEventListener('scroll', function(e) {
inhibitScroll = true;
});
cell:
if (!inhibitScroll) myVizzu.scrollIntoView(...);
I don't how to set inhibitScroll
back to false
after running, but next run should do autoscrolling again.
Pandas supports setting type for data series, so handling this in ipyvizzu is redundant.
It would be enough to mention this in the docs instead.
example:
data_frame = pd.read_csv('../../data/eu_survey.csv', dtype={"Year": str})
Data filter can be specified for Vizzu on the JS API as a JS function:
chart.animate({ data: { filter: record => expression ) }});
where data series can be referenced through the record object, e.g.:
record => { return record["foo"] == "blabla" || record["baz"] > 5; }
It would be good to have two possibilities to define this filter on the ipyvizzu API
Simple solution, supplying the JS expression in a string:
Python:
filter = JSExpression("string-of-JS-code")
where ipyvizzu should generate the following JS code:
JS:
filter: record => { return (string-of-JS-code); }
e.g.:
Python:
filter = JSExpression("record['foo'] == 'blabla' || record['baz'] > 5")
=>
JS:
filter: record => { return record['foo'] == 'blabla' || record['baz'] > 5; }
Through Python wrapper object with overloaded operators building the js code under the hood.
Python:
filter = Series("foo") == "blabla" || Series("baz" > 5)
where ipyvizzu should generate the following:
JS:
filter: record => { return record["foo"] == "blabla" || record["baz"] > 5; }
Operators, which should be supported:
==, !=, <, <=, >=, >, ||, &&
needs a back button.
I have a question about the online version of the documentation.
If I change something in a ipynb file in doc/examples, after that I need to run make doc and commit changed htmls if I want to update the site too? (In that case I do not understand clearly what pages-build-deployment workflow do.)
ipyvizzu.Chart.animate() can not handle animoptions (like delay, duration etc.).
The JS API accepts the following arguments:
animate({ data, config, style }, animoptions)
animate(config, animoptions)
animate({ data, config, style })
animate(config)
ipyvizzu's behavior do not need to be the same like the JS API, so it can be pythonic, but the functions have to work.
(animoptions is a js object like a python dict, or in js api it can be a single string if only want to change the duration so '500ms' instead of {duration: '500ms'})
I think possible solutions in ipyvizzu are:
I.
kwargs only be animoptions
style, data and config only be Style, Data, Config classes in args
(it is a further problem with this, Style(None) needs to work to reset previous style modifications, but now it is working only in kwargs style=None)
II.
create az animOptions class, and handle it differently in _merge_animations()
III.
any other idea
Problem:
In the HTML output, when the chart moves down to the next cell, the view won't follow it and it goes out of the screen.
Solution:
It would be good to have a "scrollIntoView" parameter for ipyvizzu, which - if set - would cause the generator to emit js code for all cells scrolling them into view on activation.
see: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
https://vizzuhq.github.io/ipyvizzu/examples/examples.html
In this site: "This site is open source. Improve this page." is incorrect, because this page is genearted, so every modification will be lost.
Panel is a powerful framework for #dataapps in #python. It would be really nice if it was easy to use Ipyvizzu with Panel.
As a first step I created an example of how this can be done. See https://discourse.holoviz.org/t/animated-charts-and-story-telling-with-ipyvizzu/3622 for the details.
I've made a small tweet about it here https://twitter.com/MarcSkovMadsen/status/1518219138266804224?s=20&t=qKrkT52SeEvRLp74fHpE6g. I've shared it on LinkedIn here https://www.linkedin.com/posts/marcskovmadsen_dataapp-python-dataapp-activity-6923988516120985600-qJ_C?utm_source=linkedin_share&utm_medium=member_desktop_web.
To make it easy would probably either include some documentation on the ipyvizzu side and/ or a custom Panel pane that users can wrap the Ipyvizzu chart in to get it rendered.
This issue is mostly for info at the current state such that your community knows it can be done.
Import data classes of the examples instead of copy then into every snippet.
not working example:
https://colab.research.google.com/drive/1pSGB3xEnStTRqWhq_duPGPJ30cXq27ua?usp=sharing
The problem seems to be, that this environment creates separate HTML documents for each cell including them into the notebook using iframe.
Hello, may I ask, where can I get datasets used in examples charts?
Tested. Works in certain cases.
Seems to be working ok on:
pd.DataFrames
of various shapes, including 1 x n
and n x 1
DataFrame
index
and column
names of any type, including str
and int
DataFrame
contains None
or np.nan
elementsDoes not work when:
pd.Series
as an argument
[[ ]]
on your data and pass it as a n x 1
DataFrame
insteadNone
as argument
DataFrame
object insteadOriginally posted by @csaladenes in #69 (review)
Quick fix: Insert in line 1
of add_df
:
if type(df) in [type(None)]: return {} # return empty dict if NoneType
else:
if type(df)==pd.core.series.Series:
df=pd.DataFrame(df) # force type to DataFrame
for name ...
Makes it dependent on pandas
imported as pd
of course.
Originally posted by @csaladenes in #69 (comment)
The notebooks (ipynb) inculdes the markdown and code cells as list of lines. Editing the notebook is error prone therefore we should read the cells from separate assets.
A notebook
{
"cells": [
{
"cell_type": "markdown",
"id": "e582c95b",
"metadata": {},
"source": [
"## Aggregate/drill-down\n",
"\n",
"These features basically mean that you add or remove an additional dimension to/from an axis or another channel. As you can see below, there are some important things to keep in mind when you use them.\n",
"\n",
"Let’s stack together the elements by putting the Genres dimension from the x-axis to the y-axis. At the end of this phase, there are chart elements with the same color stacked on top of each other, which is something you would want to avoid. "
]
}
]
}
would be split into a json and markdown/python files
{
"cells": [
{
"cell_type": "markdown",
"id": "e582c95b",
"metadata": {},
"source": {"@readlines": "aggregate.md"}
}
]
}
## Aggregate/drill-down
These features basically mean that you add or remove an additional dimension to/from an axis or another channel. As you can see below, there are some important things to keep in mind when you use them.
Let’s stack together the elements by putting the Genres dimension from the x-axis to the y-axis. At the end of this phase, there are chart elements with the same color stacked on top of each other, which is something you would want to avoid.
The {"@readlines": "aggregate.md"}
would be handle by a simple python script with the json.load object_hook. And the Makefile would genearte ipynb
from the json
template:
#!/usr/bin/env python3
"""
Replace `{"@readlines": "referred/file"}` object from the `json_file` with the
list of lines read from the referred file. The path of the referred file is
relative to the `json_file`.
"""
import argparse
import json
import sys
import pathlib
def main():
args = _parse_args()
reader = Reader(args.json_file.parent)
with args.json_file.open() as fp:
obj = json.load(fp, object_hook=reader.object_hook)
json.dump(obj, fp=sys.stdout, indent=4, sort_keys=True)
def _parse_args():
parser = argparse.ArgumentParser(
description="Read files as list of lines into json", epilog=__doc__
)
parser.add_argument("json_file", type=pathlib.Path)
return parser.parse_args()
class Reader:
def __init__(self, source_dir):
self._source_dir = source_dir
def object_hook(self, obj):
if len(obj) != 1:
return obj
try:
path = obj["@readlines"]
except KeyError:
return obj
file_name = self._source_dir / path
with file_name.open() as fp:
return fp.readlines()
if __name__ == "__main__":
exit(main())
This is a great library! Exactly the lib that I was looking for! Thank you! 🥇
How to run the animation in the loop? Can I add controls for animation (stop, play)?
I'm working on a framework for converting Jupyter Notebooks to interactive web apps. Would love to use vizzu in demos. I will let you know, thanks!
Serie is in french :)
Check if ipyvizzu works with Mercury after this PR merged:
#107
See also:
mljar/mercury#81
If run initiated on a cell while another cell did not finished running, then the chart div somehow gets duplicated.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.