respysive-slide


Namerespysive-slide JSON
Version 1.1.15 PyPI version JSON
download
home_pageNone
SummaryA Python package that allows you to create interactive presentations using Python, Bootstrap and Reveal.js. Charts from Altair and Plotly can also be added
upload_time2025-07-29 19:36:54
maintainerNone
docs_urlNone
authorfbxyz
requires_python>=3.7
licenseNone
keywords slide presentation reveal.js bootstrap
VCS
bugtrack_url
requirements beautifulsoup4 certifi charset-normalizer contourpy cycler fonttools idna kiwisolver matplotlib numpy packaging pillow pyparsing python-dateutil requests six soupsieve typing-extensions urllib3
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # respysive-slide
___
A Python package that allows you to create interactive presentations using Python, 
Bootstrap and Reveal.js. 
Charts from Matplotlib Altair and Plotly can be easily added.

![respysiv.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/respysiv.png)

You will find a <a href="https://raw.githack.com/fbxyz/respysive-slide/master/readme_example.html" target="_blank">live example here</a>


___
## Installation
With PyPI 
```
pip install respysive-slide
```

Upgrade
```
pip install respysive-slide --upgrade
```

You can also clone the <a href="https://github.com/fbxyz/respysive-slide" target="_blank">repo</a> and import respysive as a module

___
## Usage

The package consists of two main classes: `Presentation` and `Slide`.

`Presentation` is the main instance, containing your slides. 

`Slide` is used to create a unique slide. You can add various elements to it such as text, headings, images, cards etc.

Each `Slide` instance is added to the `Presentation` instance for final rendering.

### Creating a new presentation
Here's an example of how to use `respysive-slide`

```python
from respysive import Slide, Presentation

# Create a new presentation
p = Presentation()

# Create the first slide with a centered layout
slide1 = Slide(center=True)

# Content for the title page
logo_url = "https://upload.wikimedia.org/wikipedia/commons/4/4d/Fractal_canopy.svg"
title_page_content = {
    'title': 'Your presentation title',
    'subtitle': 'Your subtitle',
    'authors': 'Author 1, Author 2',
    'logo': logo_url
}

# Styles for the title page content in the same order as content
styles = [
    {'color': '#e63946', 'class': 'r-fit-text border-top'},  # title
    {},  # subtitle style by default
    {},  # authors style by default
    {'filter': 'invert(100%) opacity(30%)'},  # logo
]

# Add the title page to the slide
slide1.add_title_page(title_page_content, styles)
```

You can pass CSS styles and classes as kwargs. For example, in the code below,
the add_title method takes a dictionary kwarg `styles` containing : 
 - one or several CSS styles as key : values
 - and class as a unique key:

![slide1.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide1.png)

### Split title page layout

As an alternative to the classic title page, you can create a split layout with the title content on one side and custom content (logo, image, chart) on the other side using `add_split_title_page()`:

```python
# Create a slide with split title page layout
slide1b = Slide(center=True)

# Content for the split title page
split_title_content = {
    'title': 'Your presentation title',
    'subtitle': 'Your subtitle',
    'authors': 'Author 1, Author 2',
}

# Styles for the title elements  
title_styles = [
    {'color': '#e63946', 'font-weight': 'bold', 'font-size': '60px'},  # title
    {'color': '#457b9d', 'font-size': '40px'},  # subtitle
    {'color': '#457b9d', 'font-size': '25px'},  # authors
]

# Style for the title column 
title_column_style = {
    'background-color': '#1d3557', 
    'color': '#f1faee',             
    'padding': '40px',              
    'border-radius': '10px 0 0 10px'  
}

# Style for the custom content column 
image_style = {
    'text-align': 'center',
    'padding': '30px',
    'background-color': '#e63946',
    'border-radius': '0 10px 10px 0'  
}

# Add the split title page - title on left (8 cols), logo on right (4 cols)
slide1b.add_split_title_page(
    title_page_content=split_title_content,
    custom_content=logo_url,
    title_column_width=8,
    custom_column_width=4,
    title_page_class="split-intro",
    custom_content_style=image_style,
    title_styles=title_styles,
    title_column_style=title_column_style  
)
```

![split_title.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/split_title.png)



### A simple text slide

Now, lets create a simple slide with a title and some content. 

Markdown is more intuitive, so we will use it, but it's not mandatory.

 ```python
# Create the second slide
slide2 = Slide()

# Add a title to the slide with a fontawesome icon
slide2.add_title("Your title with a fontawesome icon", icon="fas fa-infinity fa-beat")

# Create some text in markdown format
txt = markdown("""
This is some dummy text 

- and it's easier to use Markdown
<ul><li>but it's ok to use HTML tag</li></ul>
""")

# Add the text to the slide in a new Bootstrap column with a width of 12 (default)
slide2.add_content([txt], columns=[12])
 ```
Note that for the add_title() method, <a href="https://fontawesome.com/icons" target="_blank">Fontawesome icons</a> can be added.

![slide2.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide2.png)

### A two columns slide with text and image

Let's add  two columns : 
- the first with some text
- the second with an image

`respysive-slide` will try to find automatically the content type (txt, image, chart from json). 
You only have to pass the content list with the add_content() method

 ```python    
# Create a new slide
slide3 = Slide()

text = markdown("""
En cosmologie, le modèle de l'univers fractal désigne un modèle cosmologique 
dont la structure et la répartition de la matière possèdent une dimension fractale, 
et ce, à plusieurs niveaux. 

De façon plus générale, il correspond à l'usage ou 
l'apparence de fractales dans l'étude de l'Univers et de la matière qui le compose.
Ce modèle présente certaines lacunes lorsqu'il est utilisé à de très grandes ou de 
très petites échelles.

""")

# Add image url
url = "./assets/img/Univers_Fractal_J.H..jpg"

# Add title to slide
slide3.add_title("Bootstrap powering")

# Add styles to slide
css_txt = [
    {'font-size': '70%', 'text-align': 'justify', 'class': 'bg-warning'},  # text style
    None  # url style is mandatory even it is None
]

# Add content to slide, where text and url are added to the slide with 7 and 5 columns respectively
# css_txt is added as styles
slide3.add_content([text, url], columns=[7, 5], styles=css_txt)
```

