import io
import os
import tempfile
import numpy as np
import cv2
import matplotlib
import matplotlib.pyplot as plt
from ..img.image import RGB
from ..data import Data, Pickle
from .. import MATPLOTLIB_BACKEND
matplotlib.use(MATPLOTLIB_BACKEND)
[docs]
class ToTiff(RGB):
"""Convert matplotlib figure object to RGB tiff class.
Args:
reqs[0] (Figure): Figure class containing
:class:`matplotlib.figure.Figure` objects.
param["dpi"] (int, optional): Dot per inch of image. Defaults to 400.
param["scalebar"] (list, optional): [length, left position, bottom
position, line width, line color] of the scale bar. Positions
should be the relative positions of figure size (0-1). Line color
should be [R(0-255), G(0-255), B(0-255)]. This parameter requires
"limit", "size" and "length_unit" to reqs[0].
param["split_depth"] (int): File split depth number.
Returns:
slitflow.img.image.RGB: Image of figure
"""
[docs]
def set_info(self, param={}):
"""Copy information from reqs[0] and add parameters.
"""
if self.reqs[0].info.data_split_depth != \
self.reqs[0].info.split_depth():
raise Exception("Data should split to the file split depth")
self.info.copy_req(0)
if "dpi" not in param:
param["dpi"] = 400
self.info.add_param(
"dpi", param["dpi"], "int", "Dot per inch of figure image")
# use only x-axis for scale bar
limit = self.info.get_param_value("limit")
size = self.info.get_param_value("size")
length_unit = self.info.get_param_value("length_unit")
if limit and size and length_unit:
pixel = size[0] / 2.54 * param["dpi"]
if limit[0] is not None:
pitch = (limit[1] - limit[0]) / pixel
self.info.add_param(
"pitch", pitch, length_unit, "Pixel size of figure")
if "scalebar" in param:
self.info.add_param(
"scalebar", param["scalebar"], "list",
"[length, left, bottom , line_width, line_color] of the scale\
bar")
self.info.set_split_depth(param["split_depth"])
[docs]
@staticmethod
def process(reqs, param):
"""Convert matplotlib figure object to RGB tiff class.
Args:
reqs[0] (matplotlib.figure.Figure): Figure object.
param["dpi"] (int, optional): Dot per inch of image. Defaults to
400.
param["scalebar"] (list, optional): [length, left position, bottom
position, line width, line color] of the scale bar. Positions
should be the relative positions of figure size (0-1).
Line color should be [R(0-255), G(0-255), B(0-255)]. This
parameter requires "limit", "size" and "length_unit" to
reqs[0].
param["limit"] (list of float, optional): [left, right, bottom,
top] limits of figure axes. Required if ``scale`` in param.
Returns:
numpy.ndarray: Image of figure
"""
fig = reqs[0]
if "scalebar" in param:
width = param["limit"][1] - param["limit"][0]
height = param["limit"][3] - param["limit"][2]
left = width * param["scalebar"][1] + param["limit"][0]
bottom = height * param["scalebar"][2] + param["limit"][2]
fig.axes[0].plot([left, left + param["scalebar"][0]],
[bottom, bottom], linewidth=param["scalebar"][3],
color=np.array(param["scalebar"][4]) / 255)
stack = np.array(get_stack(fig, param["dpi"]))
return stack
[docs]
def get_stack(fig, dpi):
"""Convert matplotlib.figure.Figure to numpy.ndarray of RGB image.
Args:
fig (matplotlib.figure.Figure): Figure object.
dpi (int): Dot per inch.
Returns:
numpy.ndarray: RGB image with the shape of (color, height, width)
"""
stack = []
fig.set_dpi(dpi)
buf = io.BytesIO()
fig.savefig(buf, format="png", dpi=dpi)
buf.seek(0)
fig_rgb = np.frombuffer(buf.getvalue(), dtype=np.uint8)
img = cv2.imdecode(fig_rgb, 1)
fig_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
stack.append(np.flipud(fig_rgb[:, :, 0]))
stack.append(np.flipud(fig_rgb[:, :, 1]))
stack.append(np.flipud(fig_rgb[:, :, 2]))
return stack
[docs]
def inherit_split_depth(Data, reqs_no, group_depth):
"""Set the group and split depth based on the reqs data.
Args:
Data (Data): Target Data object to set split_depth.
reqs_no (int): Required Data number to get split_depth.
group_depth (int): Data grouping depth number to set calc_cols.
"""
Data.info.set_group_depth(group_depth)
split_depth = Data.reqs[reqs_no].info.data_split_depth
keeps = Data.info.get_column_name("index")[:split_depth]
Data.info.delete_column(keeps=keeps)
Data.info.set_split_depth(split_depth)