Create new folder when save image in Python Plotly

Viewed 134

I use a for-loop to generate multiple images with fig.write_image in plotly. However, this gets very messy when there are many images. Is there a way to create a new folder and save these images in that folder when writing these images, so that all images will be stored in the same place rather than everywhere?

The code I used looks like below:

def draw(summary_df, data_df):

    for i, row in summary_df.iterrows():

        sub_df = data_df[(data_df.id== row.id) & (data_df.Timestamp >= row.start_time- datetime.timedelta(minutes=1)) & (data_df.Timestamp <= row.end_time +datetime.timedelta(minutes=1))]

        fig = go.Figure()
        
        fig.add_trace(go.Scatter(x=sub_df.Timestamp, y=sub_df.Data,
                            mode='lines+markers+text',
                            text = sub_df.Data,
                            textposition="top center",
                            textfont=dict(
                                family="arial",
                                size=10,
                                color="#6570f9") ))

        fig.update_layout(
        title=f'{i}. {row.id}, {row.Timestamp}', 
        xaxis_title="Timestamp",
        yaxis_title="Measurement",
        legend_title="Data",
        font=dict(
            size=11
        )
    )


        fig.write_image(f"{row.id}-{row.Timestamp.strftime('%Y-%m-%d_%H_%M_%S')}.png")
        fig.show()

2 Answers

First create a directory

image_path = "path/to/image"
if not os.path.exists("images"):
    os.mkdir(image_path)

Then import images to said directory inside your for loop:

from PIL import Image
import os


fig.write_image(f"{image_path}/{row.id}-{row.Timestamp.strftime('%Y-%m-%d_%H_%M_%S')}.png")
  • pathlib is the way to go.
  • Simple case of using object based approach to file system. In this case it will put results into sub-directory of current working directory.
    out_dir = Path.cwd().joinpath("out")
    if not out_dir.exists():
        out_dir.mkdir()
  • the call to write your png
        fig.write_image(
            out_dir.joinpath(
                f"{row.id}-{row.Timestamp.strftime('%Y-%m-%d_%H_%M_%S')}.png"
            )

full code

  • have included some code to generate sample data frames
import pandas as pd
import numpy as np
import plotly.graph_objects as go
import datetime
from pathlib import Path


def draw(summary_df, data_df):
    out_dir = Path.cwd().joinpath("out")
    if not out_dir.exists():
        out_dir.mkdir()

    for i, row in summary_df.iterrows():

        sub_df = data_df[
            (data_df.id == row.id)
            & (data_df.Timestamp >= row.start_time - datetime.timedelta(minutes=1))
            & (data_df.Timestamp <= row.end_time + datetime.timedelta(minutes=1))
        ]

        fig = go.Figure()

        fig.add_trace(
            go.Scatter(
                x=sub_df.Timestamp,
                y=sub_df.Data,
                mode="lines+markers+text",
                text=sub_df.Data,
                textposition="top center",
                textfont=dict(family="arial", size=10, color="#6570f9"),
            )
        )

        fig.update_layout(
            title=f"{i}. {row.id}, {row.Timestamp}",
            xaxis_title="Timestamp",
            yaxis_title="Measurement",
            legend_title="Data",
            font=dict(size=11),
        )

        fig.write_image(
            out_dir.joinpath(
                f"{row.id}-{row.Timestamp.strftime('%Y-%m-%d_%H_%M_%S')}.png"
            )
        )
        fig.show()


# generate some sample data..
summary_df = (
    pd.DataFrame(
        index=pd.MultiIndex.from_product(
            [
                range(3),
                pd.date_range("1-may-2022", periods=3),
                pd.date_range("15-may-2022", periods=3),
            ],
            names=["id", "start_time", "end_time"],
        )
    )
    .reset_index()
    .assign(Timestamp=lambda d: pd.date_range("today", freq="5Min", periods=len(d)))
)

data_df = pd.concat(
    [
        pd.DataFrame(
            {"Timestamp": pd.date_range(r.start_time, r.end_time, freq="30H")}
        ).assign(id=r.id, Data=lambda d: np.random.randint(3, 10, len(d)))
        for i, r in summary_df.iterrows()
    ]
).sort_values(["id", "Timestamp", "Data"])

summary_df = summary_df.sample(4)

draw(summary_df, data_df)
Related