Note that class can include <a href="https://revealjs.com/fragments/" target="_blank">Reveal.js fragments</a> for step-by-step content reveal.

![slide3.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide3.png)

### Plotly, Altair and Matplotlib
Plotly, Altair or Matplotlib graphs can be easily added with `add_content()`. Interactivity 
is fully functional for Plotly and Altair.

```python
slide4 = Slide()
slide4.add_title("Plotly")

# import plotly express for creating scatter plot
import plotly.express as px

# load iris data
df = px.data.iris()

# create scatter plot
fig = px.scatter(df, x="sepal_width", y="sepal_length",
                 color="species", size="petal_length", hover_data=["petal_width"])

# update layout
fig.update_layout(autosize=True)

# Export the figure to json format
j = fig.to_json()

# apply css to the figure
css_txt = [{'class': 'stretch'}]

# add the scatter plot to the slide
slide4.add_content([j], columns=[12], styles=css_txt)

```  
![slide4.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide4.png)

#### Sharing GeoJSON data between multiple Plotly charts

You can optimize performance by sharing large data (like GeoJSON) between multiple charts across the entire presentation.

**Simple example:**
```python
# Add shared data once
p.add_global_geojson("my_data", geojson_dict)
# Use in multiple charts with shared_data_ids parameter  
slide.add_content([chart1, chart2],
                  columns=[6, 6],
                  shared_data_ids=["my_data", "my_data"])
```

**Complete example:**
```python
from respysive import Presentation, Slide

# Create presentation
p = Presentation()

# Load GeoJSON data
from urllib.request import urlopen
import json
with urlopen('https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json') as response:
    counties = json.load(response)

# Load unemployment data
import pandas as pd
df_counties = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/fips-unemp-16.csv", dtype={"fips": str})

# Add additional columns with pandas
import random
random.seed(42)
df_counties['population'] = [random.randint(10000, 500000) for _ in range(len(df_counties))]
df_counties['income'] = [random.randint(25000, 85000) for _ in range(len(df_counties))]
# Add area data for density calculation
df_counties['area_sq_miles'] = [random.randint(200, 2000) for _ in range(len(df_counties))]
df_counties['density'] = (df_counties['population'] / df_counties['area_sq_miles']).round(1)

# Add global geojson data to presentation
p.add_global_geojson("us_counties", counties)

slide_maps = Slide()
slide_maps.add_title("Sharing geojson data between multiple plotly charts", **{'class': 'r-fit-text'})

# Add context text
context_text = """
Counties geojson data (~2MB) is shared across the presentation
"""

css_txt = [{'text-align': 'center', 'font-size': "70%"}]

slide_maps.add_content([context_text], columns=[12], styles=css_txt)

# Create population density map
population_config = {
    "data": [{
        "type": "choropleth",
        "locations": df_counties['fips'].tolist(),
        "z": df_counties['density'].tolist(),
        "colorscale": "Blues",
        "colorbar": {
            "title": "Density<br>(per sq mi)",
            "thickness": 15,
            "len": 0.7
        },
        "hovertemplate": (
            "<b>County {text}</b><br>" +
            "Population: %{customdata[0]:,.0f}<br>" +
            "Area: %{customdata[1]:,.0f} sq mi<br>" + 
            "Density: <b>%{z:.1f} per sq mi</b>" +
            "<extra></extra>"
        ),
        "text": df_counties['fips'].tolist(),
        "customdata": list(zip(df_counties['population'], df_counties['area_sq_miles']))
    }],
    "layout": {
        "geo": {
            "projection": {"type": "albers usa"}, 
            "scope": "usa",
            "showlakes": True,
            "lakecolor": "lightblue"
        },
        "title": {
            "text": "Population Density by County (Random Data)",
            "x": 0.5,
            "xanchor": "center",
            "font": {"size": 16}
        },
        "margin": {"r":10,"t":50,"l":10,"b":10}
    }
}

# Create choropleth map for income
income_config = {
    "data": [{
        "type": "choroplethmap",
        "locations": df_counties['fips'].tolist(),
        "z": df_counties['income'].tolist(),
        "colorscale": [
            [0.0, "#ffffb2"],
            [0.2, "#fed976"],
            [0.4, "#feb24c"],
            [0.6, "#fd8d3c"],
            [0.8, "#f03b20"],
            [1.0, "#bd0026"]
        ],
        "colorbar": {
            "title": {
                "text": "Median Income ($)",
                "font": {"size": 14, "family": "Arial Black"}
            },
            "thickness": 20,
            "len": 0.8,
            "x": 1.02,
            "tickmode": "array",
            "tickvals": [25000, 40000, 55000, 70000, 85000],
            "ticktext": ["$25K", "$40K", "$55K", "$70K", "$85K"],
            "tickfont": {"size": 11}
        },
        "hovertemplate": (
            "<b>County FIPS: %{location}</b><br>" +
            "Median Income: <b>$%{z:,.0f}</b><br>" +
            "Population: <b>%{customdata:,.0f}</b>" +
            "<extra></extra>"
        ),
        "customdata": df_counties['population'].tolist(),
        "marker": {
            "line": {"color": "white", "width": 0.5},
            "opacity": 0.9
        }
    }],
    "layout": {
        "map": {
            "style": "carto-positron",
            "zoom": 3.2,
            "center": {"lat": 38.0, "lon": -97.0}
        },
        "title": {
            "text": "Median Household Income by County (Random Data)",
            "x": 0.5,
            "xanchor": "center",
            "font": {
                "size": 18,
                "family": "Arial Black", 
                "color": "#2E86AB"
            },
            "pad": {"t": 20}
        },
        "annotations": [{
            "text": "Data source: Simulated random data",
            "showarrow": False,
            "x": 0.99,
            "y": 0.01,
            "xref": "paper",
            "yref": "paper",
            "xanchor": "right",
            "yanchor": "bottom",
            "font": {"size": 10, "color": "gray"}
        }],
        "margin": {"r":80,"t":80,"l":20,"b":40},
        "paper_bgcolor": "rgba(248, 249, 250, 0.95)"
    }
}

# Add the two maps side by side using shared GeoJSON data
slide_maps.add_content(
    [population_config, income_config], 
    columns=[6, 6],
    shared_data_ids=["us_counties", "us_counties"]
)
```

