pandas-render 0.2.1__py3-none-any.whl → 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pandas_render/__init__.py +23 -67
- pandas_render/base/Component.py +0 -1
- pandas_render/base/Element.py +6 -3
- pandas_render/base/__init__.py +2 -2
- pandas_render/cli/__init__.py +0 -0
- pandas_render/cli/__main__.py +37 -0
- pandas_render/components/Toggle.py +10 -8
- pandas_render/elements/Image.py +12 -4
- pandas_render/elements/Link.py +14 -6
- pandas_render/extensions/DataFrame.py +106 -31
- pandas_render/extensions/Series.py +18 -15
- pandas_render/extensions/__init__.py +11 -9
- pandas_render/utils.py +69 -0
- pandas_render-0.3.0.dist-info/METADATA +99 -0
- pandas_render-0.3.0.dist-info/RECORD +20 -0
- {pandas_render-0.2.1.dist-info → pandas_render-0.3.0.dist-info}/WHEEL +1 -1
- pandas_render-0.3.0.dist-info/entry_points.txt +2 -0
- {pandas_render-0.2.1.dist-info → pandas_render-0.3.0.dist-info/licenses}/LICENSE +2 -1
- pandas_render-0.2.1.dist-info/LICENSES/JUPYTERLAB_LICENSE +0 -37
- pandas_render-0.2.1.dist-info/LICENSES/PANDAS_LICENSE +0 -35
- pandas_render-0.2.1.dist-info/METADATA +0 -34
- pandas_render-0.2.1.dist-info/RECORD +0 -18
pandas_render/__init__.py
CHANGED
@@ -1,78 +1,34 @@
|
|
1
|
-
from
|
2
|
-
from collections import namedtuple
|
3
|
-
from inspect import cleandoc
|
1
|
+
from __future__ import annotations
|
4
2
|
|
5
|
-
from
|
6
|
-
from jinja2 import Template as JinjaTemplate
|
7
|
-
import pandas # noqa
|
3
|
+
from typing import Union
|
8
4
|
|
9
5
|
|
10
|
-
def
|
11
|
-
|
6
|
+
def _extend(package: Union["pandas", "polars"]):
|
7
|
+
# Extend pandas.Series with `render` method:
|
8
|
+
if not hasattr(package.Series, "render"):
|
12
9
|
from pandas_render.extensions.Series import render_series
|
13
|
-
setattr(pandas.Series, 'render', render_series)
|
14
10
|
|
15
|
-
|
16
|
-
from pandas_render.extensions.DataFrame import render_dataframe
|
17
|
-
setattr(pandas.DataFrame, 'render', render_dataframe)
|
18
|
-
|
19
|
-
|
20
|
-
def _handle_libraries(
|
21
|
-
libraries: Union[str, Tuple[str, str], List[Union[str, Tuple[str, str]]]]) -> str:
|
22
|
-
Library = namedtuple('Library', 'src scope')
|
23
|
-
|
24
|
-
if isinstance(libraries, (str, tuple)):
|
25
|
-
libraries = [libraries]
|
11
|
+
setattr(package.Series, "render", render_series)
|
26
12
|
|
27
|
-
|
28
|
-
if
|
29
|
-
|
30
|
-
if isinstance(library, str):
|
31
|
-
if library == 'alpine':
|
32
|
-
library = Library(
|
33
|
-
src='https://unpkg.com/alpinejs@3.4.2/dist/cdn.min.js',
|
34
|
-
scope='window.Alpine')
|
35
|
-
else:
|
36
|
-
library = Library(src=library, scope='null')
|
37
|
-
elif isinstance(library, tuple) and len(library) >= 2:
|
38
|
-
library = Library(src=library[0], scope=library[1])
|
39
|
-
|
40
|
-
if isinstance(library, Library):
|
41
|
-
valid_libraries.append(library)
|
42
|
-
|
43
|
-
template = JinjaTemplate(
|
44
|
-
cleandoc("""
|
45
|
-
var loadScriptSync = function(src, scope) {
|
46
|
-
if (scope != null && !scope) {
|
47
|
-
var script = document.createElement('script');
|
48
|
-
script.src = src;
|
49
|
-
script.type = 'text/javascript';
|
50
|
-
script.async = false;
|
51
|
-
document.getElementsByTagName('head')[0].appendChild(script);
|
52
|
-
}
|
53
|
-
};
|
54
|
-
{%- for library in libraries -%}
|
55
|
-
loadScriptSync("{{ library.src }}", {{ library.scope }});
|
56
|
-
{%- endfor -%}
|
57
|
-
"""))
|
58
|
-
|
59
|
-
output = ''
|
60
|
-
if len(valid_libraries):
|
61
|
-
output = template.render(libraries=valid_libraries)
|
62
|
-
return output
|
13
|
+
# Extend pandas.DataFrame with `render` method:
|
14
|
+
if not hasattr(package.DataFrame, "render"):
|
15
|
+
from pandas_render.extensions.DataFrame import render_dataframe
|
63
16
|
|
17
|
+
setattr(package.DataFrame, "render", render_dataframe)
|
64
18
|
|
65
|
-
def init(libraries: Optional[Union[str, Tuple[str, str], List[Union[str, Tuple[str, str]]]]] = None,
|
66
|
-
return_str: bool = False) -> Optional[Union[str, Javascript]]:
|
67
|
-
_handle_extensions()
|
68
|
-
if libraries:
|
69
|
-
output = _handle_libraries(libraries)
|
70
|
-
if return_str:
|
71
|
-
return output
|
72
|
-
return Javascript(output)
|
73
|
-
return None
|
74
19
|
|
20
|
+
try:
|
21
|
+
import pandas
|
22
|
+
except ImportError:
|
23
|
+
pass
|
24
|
+
else:
|
25
|
+
_extend(pandas)
|
75
26
|
|
76
|
-
|
27
|
+
try:
|
28
|
+
import polars
|
29
|
+
except ImportError:
|
30
|
+
pass
|
31
|
+
else:
|
32
|
+
_extend(polars)
|
77
33
|
|
78
|
-
__version__ =
|
34
|
+
__version__ = "0.3.0"
|
pandas_render/base/Component.py
CHANGED
pandas_render/base/Element.py
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
from typing import Dict, Optional
|
2
|
-
|
3
2
|
from xml.etree.ElementTree import Element as XmlElement
|
4
3
|
from xml.etree.ElementTree import tostring
|
5
4
|
|
6
5
|
|
7
6
|
class Element:
|
8
|
-
|
9
|
-
|
7
|
+
def __init__(
|
8
|
+
self,
|
9
|
+
tag: str,
|
10
|
+
attribs=Dict[str, str],
|
11
|
+
text: Optional[str] = None,
|
12
|
+
):
|
10
13
|
element = XmlElement(tag, attrib=attribs)
|
11
14
|
element.text = text if text else None
|
12
15
|
self.element = element
|
pandas_render/base/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
from pandas_render.base.Component import Component
|
2
|
-
from pandas_render.base.Element import Element
|
1
|
+
from pandas_render.base.Component import Component # noqa
|
2
|
+
from pandas_render.base.Element import Element # noqa
|
File without changes
|
@@ -0,0 +1,37 @@
|
|
1
|
+
from functools import partial
|
2
|
+
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
3
|
+
from pathlib import Path
|
4
|
+
|
5
|
+
import typer
|
6
|
+
from typing_extensions import Annotated
|
7
|
+
|
8
|
+
app = typer.Typer()
|
9
|
+
|
10
|
+
|
11
|
+
@app.command()
|
12
|
+
def render():
|
13
|
+
print("Render dataframe")
|
14
|
+
|
15
|
+
|
16
|
+
@app.command()
|
17
|
+
def serve(
|
18
|
+
host: str = "0.0.0.0",
|
19
|
+
port: int = 8080,
|
20
|
+
directory: Annotated[str, Path, typer.Argument()] = Path.cwd(),
|
21
|
+
):
|
22
|
+
if not directory:
|
23
|
+
directory = Path.cwd()
|
24
|
+
|
25
|
+
if not isinstance(directory, Path):
|
26
|
+
directory = Path(directory)
|
27
|
+
|
28
|
+
assert directory.exists() and directory.is_dir()
|
29
|
+
|
30
|
+
directory = str(directory.resolve().absolute())
|
31
|
+
|
32
|
+
handler = partial(SimpleHTTPRequestHandler, directory=directory)
|
33
|
+
server = ThreadingHTTPServer((host, port), handler)
|
34
|
+
|
35
|
+
print(f"Serving files at http://{host}:{port} ... (ctrl+c to stop)")
|
36
|
+
|
37
|
+
server.serve_forever()
|
@@ -6,12 +6,13 @@ from pandas_render.base import Component
|
|
6
6
|
|
7
7
|
|
8
8
|
class Toggle(Component):
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
def __init__(
|
10
|
+
self,
|
11
|
+
content: str = "{{ content }}",
|
12
|
+
is_open: bool = False,
|
13
|
+
show: str = "Show",
|
14
|
+
hide: str = "Hide",
|
15
|
+
):
|
15
16
|
template = cleandoc("""
|
16
17
|
<div x-data="{ open: {{ is_open }} }" style="text-align: center;">
|
17
18
|
<div x-show="open">
|
@@ -23,10 +24,11 @@ class Toggle(Component):
|
|
23
24
|
|
24
25
|
output = JinjaTemplate(template).render(
|
25
26
|
dict(
|
26
|
-
is_open=
|
27
|
+
is_open="true" if is_open else "false",
|
27
28
|
content=content,
|
28
29
|
show=show,
|
29
30
|
hide=hide,
|
30
|
-
)
|
31
|
+
)
|
32
|
+
)
|
31
33
|
|
32
34
|
super().__init__(template=output)
|
pandas_render/elements/Image.py
CHANGED
@@ -4,9 +4,17 @@ from pandas_render.base import Element
|
|
4
4
|
|
5
5
|
|
6
6
|
class Image(Element):
|
7
|
-
|
8
|
-
|
7
|
+
def __init__(
|
8
|
+
self,
|
9
|
+
attribs: Optional[Dict[str, str]] = None,
|
10
|
+
):
|
9
11
|
if not attribs:
|
10
12
|
attribs = {}
|
11
|
-
|
12
|
-
|
13
|
+
if "src" not in attribs:
|
14
|
+
attribs["src"] = "{{ content }}"
|
15
|
+
if "loading" not in attribs:
|
16
|
+
attribs["loading"] = "lazy"
|
17
|
+
super().__init__(
|
18
|
+
tag="img",
|
19
|
+
attribs=attribs,
|
20
|
+
)
|
pandas_render/elements/Link.py
CHANGED
@@ -4,11 +4,19 @@ from pandas_render.base import Element
|
|
4
4
|
|
5
5
|
|
6
6
|
class Link(Element):
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
def __init__(
|
8
|
+
self,
|
9
|
+
attribs: Optional[Dict[str, str]] = None,
|
10
|
+
text: Optional[str] = "{{ content }}",
|
11
|
+
):
|
11
12
|
if not attribs:
|
12
13
|
attribs = {}
|
13
|
-
|
14
|
-
|
14
|
+
if "href" not in attribs:
|
15
|
+
attribs["href"] = "{{ content }}"
|
16
|
+
if "target" not in attribs:
|
17
|
+
attribs["target"] = "_blank"
|
18
|
+
super().__init__(
|
19
|
+
tag="a",
|
20
|
+
attribs=attribs,
|
21
|
+
text=text,
|
22
|
+
)
|
@@ -1,34 +1,75 @@
|
|
1
|
-
from
|
2
|
-
from inspect import cleandoc
|
1
|
+
from __future__ import annotations
|
3
2
|
|
4
|
-
|
5
|
-
from
|
3
|
+
from inspect import cleandoc, signature
|
4
|
+
from typing import Dict, List, Optional, Union
|
5
|
+
|
6
|
+
from IPython.display import HTML
|
6
7
|
from jinja2 import Template as JinjaTemplate
|
7
8
|
|
8
9
|
from pandas_render.base import Component, Element
|
9
10
|
from pandas_render.extensions import render
|
11
|
+
from pandas_render.utils import _chunk
|
12
|
+
|
13
|
+
try:
|
14
|
+
import pandas as pd
|
15
|
+
except ImportError:
|
16
|
+
pass
|
17
|
+
|
18
|
+
try:
|
19
|
+
import polars as pl
|
20
|
+
except ImportError:
|
21
|
+
pass
|
10
22
|
|
11
23
|
|
12
|
-
def render_dataframe(
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
24
|
+
def render_dataframe(
|
25
|
+
self: Union["pd.DataFrame", "pl.DataFrame"],
|
26
|
+
templates: Dict[str, Union[str, Element, Component]],
|
27
|
+
filter_columns: bool = False,
|
28
|
+
table_with_thead: bool = True,
|
29
|
+
table_column_names: Optional[List[str]] = None,
|
30
|
+
table_css_classes: Optional[List[str]] = ["dataframe"],
|
31
|
+
n: Optional[int] = None,
|
32
|
+
return_str: bool = False,
|
33
|
+
) -> Union[str, HTML]:
|
34
|
+
# Determine relevant columns:
|
35
|
+
if filter_columns:
|
36
|
+
column_names = list(templates.keys())
|
37
|
+
else:
|
38
|
+
column_names = [col for col in templates.keys() if col in self.columns] + [
|
39
|
+
col for col in self.columns if col not in templates.keys()
|
40
|
+
]
|
41
|
+
|
42
|
+
# Overwrite column names if custom names are provided:
|
43
|
+
if table_column_names is None or len(table_column_names) != len(column_names):
|
44
|
+
table_column_names = column_names
|
17
45
|
|
18
46
|
# Load templates:
|
19
47
|
jinja_templates = {}
|
20
|
-
for column, template in
|
48
|
+
for column, template in templates.items():
|
21
49
|
if column in list(self.columns):
|
22
50
|
jinja_templates[column] = JinjaTemplate(render(template))
|
23
51
|
|
52
|
+
# Convert data:
|
53
|
+
if hasattr(self, "to_dict"):
|
54
|
+
sig = signature(self.to_dict)
|
55
|
+
if "orient" in sig.parameters:
|
56
|
+
rows = self.to_dict(orient="records")
|
57
|
+
elif "as_series" in sig.parameters:
|
58
|
+
rows = self.to_dict(as_series=False)
|
59
|
+
rows = [dict(zip(rows, record)) for record in zip(*rows.values())]
|
60
|
+
else:
|
61
|
+
raise ValueError("Unsupported to_dict signature.")
|
62
|
+
else:
|
63
|
+
raise ValueError("Unsupported DataFrame type.")
|
64
|
+
|
24
65
|
# Render data:
|
25
66
|
rendered_rows = []
|
26
|
-
for row in
|
67
|
+
for row in rows:
|
27
68
|
rendered_row = {}
|
28
69
|
for column in row.keys():
|
29
|
-
if column in
|
70
|
+
if column in column_names:
|
30
71
|
if column in jinja_templates.keys():
|
31
|
-
values = {
|
72
|
+
values = {"content": row[column]}
|
32
73
|
values.update(row)
|
33
74
|
jinja_template = jinja_templates.get(column)
|
34
75
|
if jinja_template:
|
@@ -37,28 +78,62 @@ def render_dataframe(self: pd.DataFrame,
|
|
37
78
|
rendered_row[column] = row.get(column)
|
38
79
|
rendered_rows.append(rendered_row)
|
39
80
|
|
40
|
-
|
41
|
-
|
42
|
-
|
81
|
+
if (
|
82
|
+
n is not None
|
83
|
+
and isinstance(n, int)
|
84
|
+
and len(column_names) == 1
|
85
|
+
and column_names[0] in rendered_rows[0].keys()
|
86
|
+
):
|
87
|
+
# Render content as gallery:
|
88
|
+
column_name = column_names[0]
|
89
|
+
cells = [row[column_name] for row in rendered_rows]
|
90
|
+
rendered_rows = list(_chunk(cells, n=max(1, n)))
|
91
|
+
|
92
|
+
template = cleandoc("""
|
93
|
+
<table {% if table_css_classes %}class="{{ table_css_classes|join(' ') }}"{% endif %}>
|
94
|
+
{%- for row in rows -%}
|
43
95
|
<tr>
|
44
|
-
|
45
|
-
<
|
46
|
-
|
96
|
+
{%- for cell in row -%}
|
97
|
+
<td>{{ cell }}</td>
|
98
|
+
{%- endfor -%}
|
47
99
|
</tr>
|
48
|
-
</thead>
|
49
|
-
<tbody>
|
50
|
-
{%- for row in rows -%}
|
51
|
-
<tr>
|
52
|
-
{%- for column in columns -%}
|
53
|
-
<td>{{ row[column] }}</td>
|
54
100
|
{%- endfor -%}
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
101
|
+
</table>
|
102
|
+
""")
|
103
|
+
else:
|
104
|
+
# Render content as table:
|
105
|
+
template = cleandoc("""
|
106
|
+
<table {% if table_css_classes %}class="{{ table_css_classes|join(' ') }}"{% endif %}>
|
107
|
+
{%- if table_with_thead -%}
|
108
|
+
<thead>
|
109
|
+
<tr>
|
110
|
+
{%- for column_name in column_names -%}
|
111
|
+
<th>{{ column_name }}</th>
|
112
|
+
{%- endfor -%}
|
113
|
+
</tr>
|
114
|
+
</thead>
|
115
|
+
{%- endif -%}
|
116
|
+
<tbody>
|
117
|
+
{%- for row in rows -%}
|
118
|
+
<tr>
|
119
|
+
{%- for column in columns -%}
|
120
|
+
<td>{{ row[column] }}</td>
|
121
|
+
{%- endfor -%}
|
122
|
+
</tr>
|
123
|
+
{%- endfor -%}
|
124
|
+
</tbody>
|
125
|
+
</table>
|
126
|
+
""")
|
60
127
|
|
61
|
-
output = JinjaTemplate(template).render(
|
128
|
+
output = JinjaTemplate(template).render(
|
129
|
+
dict(
|
130
|
+
columns=column_names,
|
131
|
+
column_names=table_column_names,
|
132
|
+
rows=rendered_rows,
|
133
|
+
table_with_thead=table_with_thead,
|
134
|
+
table_css_classes=table_css_classes,
|
135
|
+
)
|
136
|
+
)
|
62
137
|
|
63
138
|
if return_str:
|
64
139
|
return output
|
@@ -1,31 +1,29 @@
|
|
1
|
-
from typing import Union
|
2
1
|
from inspect import cleandoc
|
2
|
+
from typing import List, Optional, Union
|
3
3
|
|
4
|
-
import pandas as pd
|
5
|
-
from IPython.display import HTML
|
4
|
+
import pandas as pd
|
5
|
+
from IPython.display import HTML
|
6
6
|
from jinja2 import Template as JinjaTemplate
|
7
7
|
|
8
8
|
from pandas_render.base.Element import Element
|
9
9
|
from pandas_render.extensions import render
|
10
|
+
from pandas_render.utils import _chunk
|
10
11
|
|
11
12
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
n: int = 1,
|
20
|
-
return_str: bool = False) -> Union[str, HTML]:
|
21
|
-
|
13
|
+
def render_series(
|
14
|
+
self: pd.Series,
|
15
|
+
template: Union[str, Element],
|
16
|
+
table_css_classes: Optional[List[str]] = ["dataframe"],
|
17
|
+
n: int = 1,
|
18
|
+
return_str: bool = False,
|
19
|
+
) -> Union[str, HTML]:
|
22
20
|
# Gather and render data:
|
23
21
|
jinja_template = JinjaTemplate(render(template))
|
24
22
|
cells = [jinja_template.render(dict(content=cell)) for cell in self]
|
25
23
|
rows = list(_chunk(cells, n=max(1, n)))
|
26
24
|
|
27
25
|
template = cleandoc("""
|
28
|
-
<table>
|
26
|
+
<table {% if table_css_classes %}class="{{ table_css_classes|join(' ') }}"{% endif %}>
|
29
27
|
{%- for row in rows -%}
|
30
28
|
<tr>
|
31
29
|
{%- for cell in row -%}
|
@@ -36,7 +34,12 @@ def render_series(self: pd.Series,
|
|
36
34
|
</table>
|
37
35
|
""")
|
38
36
|
|
39
|
-
output = JinjaTemplate(template).render(
|
37
|
+
output = JinjaTemplate(template).render(
|
38
|
+
dict(
|
39
|
+
rows=rows,
|
40
|
+
table_css_classes=table_css_classes,
|
41
|
+
)
|
42
|
+
)
|
40
43
|
|
41
44
|
if return_str:
|
42
45
|
return output
|
@@ -1,30 +1,32 @@
|
|
1
1
|
from typing import Union
|
2
2
|
|
3
|
-
from pandas_render.base import Element
|
4
|
-
from pandas_render.base import Component
|
5
|
-
|
6
|
-
from pandas_render.elements import collection as elements_collection
|
3
|
+
from pandas_render.base import Component, Element
|
7
4
|
from pandas_render.components import collection as components_collection
|
5
|
+
from pandas_render.elements import collection as elements_collection
|
8
6
|
|
9
7
|
|
10
8
|
def render(something: Union[str, Element, Component, type]) -> str:
|
11
9
|
if isinstance(something, str):
|
12
|
-
clazz = elements_collection.get(something) or components_collection.get(
|
10
|
+
clazz = elements_collection.get(something) or components_collection.get(
|
11
|
+
something
|
12
|
+
)
|
13
13
|
if clazz:
|
14
14
|
return clazz().render()
|
15
15
|
return something
|
16
16
|
|
17
17
|
# Check customized instances:
|
18
18
|
for clazz in [Element, Component]:
|
19
|
-
if isinstance(something, clazz) and hasattr(something,
|
19
|
+
if isinstance(something, clazz) and hasattr(something, "render"):
|
20
20
|
return something.render()
|
21
21
|
|
22
22
|
# Check passed classes:
|
23
|
-
collection = list(elements_collection.values()) + list(
|
23
|
+
collection = list(elements_collection.values()) + list(
|
24
|
+
components_collection.values()
|
25
|
+
)
|
24
26
|
for clazz in collection:
|
25
27
|
if issubclass(something, clazz):
|
26
28
|
something = something()
|
27
|
-
if hasattr(something,
|
29
|
+
if hasattr(something, "render"):
|
28
30
|
return something.render()
|
29
31
|
|
30
|
-
return
|
32
|
+
return "{{ content }}"
|
pandas_render/utils.py
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
from collections import namedtuple
|
2
|
+
from inspect import cleandoc
|
3
|
+
from typing import List, Tuple, Union
|
4
|
+
|
5
|
+
from IPython.display import Javascript
|
6
|
+
from jinja2 import Template as JinjaTemplate
|
7
|
+
|
8
|
+
|
9
|
+
def load(
|
10
|
+
libraries: Union[
|
11
|
+
str,
|
12
|
+
Tuple[str, str],
|
13
|
+
List[Union[str, Tuple[str, str]]],
|
14
|
+
],
|
15
|
+
return_str: bool = False,
|
16
|
+
):
|
17
|
+
"""Load external JavaScript libraries synchronously."""
|
18
|
+
if isinstance(libraries, (str, tuple)):
|
19
|
+
libraries = [libraries]
|
20
|
+
|
21
|
+
Library = namedtuple("Library", "name src")
|
22
|
+
valid_libraries: List[Library] = []
|
23
|
+
|
24
|
+
for library in libraries:
|
25
|
+
if isinstance(library, str):
|
26
|
+
if library == "alpinejs":
|
27
|
+
library = Library(
|
28
|
+
name="alpinejs",
|
29
|
+
src="https://unpkg.com/alpinejs",
|
30
|
+
)
|
31
|
+
valid_libraries.append(library)
|
32
|
+
else:
|
33
|
+
if isinstance(library, tuple):
|
34
|
+
library = Library(name=library[0], src=library[1])
|
35
|
+
valid_libraries.append(library)
|
36
|
+
|
37
|
+
template = JinjaTemplate(
|
38
|
+
cleandoc("""
|
39
|
+
var loadScriptSync = function(name, src) {
|
40
|
+
if (document.querySelector('script[data-pandas-render-library="' + name + '"]')) {
|
41
|
+
return;
|
42
|
+
}
|
43
|
+
var script = document.createElement('script');
|
44
|
+
script.src = src;
|
45
|
+
script.type = 'text/javascript';
|
46
|
+
script.async = false;
|
47
|
+
script.setAttribute("data-pandas-render-library", name);
|
48
|
+
document.getElementsByTagName('head')[0].appendChild(script);
|
49
|
+
};
|
50
|
+
{%- for library in libraries -%}
|
51
|
+
loadScriptSync("{{ library.name }}", "{{ library.src }}");
|
52
|
+
{%- endfor -%}
|
53
|
+
"""),
|
54
|
+
autoescape=False,
|
55
|
+
)
|
56
|
+
|
57
|
+
output = ""
|
58
|
+
if len(valid_libraries) > 0:
|
59
|
+
output = template.render(libraries=valid_libraries)
|
60
|
+
|
61
|
+
if return_str:
|
62
|
+
return output
|
63
|
+
|
64
|
+
return Javascript(output)
|
65
|
+
|
66
|
+
|
67
|
+
def _chunk(sequence, n: int):
|
68
|
+
for i in range(0, len(sequence), n):
|
69
|
+
yield sequence[i : i + n]
|
@@ -0,0 +1,99 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: pandas-render
|
3
|
+
Version: 0.3.0
|
4
|
+
Summary: A pandas extension for rendering DataFrames
|
5
|
+
Project-URL: Repository, https://github.com/nok/pandas-render
|
6
|
+
Project-URL: Issues, https://github.com/nok/pandas-render/issues
|
7
|
+
Author-email: Darius Morawiec <nok@users.noreply.github.com>
|
8
|
+
License-Expression: BSD-3-Clause
|
9
|
+
License-File: LICENSE
|
10
|
+
Classifier: Programming Language :: Python
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
13
|
+
Requires-Python: >=3.9
|
14
|
+
Requires-Dist: ipython>=7.11.1
|
15
|
+
Requires-Dist: jinja2>=3.0.0
|
16
|
+
Requires-Dist: typer>=0.15.2
|
17
|
+
Provides-Extra: examples
|
18
|
+
Requires-Dist: jupyterlab>=4.3.6; extra == 'examples'
|
19
|
+
Provides-Extra: pandas
|
20
|
+
Requires-Dist: pandas>=1.0.0; extra == 'pandas'
|
21
|
+
Provides-Extra: polars
|
22
|
+
Requires-Dist: polars>=1.0.0; extra == 'polars'
|
23
|
+
Description-Content-Type: text/markdown
|
24
|
+
|
25
|
+
<p align="center">
|
26
|
+
<img src="/assets/pandas-render.png" alt="pandas-render" height=130>
|
27
|
+
</p>
|
28
|
+
|
29
|
+
<h1 align="center">pandas-render</h1>
|
30
|
+
|
31
|
+
<p align="center">Render <a href="https://github.com/pandas-dev/pandas" target="_pandas">pandas</a> or <a href="https://github.com/pola-rs/polars" target="_polars">polars</a> DataFrames and Series as HTML tables with flexibility for formatting and styling.</p>
|
32
|
+
|
33
|
+
<div align="center">
|
34
|
+
|
35
|
+

|
36
|
+
[](https://ko-fi.com/nok)
|
37
|
+
[](LICENSE)
|
38
|
+
|
39
|
+
</div>
|
40
|
+
|
41
|
+
|
42
|
+
## Installation
|
43
|
+
|
44
|
+
```bash
|
45
|
+
pip install pandas-render[pandas]
|
46
|
+
```
|
47
|
+
|
48
|
+
```bash
|
49
|
+
pip install pandas-render[polars]
|
50
|
+
```
|
51
|
+
|
52
|
+
|
53
|
+
## Usage
|
54
|
+
|
55
|
+
This is a simple example that demonstrates the basic functionality. The column names are used to match individual [Jinja2](https://github.com/pallets/jinja) templates. And `{{ content }}` is the placeholder for the content of the original cell.
|
56
|
+
|
57
|
+
```python
|
58
|
+
from pandas_render import pandas as pd
|
59
|
+
|
60
|
+
df = pd.DataFrame(
|
61
|
+
[
|
62
|
+
dict(name="Alice", age=25, hobbies=["coding"]),
|
63
|
+
dict(name="Bob", age=30, hobbies=["reading", "hiking"]),
|
64
|
+
]
|
65
|
+
)
|
66
|
+
|
67
|
+
df.render(
|
68
|
+
templates=dict(
|
69
|
+
name="<strong>{{ content }}</strong>",
|
70
|
+
age="{{ content }} years old",
|
71
|
+
hobbies="<em>{{ content|join(', ') }}</em>",
|
72
|
+
),
|
73
|
+
table_column_names=["Name", "Age", "Hobbies"],
|
74
|
+
)
|
75
|
+
```
|
76
|
+
|
77
|
+
The result is a rendered dataframe:
|
78
|
+
|
79
|
+
<table class="dataframe"><thead><tr><th>Name</th><th>Age</th><th>Hobbies</th></tr></thead><tbody><tr><td><strong>Alice</strong></td><td>25 years old</td><td><em>coding</em></td></tr><tr><td><strong>Bob</strong></td><td>30 years old</td><td><em>reading, hiking</em></td></tr></tbody></table>
|
80
|
+
|
81
|
+
|
82
|
+
## Examples
|
83
|
+
|
84
|
+
Exciting and more powerful features can be explored and learned in the [Getting Started](examples/01_getting_started.ipynb) notebook.
|
85
|
+
|
86
|
+
List of all notebooks with examples:
|
87
|
+
|
88
|
+
- [Getting Started](examples/01_getting_started.ipynb) ✨
|
89
|
+
- [Components](examples/02_components.ipynb)
|
90
|
+
|
91
|
+
|
92
|
+
## Contributing
|
93
|
+
|
94
|
+
We encourage you to contribute to this project! Please check out the [contributing guidelines](CONTRIBUTING.md) about how to proceed.
|
95
|
+
|
96
|
+
|
97
|
+
## License
|
98
|
+
|
99
|
+
This package is Open Source Software released under the [BSD-3-Clause](LICENSE) license.
|
@@ -0,0 +1,20 @@
|
|
1
|
+
pandas_render/__init__.py,sha256=_xXSaWNUDJE1UUwUOQA_v0qAvz9EFSZHvFopaOX23t4,751
|
2
|
+
pandas_render/utils.py,sha256=7A4Jb4fiZ9NxqI5pgfvEFFqDYGSW0oe1v_8hnTzBr6o,2058
|
3
|
+
pandas_render/base/Component.py,sha256=kqUkICpnwESyiYXdhwZmqiOApphQ1GXLgO2jkwvuXGA,148
|
4
|
+
pandas_render/base/Element.py,sha256=0brsb8SeImB9CwlFkR5y5GvPTYfzQ4xkZXIxyIf45TE,479
|
5
|
+
pandas_render/base/__init__.py,sha256=Et3vXoZBjHarsVva2LRO4__JjmQnwtMibnsDOiH1gpc,114
|
6
|
+
pandas_render/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
+
pandas_render/cli/__main__.py,sha256=5BR8Lv1EOrvw6sUTFmUnautm4dH3zXFT3XhtdK1_Trg,874
|
8
|
+
pandas_render/components/Toggle.py,sha256=k95XtPiIOUU87mYjbndqF4-znTUFunhCHajtMKCdatI,899
|
9
|
+
pandas_render/components/__init__.py,sha256=UyNFQF74f3A5EX-0fMFUKdZ793IdHiBfsgqJ5ZypnQc,85
|
10
|
+
pandas_render/elements/Image.py,sha256=z4JpBhsu02lkNiUubPS9IzRrgq157j4ukuw5lJIhBjU,479
|
11
|
+
pandas_render/elements/Link.py,sha256=ICmCPtzERbiiH7UhkBG7I47MarMqXkKw9t3ThZULbGY,548
|
12
|
+
pandas_render/elements/__init__.py,sha256=ypHBGJogLiq8HeWsK0ipfd5KfIRxU1SYJF7XUL8imPU,135
|
13
|
+
pandas_render/extensions/DataFrame.py,sha256=nIG_Tic7IXIKYITXH7rDqV6kie9H5im_Da0Zd5rHywE,4449
|
14
|
+
pandas_render/extensions/Series.py,sha256=Qsyshb5zMCY6fbh742t9Y1hy56xhtsqUAzh9K8Afags,1240
|
15
|
+
pandas_render/extensions/__init__.py,sha256=yK50vqpfLpXWV6XL0QYIrb9UhMrq5rXKmlxBdlqZ5Yg,1056
|
16
|
+
pandas_render-0.3.0.dist-info/METADATA,sha256=KGdLgk5H1jcU3Hx6j2_KKJKZQAkue0cN7BoHolG0o9g,3260
|
17
|
+
pandas_render-0.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
18
|
+
pandas_render-0.3.0.dist-info/entry_points.txt,sha256=fi51l72yIjjuNfbp_u9RvlYsIICe9Q-taHj-AKaOtG0,58
|
19
|
+
pandas_render-0.3.0.dist-info/licenses/LICENSE,sha256=ksCNzrXJZsQw-h1lYI9-n9gzQDUsFJBQOZoCkSNZmJU,1532
|
20
|
+
pandas_render-0.3.0.dist-info/RECORD,,
|
@@ -1,37 +0,0 @@
|
|
1
|
-
https://raw.githubusercontent.com/jupyterlab/jupyterlab/master/LICENSE
|
2
|
-
|
3
|
-
-------------------------------------------------------------------------------
|
4
|
-
|
5
|
-
Copyright (c) 2015-2021 Project Jupyter Contributors
|
6
|
-
All rights reserved.
|
7
|
-
|
8
|
-
Redistribution and use in source and binary forms, with or without
|
9
|
-
modification, are permitted provided that the following conditions are met:
|
10
|
-
|
11
|
-
1. Redistributions of source code must retain the above copyright notice, this
|
12
|
-
list of conditions and the following disclaimer.
|
13
|
-
|
14
|
-
2. Redistributions in binary form must reproduce the above copyright notice,
|
15
|
-
this list of conditions and the following disclaimer in the documentation
|
16
|
-
and/or other materials provided with the distribution.
|
17
|
-
|
18
|
-
3. Neither the name of the copyright holder nor the names of its
|
19
|
-
contributors may be used to endorse or promote products derived from
|
20
|
-
this software without specific prior written permission.
|
21
|
-
|
22
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
-
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
25
|
-
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
26
|
-
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
27
|
-
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
28
|
-
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
29
|
-
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
30
|
-
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
31
|
-
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32
|
-
|
33
|
-
Semver File License
|
34
|
-
===================
|
35
|
-
|
36
|
-
The semver.py file is from https://github.com/podhmo/python-semver
|
37
|
-
which is licensed under the "MIT" license. See the semver.py file for details.
|
@@ -1,35 +0,0 @@
|
|
1
|
-
https://raw.githubusercontent.com/pandas-dev/pandas/master/LICENSE
|
2
|
-
|
3
|
-
-------------------------------------------------------------------------------
|
4
|
-
|
5
|
-
BSD 3-Clause License
|
6
|
-
|
7
|
-
Copyright (c) 2008-2011, AQR Capital Management, LLC, Lambda Foundry, Inc. and PyData Development Team
|
8
|
-
All rights reserved.
|
9
|
-
|
10
|
-
Copyright (c) 2011-2021, Open source contributors.
|
11
|
-
|
12
|
-
Redistribution and use in source and binary forms, with or without
|
13
|
-
modification, are permitted provided that the following conditions are met:
|
14
|
-
|
15
|
-
* Redistributions of source code must retain the above copyright notice, this
|
16
|
-
list of conditions and the following disclaimer.
|
17
|
-
|
18
|
-
* Redistributions in binary form must reproduce the above copyright notice,
|
19
|
-
this list of conditions and the following disclaimer in the documentation
|
20
|
-
and/or other materials provided with the distribution.
|
21
|
-
|
22
|
-
* Neither the name of the copyright holder nor the names of its
|
23
|
-
contributors may be used to endorse or promote products derived from
|
24
|
-
this software without specific prior written permission.
|
25
|
-
|
26
|
-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
27
|
-
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
28
|
-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
29
|
-
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
30
|
-
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
31
|
-
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
32
|
-
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
33
|
-
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
34
|
-
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
35
|
-
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@@ -1,34 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.1
|
2
|
-
Name: pandas-render
|
3
|
-
Version: 0.2.1
|
4
|
-
Summary:
|
5
|
-
Home-page: https://github.com/nok/pandas-render
|
6
|
-
License: BSD-3-Clause
|
7
|
-
Author: Darius Morawiec
|
8
|
-
Author-email: nok@users.noreply.github.com
|
9
|
-
Requires-Python: >=3.6.2
|
10
|
-
Classifier: License :: OSI Approved :: BSD License
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
12
|
-
Classifier: Programming Language :: Python :: 3.10
|
13
|
-
Classifier: Programming Language :: Python :: 3.7
|
14
|
-
Classifier: Programming Language :: Python :: 3.8
|
15
|
-
Classifier: Programming Language :: Python :: 3.9
|
16
|
-
Classifier: Topic :: Scientific/Engineering :: Visualization
|
17
|
-
Requires-Dist: Jinja2 (>=3.0.0)
|
18
|
-
Requires-Dist: jupyterlab (>=1.2.6)
|
19
|
-
Requires-Dist: pandas (>=1.0.0)
|
20
|
-
Project-URL: Repository, https://github.com/nok/pandas-render
|
21
|
-
Description-Content-Type: text/markdown
|
22
|
-
|
23
|
-
# pandas-render
|
24
|
-
|
25
|
-
## Installation
|
26
|
-
|
27
|
-
```bash
|
28
|
-
pip install pandas-render
|
29
|
-
```
|
30
|
-
|
31
|
-
## License
|
32
|
-
|
33
|
-
This package is Open Source Software released under the [BSD-3-Clause](blob/main/LICENSE) license.
|
34
|
-
|
@@ -1,18 +0,0 @@
|
|
1
|
-
pandas_render/__init__.py,sha256=59VcwTEwAzWhsETmuq6JyxHgnyJl4I-BxmrLE0VgUTU,2673
|
2
|
-
pandas_render/base/Component.py,sha256=lcc2oufJhc2a2O3tWaUV1ZIUZrZT_Jz4DVC0wJT5Wxk,149
|
3
|
-
pandas_render/base/Element.py,sha256=R5fWu2vDuHvffgGYlEnMzt-WIZhTZWqTSyT7sCG8iJk,442
|
4
|
-
pandas_render/base/__init__.py,sha256=MCCHIX1ebpDCS40uJibW6QwtPyoSRXuMPjZ3c3rnSGE,98
|
5
|
-
pandas_render/components/Toggle.py,sha256=W32fsD9hlMBpcMHICW2FHxmJZDBjbpm435G5qRBRyV0,912
|
6
|
-
pandas_render/components/__init__.py,sha256=UyNFQF74f3A5EX-0fMFUKdZ793IdHiBfsgqJ5ZypnQc,85
|
7
|
-
pandas_render/elements/Image.py,sha256=ckE9pVgTJdG61iJdrzvwyxEq-3f9uL8JDowkB9R5dtQ,338
|
8
|
-
pandas_render/elements/Link.py,sha256=y9VXGw-vvQFoCbtNeKidIHzwwP7_gPKGev7PyDM0Pbc,399
|
9
|
-
pandas_render/elements/__init__.py,sha256=ypHBGJogLiq8HeWsK0ipfd5KfIRxU1SYJF7XUL8imPU,135
|
10
|
-
pandas_render/extensions/DataFrame.py,sha256=7APLDX2qjRjXW5r7nEHHQcUjlw_oV2QC9AK7HC5jTiY,2102
|
11
|
-
pandas_render/extensions/Series.py,sha256=GWEaYDiyDuQE8yy1_jQH-bS46fdl1H6cfFxA5t0xu84,1117
|
12
|
-
pandas_render/extensions/__init__.py,sha256=79tcjCH9V6BER7NMRNravfcFq5-GUrknKS1k6HwmeXk,1051
|
13
|
-
pandas_render-0.2.1.dist-info/LICENSE,sha256=11vakp7Zm8HYAmDo4Zr8bwSCGGH_o-TsOw_eNuhL190,1523
|
14
|
-
pandas_render-0.2.1.dist-info/LICENSES/JUPYTERLAB_LICENSE,sha256=qfT49q5wmmHkR2VtOWJVJFGdw7qqUE4eZ4vpy6ZK9lg,1860
|
15
|
-
pandas_render-0.2.1.dist-info/LICENSES/PANDAS_LICENSE,sha256=zyJYWK1-R8cQQC0YT4IgH7KuLX0KFgqg5eowQBqw2T0,1783
|
16
|
-
pandas_render-0.2.1.dist-info/WHEEL,sha256=y3eDiaFVSNTPbgzfNn0nYn5tEn1cX6WrdetDlQM4xWw,83
|
17
|
-
pandas_render-0.2.1.dist-info/METADATA,sha256=dglcvqHtfiYjnfbnAarOIcYagv4BnccNSuaLG9wg-xc,978
|
18
|
-
pandas_render-0.2.1.dist-info/RECORD,,
|