Skip to content

czitools.visu_tools.vis_tools #

Scatter-plot visualisation utilities for CZI planetable data.

Provides scatterplot_mpl and scatterplot_plotly for visualising per-plane stage-position data from a CZI planetable DataFrame using Matplotlib or Plotly respectively.

Functions:

  • scatterplot_mpl

    Generates 2D and 3D scatter plots of XYZ positions from a given table and saves them as PNG files.

  • scatterplot_plotly

    Generates 2D and 3D scatter plots using Plotly and saves them as HTML files.

scatterplot_mpl #

scatterplot_mpl(
    planetable: DataFrame,
    s: int = 0,
    t: int = 0,
    z: int = 0,
    c: int = 0,
    msz2d: int = 35,
    normz: bool = True,
    fig1savename: str = "zsurface2d.png",
    fig2savename: str = "zsurface3d.png",
    msz3d: int = 20,
) -> tuple[Figure, Figure]

Generates 2D and 3D scatter plots of XYZ positions from a given table and saves them as PNG files.

Parameters:

  • planetable #

    (DataFrame) –

    DataFrame containing the XYZ positions with columns 'X[micron]', 'Y[micron]', and 'Z[micron]'.

  • s #

    (int, default: 0 ) –

    Unused parameter, default is 0.

  • t #

    (int, default: 0 ) –

    Time point, default is 0.

  • z #

    (int, default: 0 ) –

    Z position, default is 0.

  • c #

    (int, default: 0 ) –

    Channel, default is 0.

  • msz2d #

    (int, default: 35 ) –

    Marker size for the 2D scatter plot, default is 35.

  • normz #

    (bool, default: True ) –

    If True, normalize Z data by subtracting the minimum value, default is True.

  • fig1savename #

    (str, default: 'zsurface2d.png' ) –

    Filename for saving the 2D scatter plot, default is "zsurface2d.png".

  • fig2savename #

    (str, default: 'zsurface3d.png' ) –

    Filename for saving the 3D scatter plot, default is "zsurface3d.png".

  • msz3d #

    (int, default: 20 ) –

    Marker size for the 3D scatter plot, default is 20.

Returns:

  • tuple[Figure, Figure]

    Tuple[MplFigure, MplFigure]: A tuple containing: - fig1: The 2D scatter plot figure. - fig2: The 3D scatter plot figure.

Raises:

  • KeyError

    If the required columns 'X[micron]', 'Y[micron]', or 'Z[micron]' are not found in the DataFrame.

Notes
  • The function attempts to find a "good" aspect ratio for the figures based on the data.
  • The Y-axis is inverted to have the origin (0,0) at the top-left.
  • The color of the scatter points represents the Z positions.
  • The function logs the filenames of the saved figures.