This approach stores the large `counties` GeoJSON data (~2MB) only once globally in the presentation. Multiple maps across any slides can then reference this shared data, avoiding duplication.

**Compatible map types:**
- `choropleth` - Standard geographic choropleth maps
- `choroplethmap` - Modern tile-based choropleth maps  
- `scattermap`/`scattermapbox` - Scatter plots on maps
- Line plots on maps (using `scattermap` with `mode: "lines"`)

![slide4b.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide4b.png)

#### Altair

```python
slide5 = Slide()
slide5.add_title("Altair")

# import altair for creating scatter plot
import altair as alt

source = px.data.iris()

# create scatter plot
chart = (
    alt.Chart(source)
    .mark_circle(size=60)
    .encode(
        x="sepal_width", y="sepal_length", color="species",
        tooltip=["species", "sepal_length", "sepal_width"],
    )
    .interactive()
    .properties(width=900, height=500)
)

# Export the figure to json format
j = chart.to_json()

# add the scatter plot to the slide
slide5.add_content([j], columns=[12])
```
![slide5.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide5.png)

Matplotlib fig are automatically converted to svg

```python
slide5_fig = Slide()
slide5_fig.add_title("Matplotlib")

import numpy as np
import matplotlib.pyplot as plt

x = np.arange(0,4*np.pi-1,0.1)   # start,stop,step
y = np.sin(x)
z = np.cos(x)

plt.rcParams["figure.figsize"] = (8, 5)
fig, ax = plt.subplots()
plt.plot(x,y,x,z)
plt.xlabel('x values')
plt.title('sin and cos ')
plt.legend(['sin(x)', 'cos(x)'])

# add the  plot to the slide
slide5_fig.add_content([fig], columns=[12])
```
![slide5_fig.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide5_fig.png)

It is **highly recommended** to set chart's width and height manually

### LaTeX support

You can use LaTeX mathematical expressions in your slides. The package automatically detects and processes LaTeX syntax:

```python
slide6 = Slide()
slide6.add_title("Mathematical Equations")

# Text with LaTeX expressions
math_content = """
The Gaussian function $f(x) = e^{-x^2}$ or in display mode:

$$f(x) = e^{-x^2}$$
"""

slide6.add_content([math_content], columns=[12])
```

The LaTeX processing is automatic when you include `$` or `$$` delimiters in your text content.

### Bootstrap cards
Bootstrap Cards can also be added with `add_card()` method.

```python
slide7 = Slide()

# card 1 content
txt_card1 = markdown("""
- list 1
- list 2

""")

# card 1 image
univ_url = "https://upload.wikimedia.org/wikipedia/commons/b/b5/Mandel_zoom_04_seehorse_tail.jpg"

# list of cards. These orders will be the same on the HTML page
cards = [{'text': txt_card1, 'image': univ_url},  # Only text and image
         {'image': logo_url, 'text': "Card text 2", 'title': "Card Title 2", },  # Image, text and title
         {'title': "Card Title 3", 'text': "Card text 3"}]  # Title and text

# styles for each cards
styles_list = [{'font-size': '20px', 'color': '#1d3557', 'class': 'bg-danger'},
               {'font-size': '20px', 'color': '#e63946', 'class': 'bg-warning'},
               {'font-size': '20px', 'color': '#f1faee', 'class': 'bg-info'}]

# add title and card to slide
slide7.add_title("Bootstrap cards can be added")
slide7.add_card(cards, styles_list)
```

![slide6.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide6.png)

### Background image

<a href="https://revealjs.com/backgrounds/" target="_blank">Reveal.js Slide Backgrounds</a> by passing a class `data-background-*`  to 
the Slide() method with a kwarg

```python
bckgnd_url = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Frost_patterns_2.jpg/1920px-Frost_patterns_2.jpg"

# Create a dictionary with slide kwargs
slide_kwargs = {
    'data-background-image': bckgnd_url,
    'data-background-size': 'cover',  # more options here : https://revealjs.com/backgrounds/
}

# Create a slide object with slide kwargs
slide8 = Slide(center=True, **slide_kwargs)

css_background = {"class": "text-center", "color": "#e63946", "background-color": "#f1faee"}
slide8.add_title("Image  background", **css_background)
```

![slide7.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide7.png)

### Vertical slides

You can add vertical slides. First, let's create slide 9 (horizontal one) and slide 10 (vertical one)

```python
slide9 = Slide()
text = markdown("""Press arrow down to show vertical slide""")
slide9.add_title("Horizontal and vertical slides")
slide9.add_content([text])

slide10 = Slide(center=True)
slide10.add_title("Horizontal and vertical slides")
text = markdown("""This is a vertical slide""")
slide10.add_content([text])
```

They will be added as list in the next method to export your presentation

![slide8_9.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide8_9.png)

### Speaker notes

You can add speaker notes to your slides which will be visible in the speaker view:

```python
slide11 = Slide()
slide11.add_title("Speaker view")
text = markdown("""Press S for Speaker View""")

# Add speaker notes
speaker_notes = markdown("""
  <aside class="notes">
    This is a test for speaker view
  </aside>
""")

slide11.add_content([text])
slide11.add_content([speaker_notes])
```

Press 'S' during the presentation to open the speaker view with your notes.

### Presentation rendering
Last step in rendering your Reveal.js presentation with `respysive-slide` as  HTML
The `Presentation.add_slide()` method is used

