Skip to content

Commit

Permalink
Implement dataview for HTML representations
Browse files Browse the repository at this point in the history
  • Loading branch information
edsaac committed May 18, 2024
1 parent 8deca2a commit 3c70c51
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 3 deletions.
3 changes: 3 additions & 0 deletions stpyvista/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## [v 0.0.18] - 2024-05-17
- Introduce `dataview` to display HTML representation of pyvista data

## [v 0.0.17] - 2024-04-11
- Rewrite buffer using context manager
- Introduce and experimental viewer based on trame and vanilla vtk-js
Expand Down
2 changes: 1 addition & 1 deletion stpyvista/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "stpyvista"
version = "0.0.17"
version = "0.0.18"
authors = [
{ name="Edwin Saavedra C.", email="[email protected]" },
]
Expand Down
80 changes: 78 additions & 2 deletions stpyvista/src/stpyvista/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
from pathlib import Path
from typing import Optional, Literal
import base64
import xml.dom.minidom

import streamlit as st
import streamlit.components.v1 as components

from pyvista.plotting import Plotter
from pyvista import DataSet

import panel as pn

from bokeh.resources import CDN, INLINE

pn.extension("vtk", sizing_mode="stretch_both")
Expand All @@ -32,7 +35,9 @@ class stpyvistaValueError(ValueError):
)


def experimental_vtkjs(vtksz_data: bytes, height: int = 400, key: Optional[str] = None) -> dict:
def experimental_vtkjs(
vtksz_data: bytes, height: int = 400, key: Optional[str] = None
) -> dict:
"""
Renders an interactive Pyvista Plotter in streamlit.
Expand Down Expand Up @@ -149,6 +154,77 @@ def stpyvista(
raise stpyvistaTypeError(f"{plotter} is not a `pyvista.Plotter` instance. ")


def dataview(obj: DataSet):
"""
Renders the HTML representation of a Pyvista/VTK dataset.
Parameters
----------
element: pv.DataSet
Pyvista element with some data to show.
Returns
-------
None
"""

def assemble_details(title: str, table: str) -> str:
return f"<details open><summary><em>{title}</em></summary>{table}</details>"

try:
# Look up an HTML representation and arange in details tags

dom = xml.dom.minidom.parseString(obj._repr_html_())
tables = dom.getElementsByTagName("table")

css = """
<style>
details {
padding: 6px;
margin-bottom: 5px;
border: 1px solid #eeeeee;
background-color: transparent;
border-radius: 10px;
}
summary {
background-color: transparent;
opacity: 60%;
padding: 5px;
}
summary::marker {
color: purple;
font-size: 1.1em;
}
</style>
"""

html = StringIO("""<div class="stpv-dataview">""")

if len(tables) == 1:
html.write(assemble_details("Header", tables[0].toprettyxml()))

else:
headers = (
dom.getElementsByTagName("table")[0]
.getElementsByTagName("tr")[0]
.getElementsByTagName("th")
)

for title, table in zip(headers, tables[1:]):
html.write(
assemble_details(title.firstChild.nodeValue, table.toprettyxml())
)

html.write(css + "</div>")

# Render in streamlit
st.html(html.getvalue())

except AttributeError:
# Defaults to streamlit's write function
st.write(obj)


def main():
pass

Expand Down
58 changes: 58 additions & 0 deletions stpyvista/test/dataview.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import streamlit as st
import pyvista as pv
import numpy as np
from stpyvista import stpyvista, dataview

def put_in_plotter(actor: pv.DataSet):
plotter = pv.Plotter()
plotter.window_size = (300, 300)
plotter.add_mesh(actor, color='purple', line_width=10)
plotter.view_isometric()
return plotter

def sphere():
return pv.Sphere(radius=1.0, center=(0, 0, 0))

def spline():
theta = np.linspace(-1 * np.pi, 1 * np.pi, 100)
z = np.linspace(2, -2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
points = np.column_stack((x, y, z))
return pv.Spline(points, 1000)

def surface():
x = np.arange(-10, 10, 0.5)
y = np.arange(-10, 10, 0.5)
x, y = np.meshgrid(x, y)
z = np.sin(np.sqrt(x**2 + y**2))
surf = pv.StructuredGrid(x, y, z)
x, y, z = surf.cell_centers().points.T
surf["my_scalar"] = x * y * z

return surf


def main():

st.title("Testing `dataview`")

datasets = [
sphere(),
spline(),
surface()
]

for obj in datasets:
cols = st.columns([1, 1.5])

with cols[0]:
stpyvista(put_in_plotter(obj))
with cols[1]:
dataview(obj)

dataview(pv.MultiBlock(datasets))

if __name__ == "__main__":
main()

0 comments on commit 3c70c51

Please sign in to comment.