Source code in czitools/visu_tools/vis_tools.py
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
def scatterplot_mpl(
    planetable: pd.DataFrame,
    s: int = 0,
    t: int = 0,
    z: int = 0,
    c: int = 0,
    msz2d: int = 35,
    normz: bool = True,
    fig1savename: str = "zsurface2d.png",
    fig2savename: str = "zsurface3d.png",
    msz3d: int = 20,
) -> tuple[MplFigure, MplFigure]:
    """Generates 2D and 3D scatter plots of XYZ positions from a given table and saves them as PNG files.

    Args:
        planetable (pandas.DataFrame): DataFrame containing the XYZ positions with columns
            'X[micron]', 'Y[micron]', and 'Z[micron]'.
        s (int): Unused parameter, default is 0.
        t (int): Time point, default is 0.
        z (int): Z position, default is 0.
        c (int): Channel, default is 0.
        msz2d (int): Marker size for the 2D scatter plot, default is 35.
        normz (bool): If True, normalize Z data by subtracting the minimum value, default is True.
        fig1savename (str): Filename for saving the 2D scatter plot, default is "zsurface2d.png".
        fig2savename (str): Filename for saving the 3D scatter plot, default is "zsurface3d.png".
        msz3d (int): Marker size for the 3D scatter plot, default is 20.

    Returns:
        Tuple[MplFigure, MplFigure]: A tuple containing:
            - fig1: The 2D scatter plot figure.
            - fig2: The 3D scatter plot figure.

    Raises:
        KeyError: If the required columns 'X[micron]', 'Y[micron]', or 'Z[micron]'
            are not found in the DataFrame.

    Notes:
        - The function attempts to find a "good" aspect ratio for the figures based on the data.
        - The Y-axis is inverted to have the origin (0,0) at the top-left.
        - The color of the scatter points represents the Z positions.
        - The function logs the filenames of the saved figures.
    """

    # extract XYZ positions
    try:
        xpos = planetable["X[micron]"]
        ypos = planetable["Y[micron]"]
        zpos = planetable["Z[micron]"]
    except KeyError:
        xpos = planetable["X [micron]"]
        ypos = planetable["Y [micron]"]
        zpos = planetable["Z [micron]"]

    # normalize z-data by substracting the minimum value
    if normz:
        zpos = zpos - zpos.min()

    # create a name for the figure
    figtitle = "XYZ-Positions: T=" + str(t) + " Z=" + str(z) + " CH=" + str(c)

    # try to find a "good" aspect ratio for the figures
    dx = xpos.max() - xpos.min()
    dy = ypos.max() - ypos.min()
    fsy = 8
    fsx = int(np.ceil(fsy * dx / dy))

    # create figure
    fig1, ax1 = plt.subplots(1, 1, figsize=(fsx + 1, fsy))

    # invert the Y-axis --> O,O = Top-Left
    ax1.invert_yaxis()

    # configure the axis
    ax1.set_title(figtitle)
    ax1.set_xlabel("Stage X-Axis [micron]", fontsize=12, fontweight="normal")
    ax1.set_ylabel("Stage Y-Axis [micron]", fontsize=12, fontweight="normal")
    ax1.grid(True)
    ax1.set_aspect("equal", "box")

    # plot data and label the colorbar
    sc1 = ax1.scatter(
        xpos,
        ypos,
        marker="s",
        c=zpos,
        s=msz2d,
        facecolor=getattr(cm, "coolwarm"),
        edgecolor="black",
    )

    # add the colorbar on the right-hand side
    cb1 = plt.colorbar(sc1, fraction=0.046, shrink=0.8, pad=0.04)

    # add a label
    if normz:
        cb1.set_label("Z-Offset [micron]", labelpad=20, fontsize=12, fontweight="normal")
    if not normz:
        cb1.set_label("Z-Position [micron]", labelpad=20, fontsize=12, fontweight="normal")

    # save figure as PNG
    fig1.savefig(fig1savename, dpi=100)
    logger.info(f"Saved: {fig1savename}")

    # 3D plot of surface
    fig2 = plt.figure(figsize=(fsx + 1, fsy))
    ax2 = fig2.add_subplot(111, projection="3d")

    # invert the Y-axis --> O,O = Top-Left
    ax2.invert_yaxis()

    # define the labels
    ax2.set_xlabel("Stage X-Axis [micron]", fontsize=12, fontweight="normal")
    ax2.set_ylabel("Stage Y-Axis [micron]", fontsize=12, fontweight="normal")
    ax2.set_title(figtitle)

    # plot data and label the colorbar
    sc2 = ax2.scatter(
        xpos,
        ypos,
        zpos,  # type: ignore[arg-type]
        marker=".",
        s=msz3d,
        c=zpos,
        facecolor=getattr(cm, "coolwarm"),
        depthshade=False,
    )

    # add colorbar to the 3d plot
    cb2 = plt.colorbar(sc2, shrink=0.8)
    # add a label
    if normz:
        cb2.set_label("Z-Offset [micron]", labelpad=20, fontsize=12, fontweight="normal")
    if not normz:
        cb2.set_label("Z-Position [micron]", labelpad=20, fontsize=12, fontweight="normal")

    # save figure as PNG
    fig2.savefig(fig2savename, dpi=100)
    logger.info(f"Saved: {fig2savename}")

    return fig1, fig2

scatterplot_plotly #

scatterplot_plotly(
    planetable: DataFrame,
    s: int = 0,
    t: int = 0,
    z: int = 0,
    c: int = 0,
    msz2d: int = 35,
    normz: bool = True,
    fig1savename: str = "zsurface2d.html",
    fig2savename: str = "zsurface3d.html",
    msz3d: int = 20,
) -> tuple[Figure, Figure]

Generates 2D and 3D scatter plots using Plotly and saves them as HTML files.

Parameters:

  • planetable #

    (DataFrame) –

    DataFrame containing the XYZ positions and other relevant data.

  • s #

    (int, default: 0 ) –

    Placeholder parameter, default is 0.

  • t #

    (int, default: 0 ) –

    Placeholder parameter, default is 0.

  • z #

    (int, default: 0 ) –

    Placeholder parameter, default is 0.

  • c #

    (int, default: 0 ) –

    Placeholder parameter, default is 0.

  • msz2d #

    (int, default: 35 ) –

    Marker size for the 2D scatter plot, default is 35.

  • normz #

    (bool, default: True ) –

    If True, normalize the Z data by subtracting the minimum value, default is True.

  • fig1savename #

    (str, default: 'zsurface2d.html' ) –

    Filename for saving the 2D scatter plot HTML file, default is "zsurface2d.html".

  • fig2savename #

    (str, default: 'zsurface3d.html' ) –

    Filename for saving the 3D scatter plot HTML file, default is "zsurface3d.html".

  • msz3d #

    (int, default: 20 ) –

    Marker size for the 3D scatter plot, default is 20.