```python

# Adding slide to the presentation
p.add_slide([slide1, slide1b, slide2, slide3, slide4, slide_maps, slide5, slide5_fig, slide6, slide7, slide8, [slide9, slide10], slide11])

# Saving the presentation in HTML format
p.save_html("readme_example.html")
```

As you can see, slides 9 and 10 are inside a list. That tells `respysive-slide` to create vertical slide

Different <a href="https://revealjs.com/themes/" target="_blank">Reveal.js theme</a> 
and parameters can be added :

```python
p.save_html(file_name,
            theme="moon",
            width=960,
            height=600,
            minscale=0.2,
            maxscale=1.5,
            margin=0.1,
            custom_theme=None,  # If theme="custom", pass here the custom css url 
            center=True,        # Vertical centering of slides (default: True)
            embedded=False)     # Embedded presentation mode (default: False)
```

### Vertical centering and layout options

- **`center=True`** (default): Slides are vertically centered on screen based on content
- **`center=False`**: Slides remain at fixed height, content aligns to top - useful for presentations with lots of content
- **`embedded=True`**: Presentation adapts to its container size - useful for embedding in web pages
- **`embedded=False`** (default): Presentation covers full browser viewport


### PDF export

The slide can be exported with the classic  <a href="https://revealjs.com/pdf-export/" target="_blank">Reveal.js method</a>.

Just add ?print-pdf at the end of the url and open the in-browser print dialog : 
<a href="https://raw.githack.com/fbxyz/respysive-slide/master/readme_example.html?print-pdf" target="_blank"> https://raw.githack.com/fbxyz/respysive-slide/master/readme_example.html?print-pdf </a>.

Best results are obtained with Chrome or Chromium