Returns:

  • tuple[Figure, Figure]

    Tuple[go.Figure, go.Figure]: A tuple containing: - fig1: The generated 2D scatter plot figure. - fig2: The generated 3D scatter plot figure.

Source code in czitools/visu_tools/vis_tools.py
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
def scatterplot_plotly(
    planetable: pd.DataFrame,
    s: int = 0,
    t: int = 0,
    z: int = 0,
    c: int = 0,
    msz2d: int = 35,
    normz: bool = True,
    fig1savename: str = "zsurface2d.html",
    fig2savename: str = "zsurface3d.html",
    msz3d: int = 20,
) -> tuple["go.Figure", "go.Figure"]:
    """Generates 2D and 3D scatter plots using Plotly and saves them as HTML files.

    Args:
        planetable (pandas.DataFrame): DataFrame containing the XYZ positions and other relevant data.
        s (int): Placeholder parameter, default is 0.
        t (int): Placeholder parameter, default is 0.
        z (int): Placeholder parameter, default is 0.
        c (int): Placeholder parameter, default is 0.
        msz2d (int): Marker size for the 2D scatter plot, default is 35.
        normz (bool): If True, normalize the Z data by subtracting the minimum value, default is True.
        fig1savename (str): Filename for saving the 2D scatter plot HTML file, default is "zsurface2d.html".
        fig2savename (str): Filename for saving the 3D scatter plot HTML file, default is "zsurface3d.html".
        msz3d (int): Marker size for the 3D scatter plot, default is 20.

    Returns:
        Tuple[go.Figure, go.Figure]: A tuple containing:
            - fig1: The generated 2D scatter plot figure.
            - fig2: The generated 3D scatter plot figure.
    """

    import plotly.graph_objects as go

    # extract XYZ position for the selected channel
    try:
        xpos = planetable["X[micron]"]
        ypos = planetable["Y[micron]"]
        zpos = planetable["Z[micron]"]
    except KeyError:
        xpos = planetable["X [micron]"]
        ypos = planetable["Y [micron]"]
        zpos = planetable["Z [micron]"]

    # normalize z-data by substracting the minimum value
    if normz:
        zpos = zpos - zpos.min()
        scalebar_title = "Z-Offset [micron]"
    if not normz:
        scalebar_title = "Z-Position [micron]"

    # create a name for the figure
    figtitle = "XYZ-Positions: T=" + str(t) + " Z=" + str(z) + " CH=" + str(c)

    fig1 = go.Figure(
        data=go.Scatter(
            x=xpos,
            y=ypos,
            mode="markers",
            text=np.round(zpos, 1),
            marker_symbol="square",
            marker_size=msz2d,
            marker=dict(
                color=zpos,
                colorscale="Viridis",
                line_width=2,
                showscale=True,
                colorbar=dict(thickness=10, title=dict(text=scalebar_title, side="right")),
            ),
        )
    )

    fig1.update_xaxes(showgrid=True, zeroline=True, automargin=True)
    fig1.update_yaxes(showgrid=True, zeroline=True, automargin=True)
    fig1["layout"]["yaxis"]["autorange"] = "reversed"
    fig1.update_layout(
        title=figtitle,
        xaxis_title="StageX Position [micron]",
        yaxis_title="StageY Position [micron]",
        font=dict(size=16, color="Black"),
    )

    # save the figure
    fig1.write_html(fig1savename)
    logger.info(f"Saved: {fig1savename}")

    fig2 = go.Figure(
        data=[
            go.Scatter3d(
                x=xpos,
                y=ypos,
                z=zpos,
                mode="markers",
                marker=dict(
                    size=msz3d,
                    color=zpos,
                    colorscale="Viridis",
                    opacity=0.8,
                    colorbar=dict(thickness=10, title=dict(text=scalebar_title, side="right")),
                ),
            )
        ]
    )

    fig2.update_xaxes(showgrid=True, zeroline=True, automargin=True)
    fig2.update_yaxes(showgrid=True, zeroline=True, automargin=True)
    fig2["layout"]["yaxis"]["autorange"] = "reversed"
    fig2.update_layout(
        title=figtitle,
        xaxis_title="StageX Position [micron]",
        yaxis_title="StageY Position [micron]",
        font=dict(size=16, color="Black"),
    )

    # save the figure
    fig2.write_html(fig2savename)
    logger.info(f"Saved: {fig2savename}")

    return fig1, fig2