## Future features
- add method for speaker view
- offline presentation
- prettify the final rendering

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "respysive-slide",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": null,
    "keywords": "slide, presentation, reveal.js, Bootstrap",
    "author": "fbxyz",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/7e/26/d9a6a5fa84c50ea0dc2dde01c3bccc29fcde74196bd98919c4cf1b4570af/respysive_slide-1.1.15.tar.gz",
    "platform": null,
    "description": "# respysive-slide\n___\nA Python package that allows you to create interactive presentations using Python, \nBootstrap and Reveal.js. \nCharts from Matplotlib Altair and Plotly can be easily added.\n\n![respysiv.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/respysiv.png)\n\nYou will find a <a href=\"https://raw.githack.com/fbxyz/respysive-slide/master/readme_example.html\" target=\"_blank\">live example here</a>\n\n\n___\n## Installation\nWith PyPI \n```\npip install respysive-slide\n```\n\nUpgrade\n```\npip install respysive-slide --upgrade\n```\n\nYou can also clone the <a href=\"https://github.com/fbxyz/respysive-slide\" target=\"_blank\">repo</a> and import respysive as a module\n\n___\n## Usage\n\nThe package consists of two main classes: `Presentation` and `Slide`.\n\n`Presentation` is the main instance, containing your slides. \n\n`Slide` is used to create a unique slide. You can add various elements to it such as text, headings, images, cards etc.\n\nEach `Slide` instance is added to the `Presentation` instance for final rendering.\n\n### Creating a new presentation\nHere's an example of how to use `respysive-slide`\n\n```python\nfrom respysive import Slide, Presentation\n\n# Create a new presentation\np = Presentation()\n\n# Create the first slide with a centered layout\nslide1 = Slide(center=True)\n\n# Content for the title page\nlogo_url = \"https://upload.wikimedia.org/wikipedia/commons/4/4d/Fractal_canopy.svg\"\ntitle_page_content = {\n    'title': 'Your presentation title',\n    'subtitle': 'Your subtitle',\n    'authors': 'Author 1, Author 2',\n    'logo': logo_url\n}\n\n# Styles for the title page content in the same order as content\nstyles = [\n    {'color': '#e63946', 'class': 'r-fit-text border-top'},  # title\n    {},  # subtitle style by default\n    {},  # authors style by default\n    {'filter': 'invert(100%) opacity(30%)'},  # logo\n]\n\n# Add the title page to the slide\nslide1.add_title_page(title_page_content, styles)\n```\n\nYou can pass CSS styles and classes as kwargs. For example, in the code below,\nthe add_title method takes a dictionary kwarg `styles` containing : \n - one or several CSS styles as key : values\n - and class as a unique key:\n\n![slide1.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide1.png)\n\n### Split title page layout\n\nAs an alternative to the classic title page, you can create a split layout with the title content on one side and custom content (logo, image, chart) on the other side using `add_split_title_page()`:\n\n```python\n# Create a slide with split title page layout\nslide1b = Slide(center=True)\n\n# Content for the split title page\nsplit_title_content = {\n    'title': 'Your presentation title',\n    'subtitle': 'Your subtitle',\n    'authors': 'Author 1, Author 2',\n}\n\n# Styles for the title elements  \ntitle_styles = [\n    {'color': '#e63946', 'font-weight': 'bold', 'font-size': '60px'},  # title\n    {'color': '#457b9d', 'font-size': '40px'},  # subtitle\n    {'color': '#457b9d', 'font-size': '25px'},  # authors\n]\n\n# Style for the title column \ntitle_column_style = {\n    'background-color': '#1d3557', \n    'color': '#f1faee',             \n    'padding': '40px',              \n    'border-radius': '10px 0 0 10px'  \n}\n\n# Style for the custom content column \nimage_style = {\n    'text-align': 'center',\n    'padding': '30px',\n    'background-color': '#e63946',\n    'border-radius': '0 10px 10px 0'  \n}\n\n# Add the split title page - title on left (8 cols), logo on right (4 cols)\nslide1b.add_split_title_page(\n    title_page_content=split_title_content,\n    custom_content=logo_url,\n    title_column_width=8,\n    custom_column_width=4,\n    title_page_class=\"split-intro\",\n    custom_content_style=image_style,\n    title_styles=title_styles,\n    title_column_style=title_column_style  \n)\n```\n\n![split_title.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/split_title.png)\n\n\n\n### A simple text slide\n\nNow, lets create a simple slide with a title and some content. \n\nMarkdown is more intuitive, so we will use it, but it's not mandatory.\n\n ```python\n# Create the second slide\nslide2 = Slide()\n\n# Add a title to the slide with a fontawesome icon\nslide2.add_title(\"Your title with a fontawesome icon\", icon=\"fas fa-infinity fa-beat\")\n\n# Create some text in markdown format\ntxt = markdown(\"\"\"\nThis is some dummy text \n\n- and it's easier to use Markdown\n<ul><li>but it's ok to use HTML tag</li></ul>\n\"\"\")\n\n# Add the text to the slide in a new Bootstrap column with a width of 12 (default)\nslide2.add_content([txt], columns=[12])\n ```\nNote that for the add_title() method, <a href=\"https://fontawesome.com/icons\" target=\"_blank\">Fontawesome icons</a> can be added.\n\n![slide2.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide2.png)\n\n### A two columns slide with text and image\n\nLet's add  two columns : \n- the first with some text\n- the second with an image\n\n`respysive-slide` will try to find automatically the content type (txt, image, chart from json). \nYou only have to pass the content list with the add_content() method\n\n ```python    \n# Create a new slide\nslide3 = Slide()\n\ntext = markdown(\"\"\"\nEn cosmologie, le mod\u00e8le de l'univers fractal d\u00e9signe un mod\u00e8le cosmologique \ndont la structure et la r\u00e9partition de la mati\u00e8re poss\u00e8dent une dimension fractale, \net ce, \u00e0 plusieurs niveaux. \n\nDe fa\u00e7on plus g\u00e9n\u00e9rale, il correspond \u00e0 l'usage ou \nl'apparence de fractales dans l'\u00e9tude de l'Univers et de la mati\u00e8re qui le compose.\nCe mod\u00e8le pr\u00e9sente certaines lacunes lorsqu'il est utilis\u00e9 \u00e0 de tr\u00e8s grandes ou de \ntr\u00e8s petites \u00e9chelles.\n\n\"\"\")\n\n# Add image url\nurl = \"./assets/img/Univers_Fractal_J.H..jpg\"\n\n# Add title to slide\nslide3.add_title(\"Bootstrap powering\")\n\n# Add styles to slide\ncss_txt = [\n    {'font-size': '70%', 'text-align': 'justify', 'class': 'bg-warning'},  # text style\n    None  # url style is mandatory even it is None\n]\n\n# Add content to slide, where text and url are added to the slide with 7 and 5 columns respectively\n# css_txt is added as styles\nslide3.add_content([text, url], columns=[7, 5], styles=css_txt)\n```\n\nNote that class can include <a href=\"https://revealjs.com/fragments/\" target=\"_blank\">Reveal.js fragments</a> for step-by-step content reveal.\n\n![slide3.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide3.png)\n\n### Plotly, Altair and Matplotlib\nPlotly, Altair or Matplotlib graphs can be easily added with `add_content()`. Interactivity \nis fully functional for Plotly and Altair.\n\n```python\nslide4 = Slide()\nslide4.add_title(\"Plotly\")\n\n# import plotly express for creating scatter plot\nimport plotly.express as px\n\n# load iris data\ndf = px.data.iris()\n\n# create scatter plot\nfig = px.scatter(df, x=\"sepal_width\", y=\"sepal_length\",\n                 color=\"species\", size=\"petal_length\", hover_data=[\"petal_width\"])\n\n# update layout\nfig.update_layout(autosize=True)\n\n# Export the figure to json format\nj = fig.to_json()\n\n# apply css to the figure\ncss_txt = [{'class': 'stretch'}]\n\n# add the scatter plot to the slide\nslide4.add_content([j], columns=[12], styles=css_txt)\n\n```  \n![slide4.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide4.png)\n\n#### Sharing GeoJSON data between multiple Plotly charts\n\nYou can optimize performance by sharing large data (like GeoJSON) between multiple charts across the entire presentation.\n\n**Simple example:**\n```python\n# Add shared data once\np.add_global_geojson(\"my_data\", geojson_dict)\n# Use in multiple charts with shared_data_ids parameter  \nslide.add_content([chart1, chart2],\n                  columns=[6, 6],\n                  shared_data_ids=[\"my_data\", \"my_data\"])\n```\n\n**Complete example:**\n```python\nfrom respysive import Presentation, Slide\n\n# Create presentation\np = Presentation()\n\n# Load GeoJSON data\nfrom urllib.request import urlopen\nimport json\nwith urlopen('https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json') as response:\n    counties = json.load(response)\n\n# Load unemployment data\nimport pandas as pd\ndf_counties = pd.read_csv(\"https://raw.githubusercontent.com/plotly/datasets/master/fips-unemp-16.csv\", dtype={\"fips\": str})\n\n# Add additional columns with pandas\nimport random\nrandom.seed(42)\ndf_counties['population'] = [random.randint(10000, 500000) for _ in range(len(df_counties))]\ndf_counties['income'] = [random.randint(25000, 85000) for _ in range(len(df_counties))]\n# Add area data for density calculation\ndf_counties['area_sq_miles'] = [random.randint(200, 2000) for _ in range(len(df_counties))]\ndf_counties['density'] = (df_counties['population'] / df_counties['area_sq_miles']).round(1)\n\n# Add global geojson data to presentation\np.add_global_geojson(\"us_counties\", counties)\n\nslide_maps = Slide()\nslide_maps.add_title(\"Sharing geojson data between multiple plotly charts\", **{'class': 'r-fit-text'})\n\n# Add context text\ncontext_text = \"\"\"\nCounties geojson data (~2MB) is shared across the presentation\n\"\"\"\n\ncss_txt = [{'text-align': 'center', 'font-size': \"70%\"}]\n\nslide_maps.add_content([context_text], columns=[12], styles=css_txt)\n\n# Create population density map\npopulation_config = {\n    \"data\": [{\n        \"type\": \"choropleth\",\n        \"locations\": df_counties['fips'].tolist(),\n        \"z\": df_counties['density'].tolist(),\n        \"colorscale\": \"Blues\",\n        \"colorbar\": {\n            \"title\": \"Density<br>(per sq mi)\",\n            \"thickness\": 15,\n            \"len\": 0.7\n        },\n        \"hovertemplate\": (\n            \"<b>County {text}</b><br>\" +\n            \"Population: %{customdata[0]:,.0f}<br>\" +\n            \"Area: %{customdata[1]:,.0f} sq mi<br>\" + \n            \"Density: <b>%{z:.1f} per sq mi</b>\" +\n            \"<extra></extra>\"\n        ),\n        \"text\": df_counties['fips'].tolist(),\n        \"customdata\": list(zip(df_counties['population'], df_counties['area_sq_miles']))\n    }],\n    \"layout\": {\n        \"geo\": {\n            \"projection\": {\"type\": \"albers usa\"}, \n            \"scope\": \"usa\",\n            \"showlakes\": True,\n            \"lakecolor\": \"lightblue\"\n        },\n        \"title\": {\n            \"text\": \"Population Density by County (Random Data)\",\n            \"x\": 0.5,\n            \"xanchor\": \"center\",\n            \"font\": {\"size\": 16}\n        },\n        \"margin\": {\"r\":10,\"t\":50,\"l\":10,\"b\":10}\n    }\n}\n\n# Create choropleth map for income\nincome_config = {\n    \"data\": [{\n        \"type\": \"choroplethmap\",\n        \"locations\": df_counties['fips'].tolist(),\n        \"z\": df_counties['income'].tolist(),\n        \"colorscale\": [\n            [0.0, \"#ffffb2\"],\n            [0.2, \"#fed976\"],\n            [0.4, \"#feb24c\"],\n            [0.6, \"#fd8d3c\"],\n            [0.8, \"#f03b20\"],\n            [1.0, \"#bd0026\"]\n        ],\n        \"colorbar\": {\n            \"title\": {\n                \"text\": \"Median Income ($)\",\n                \"font\": {\"size\": 14, \"family\": \"Arial Black\"}\n            },\n            \"thickness\": 20,\n            \"len\": 0.8,\n            \"x\": 1.02,\n            \"tickmode\": \"array\",\n            \"tickvals\": [25000, 40000, 55000, 70000, 85000],\n            \"ticktext\": [\"$25K\", \"$40K\", \"$55K\", \"$70K\", \"$85K\"],\n            \"tickfont\": {\"size\": 11}\n        },\n        \"hovertemplate\": (\n            \"<b>County FIPS: %{location}</b><br>\" +\n            \"Median Income: <b>$%{z:,.0f}</b><br>\" +\n            \"Population: <b>%{customdata:,.0f}</b>\" +\n            \"<extra></extra>\"\n        ),\n        \"customdata\": df_counties['population'].tolist(),\n        \"marker\": {\n            \"line\": {\"color\": \"white\", \"width\": 0.5},\n            \"opacity\": 0.9\n        }\n    }],\n    \"layout\": {\n        \"map\": {\n            \"style\": \"carto-positron\",\n            \"zoom\": 3.2,\n            \"center\": {\"lat\": 38.0, \"lon\": -97.0}\n        },\n        \"title\": {\n            \"text\": \"Median Household Income by County (Random Data)\",\n            \"x\": 0.5,\n            \"xanchor\": \"center\",\n            \"font\": {\n                \"size\": 18,\n                \"family\": \"Arial Black\", \n                \"color\": \"#2E86AB\"\n            },\n            \"pad\": {\"t\": 20}\n        },\n        \"annotations\": [{\n            \"text\": \"Data source: Simulated random data\",\n            \"showarrow\": False,\n            \"x\": 0.99,\n            \"y\": 0.01,\n            \"xref\": \"paper\",\n            \"yref\": \"paper\",\n            \"xanchor\": \"right\",\n            \"yanchor\": \"bottom\",\n            \"font\": {\"size\": 10, \"color\": \"gray\"}\n        }],\n        \"margin\": {\"r\":80,\"t\":80,\"l\":20,\"b\":40},\n        \"paper_bgcolor\": \"rgba(248, 249, 250, 0.95)\"\n    }\n}\n\n# Add the two maps side by side using shared GeoJSON data\nslide_maps.add_content(\n    [population_config, income_config], \n    columns=[6, 6],\n    shared_data_ids=[\"us_counties\", \"us_counties\"]\n)\n```\n\nThis approach stores the large `counties` GeoJSON data (~2MB) only once globally in the presentation. Multiple maps across any slides can then reference this shared data, avoiding duplication.\n\n**Compatible map types:**\n- `choropleth` - Standard geographic choropleth maps\n- `choroplethmap` - Modern tile-based choropleth maps  \n- `scattermap`/`scattermapbox` - Scatter plots on maps\n- Line plots on maps (using `scattermap` with `mode: \"lines\"`)\n\n![slide4b.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide4b.png)\n\n#### Altair\n\n```python\nslide5 = Slide()\nslide5.add_title(\"Altair\")\n\n# import altair for creating scatter plot\nimport altair as alt\n\nsource = px.data.iris()\n\n# create scatter plot\nchart = (\n    alt.Chart(source)\n    .mark_circle(size=60)\n    .encode(\n        x=\"sepal_width\", y=\"sepal_length\", color=\"species\",\n        tooltip=[\"species\", \"sepal_length\", \"sepal_width\"],\n    )\n    .interactive()\n    .properties(width=900, height=500)\n)\n\n# Export the figure to json format\nj = chart.to_json()\n\n# add the scatter plot to the slide\nslide5.add_content([j], columns=[12])\n```\n![slide5.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide5.png)\n\nMatplotlib fig are automatically converted to svg\n\n```python\nslide5_fig = Slide()\nslide5_fig.add_title(\"Matplotlib\")\n\nimport numpy as np\nimport matplotlib.pyplot as plt\n\nx = np.arange(0,4*np.pi-1,0.1)   # start,stop,step\ny = np.sin(x)\nz = np.cos(x)\n\nplt.rcParams[\"figure.figsize\"] = (8, 5)\nfig, ax = plt.subplots()\nplt.plot(x,y,x,z)\nplt.xlabel('x values')\nplt.title('sin and cos ')\nplt.legend(['sin(x)', 'cos(x)'])\n\n# add the  plot to the slide\nslide5_fig.add_content([fig], columns=[12])\n```\n![slide5_fig.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide5_fig.png)\n\nIt is **highly recommended** to set chart's width and height manually\n\n### LaTeX support\n\nYou can use LaTeX mathematical expressions in your slides. The package automatically detects and processes LaTeX syntax:\n\n```python\nslide6 = Slide()\nslide6.add_title(\"Mathematical Equations\")\n\n# Text with LaTeX expressions\nmath_content = \"\"\"\nThe Gaussian function $f(x) = e^{-x^2}$ or in display mode:\n\n$$f(x) = e^{-x^2}$$\n\"\"\"\n\nslide6.add_content([math_content], columns=[12])\n```\n\nThe LaTeX processing is automatic when you include `$` or `$$` delimiters in your text content.\n\n### Bootstrap cards\nBootstrap Cards can also be added with `add_card()` method.\n\n```python\nslide7 = Slide()\n\n# card 1 content\ntxt_card1 = markdown(\"\"\"\n- list 1\n- list 2\n\n\"\"\")\n\n# card 1 image\nuniv_url = \"https://upload.wikimedia.org/wikipedia/commons/b/b5/Mandel_zoom_04_seehorse_tail.jpg\"\n\n# list of cards. These orders will be the same on the HTML page\ncards = [{'text': txt_card1, 'image': univ_url},  # Only text and image\n         {'image': logo_url, 'text': \"Card text 2\", 'title': \"Card Title 2\", },  # Image, text and title\n         {'title': \"Card Title 3\", 'text': \"Card text 3\"}]  # Title and text\n\n# styles for each cards\nstyles_list = [{'font-size': '20px', 'color': '#1d3557', 'class': 'bg-danger'},\n               {'font-size': '20px', 'color': '#e63946', 'class': 'bg-warning'},\n               {'font-size': '20px', 'color': '#f1faee', 'class': 'bg-info'}]\n\n# add title and card to slide\nslide7.add_title(\"Bootstrap cards can be added\")\nslide7.add_card(cards, styles_list)\n```\n\n![slide6.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide6.png)\n\n### Background image\n\n<a href=\"https://revealjs.com/backgrounds/\" target=\"_blank\">Reveal.js Slide Backgrounds</a> by passing a class `data-background-*`  to \nthe Slide() method with a kwarg\n\n```python\nbckgnd_url = \"https://upload.wikimedia.org/wikipedia/commons/thumb/0/0a/Frost_patterns_2.jpg/1920px-Frost_patterns_2.jpg\"\n\n# Create a dictionary with slide kwargs\nslide_kwargs = {\n    'data-background-image': bckgnd_url,\n    'data-background-size': 'cover',  # more options here : https://revealjs.com/backgrounds/\n}\n\n# Create a slide object with slide kwargs\nslide8 = Slide(center=True, **slide_kwargs)\n\ncss_background = {\"class\": \"text-center\", \"color\": \"#e63946\", \"background-color\": \"#f1faee\"}\nslide8.add_title(\"Image  background\", **css_background)\n```\n\n![slide7.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide7.png)\n\n### Vertical slides\n\nYou can add vertical slides. First, let's create slide 9 (horizontal one) and slide 10 (vertical one)\n\n```python\nslide9 = Slide()\ntext = markdown(\"\"\"Press arrow down to show vertical slide\"\"\")\nslide9.add_title(\"Horizontal and vertical slides\")\nslide9.add_content([text])\n\nslide10 = Slide(center=True)\nslide10.add_title(\"Horizontal and vertical slides\")\ntext = markdown(\"\"\"This is a vertical slide\"\"\")\nslide10.add_content([text])\n```\n\nThey will be added as list in the next method to export your presentation\n\n![slide8_9.png](https://raw.githubusercontent.com/fbxyz/respysive-slide/master/assets/img/slide8_9.png)\n\n### Speaker notes\n\nYou can add speaker notes to your slides which will be visible in the speaker view:\n\n```python\nslide11 = Slide()\nslide11.add_title(\"Speaker view\")\ntext = markdown(\"\"\"Press S for Speaker View\"\"\")\n\n# Add speaker notes\nspeaker_notes = markdown(\"\"\"\n  <aside class=\"notes\">\n    This is a test for speaker view\n  </aside>\n\"\"\")\n\nslide11.add_content([text])\nslide11.add_content([speaker_notes])\n```\n\nPress 'S' during the presentation to open the speaker view with your notes.\n\n### Presentation rendering\nLast step in rendering your Reveal.js presentation with `respysive-slide` as  HTML\nThe `Presentation.add_slide()` method is used\n\n```python\n\n# Adding slide to the presentation\np.add_slide([slide1, slide1b, slide2, slide3, slide4, slide_maps, slide5, slide5_fig, slide6, slide7, slide8, [slide9, slide10], slide11])\n\n# Saving the presentation in HTML format\np.save_html(\"readme_example.html\")\n```\n\nAs you can see, slides 9 and 10 are inside a list. That tells `respysive-slide` to create vertical slide\n\nDifferent <a href=\"https://revealjs.com/themes/\" target=\"_blank\">Reveal.js theme</a> \nand parameters can be added :\n\n```python\np.save_html(file_name,\n            theme=\"moon\",\n            width=960,\n            height=600,\n            minscale=0.2,\n            maxscale=1.5,\n            margin=0.1,\n            custom_theme=None,  # If theme=\"custom\", pass here the custom css url \n            center=True,        # Vertical centering of slides (default: True)\n            embedded=False)     # Embedded presentation mode (default: False)\n```\n\n### Vertical centering and layout options\n\n- **`center=True`** (default): Slides are vertically centered on screen based on content\n- **`center=False`**: Slides remain at fixed height, content aligns to top - useful for presentations with lots of content\n- **`embedded=True`**: Presentation adapts to its container size - useful for embedding in web pages\n- **`embedded=False`** (default): Presentation covers full browser viewport\n\n\n### PDF export\n\nThe slide can be exported with the classic  <a href=\"https://revealjs.com/pdf-export/\" target=\"_blank\">Reveal.js method</a>.\n\nJust add ?print-pdf at the end of the url and open the in-browser print dialog : \n<a href=\"https://raw.githack.com/fbxyz/respysive-slide/master/readme_example.html?print-pdf\" target=\"_blank\"> https://raw.githack.com/fbxyz/respysive-slide/master/readme_example.html?print-pdf </a>.\n\nBest results are obtained with Chrome or Chromium\n\n## Future features\n- add method for speaker view\n- offline presentation\n- prettify the final rendering\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "A Python package that allows you to create interactive presentations using Python, Bootstrap and Reveal.js. Charts from Altair and Plotly can also be added",
    "version": "1.1.15",
    "project_urls": {
        "Home": "https://github.com/fbxyz/respysive-slide"
    },
    "split_keywords": [
        "slide",
        " presentation",
        " reveal.js",
        " bootstrap"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "89d20dfdeb456adda2736e2a3e0ab4fff048859bf95cce7c202f5f221e84ddc8",
                "md5": "59e592b7cf3b07428d9345b412b18030",
                "sha256": "2847805e8f3291d912cf38f1b8baac43eae3c9a62729edf7d307202170c291c6"
            },
            "downloads": -1,
            "filename": "respysive_slide-1.1.15-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "59e592b7cf3b07428d9345b412b18030",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 22947,
            "upload_time": "2025-07-29T19:36:52",
            "upload_time_iso_8601": "2025-07-29T19:36:52.263975Z",
            "url": "https://files.pythonhosted.org/packages/89/d2/0dfdeb456adda2736e2a3e0ab4fff048859bf95cce7c202f5f221e84ddc8/respysive_slide-1.1.15-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "7e26d9a6a5fa84c50ea0dc2dde01c3bccc29fcde74196bd98919c4cf1b4570af",
                "md5": "17452a22111bccdf9a0610473718b556",
                "sha256": "1923daa9e3fd242f2430459f9356dd09fc0eb3d1e8034de65714959b14316880"
            },
            "downloads": -1,
            "filename": "respysive_slide-1.1.15.tar.gz",
            "has_sig": false,
            "md5_digest": "17452a22111bccdf9a0610473718b556",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 26796,
            "upload_time": "2025-07-29T19:36:54",
            "upload_time_iso_8601": "2025-07-29T19:36:54.432875Z",
            "url": "https://files.pythonhosted.org/packages/7e/26/d9a6a5fa84c50ea0dc2dde01c3bccc29fcde74196bd98919c4cf1b4570af/respysive_slide-1.1.15.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-29 19:36:54",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "fbxyz",
    "github_project": "respysive-slide",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "beautifulsoup4",
            "specs": [
                [
                    "==",
                    "4.13.4"
                ]
            ]
        },
        {
            "name": "certifi",
            "specs": [
                [
                    "==",
                    "2025.4.26"
                ]
            ]
        },
        {
            "name": "charset-normalizer",
            "specs": [
                [
                    "==",
                    "3.4.2"
                ]
            ]
        },
        {
            "name": "contourpy",
            "specs": [
                [
                    "==",
                    "1.3.2"
                ]
            ]
        },
        {
            "name": "cycler",
            "specs": [
                [
                    "==",
                    "0.12.1"
                ]
            ]
        },
        {
            "name": "fonttools",
            "specs": [
                [
                    "==",
                    "4.58.0"
                ]
            ]
        },
        {
            "name": "idna",
            "specs": [
                [
                    "==",
                    "3.10"
                ]
            ]
        },
        {
            "name": "kiwisolver",
            "specs": [
                [
                    "==",
                    "1.4.8"
                ]
            ]
        },
        {
            "name": "matplotlib",
            "specs": [
                [
                    "==",
                    "3.10.3"
                ]
            ]
        },
        {
            "name": "numpy",
            "specs": [
                [
                    "==",
                    "2.2.6"
                ]
            ]
        },
        {
            "name": "packaging",
            "specs": [
                [
                    "==",
                    "25.0"
                ]
            ]
        },
        {
            "name": "pillow",
            "specs": [
                [
                    "==",
                    "11.2.1"
                ]
            ]
        },
        {
            "name": "pyparsing",
            "specs": [
                [
                    "==",
                    "3.2.3"
                ]
            ]
        },
        {
            "name": "python-dateutil",
            "specs": [
                [
                    "==",
                    "2.9.0.post0"
                ]
            ]
        },
        {
            "name": "requests",
            "specs": [
                [
                    "==",
                    "2.32.3"
                ]
            ]
        },
        {
            "name": "six",
            "specs": [
                [
                    "==",
                    "1.17.0"
                ]
            ]
        },
        {
            "name": "soupsieve",
            "specs": [
                [
                    "==",
                    "2.7"
                ]
            ]
        },
        {
            "name": "typing-extensions",
            "specs": [
                [
                    "==",
                    "4.13.2"
                ]
            ]
        },
        {
            "name": "urllib3",
            "specs": [
                [
                    "==",
                    "2.4.0"
                ]
            ]
        }
    ],
    "lcname": "respysive-slide"
}
        
Elapsed time: 0.63657s