Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions docs/updating.md
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,16 @@ pages for more details on the input and output variable types.
* pre v4.0: NA
* post v4.0: chart = **plantcv.visualize.chlorophyll_fluorescence**(*ps_da, labeled_mask, n_labels=1, label="object"*)

#### plantcv.visualize.color_chip_comparison

* pre v4.10: NA
* post v4.10: plot = plantcv.visualize.color_chip_comparison**(*std_matrix, \*args*)

#### plantcv.visualize.color_correction_scatter

* pre v4.10: NA
* post v4.10: plot = plantcv.visualize.color_correction_scatter**(*color_matrix, std_matrix, corrected_matrix*)

#### plantcv.visualize.colorize_label_img

* pre v3.13: NA
Expand Down
45 changes: 45 additions & 0 deletions docs/visualize_color_chip_comparison.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## Color Chip Comparison

This function makes a plot comparing observed versus expected values from 1 or more color cards against a standard color card matrix via a "greenness rank". The greenness rank is useful in checking color card quality. The ninth (red) color chip is known to fade most quickly and the proportion of green light that it reflects can vary dramatically as the color card ages. The color of each bar is determined by the standard color matrix on the left side of the bar and by the observed color matrix on the right side of the bar. The order along the x axis is conserved from the order of `*args`.

**plantcv.visualize.color_chip_comparison**(*std_matrix, \*args*)

**returns** plot, a altair.vegalite.v5.api.VConcatChart object

- **Parameters:**
- std_matrix - A numpy.ndarray as returned from [`pcv.transform.std_color_matrix`](std_color_matrix.md).
- \*args - Any number of numpy.ndarrays as returned from [`pcv.transform.get_color_matrix`](get_color_matrix.md)

- **Context:**
- The aim of this visualization is to help evaluate the condition of a color card or set of color cards.


- **Example use:**
- Below

**Dataset images:**

![Screenshot](img/documentation_images/visualize_color_chip_comparison/input.png)

```python

from plantcv import plantcv as pcv

tgt_matrix = pcv.transform.std_color_matrix(pos=3)
_, cc1_matrix = pcv.transform.get_color_matrix(rgb_img=img, mask=cc_mask)
# ... masking more color cards for example
_, cc6_matrix = pcv.transform.get_color_matrix(rgb_img=img, mask=cc_mask6)

plot = pcv.visualize.color_chip_comparison(tgt_matrix, cc1_matrix,
cc2_matrix, cc3_matrix,
cc4_matrix, cc5_matrix,
cc6_matrix)

```

**Color chip comparison visualizations:**

![Screenshot](img/documentation_images/visualize_color_chip_comparison/output.png)


**Source Code:** [Here](https://github.com/danforthcenter/plantcv/blob/master/plantcv/plantcv/visualize/color_chip_comparison.py)
38 changes: 38 additions & 0 deletions docs/visualize_color_correction_scatter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
## Color correction scatter plot

This function plots 4 panels of 2D scatter plot visualizations showing RGB and grayscale values of an input image, the expected color card, and optionally a color corrected image. The horizontal and vertical coordinates are defined by the intensity of the pixels in the specified channels. The color of each dot is given by the original RGB color of the image, ideal color card, or corrected image.

**plantcv.visualize.color_correction_plot**(*color_matrix, std_matrix, corrected_matrix*)

**returns** fig, axs

- **Parameters:**
- color_matrix - A tuple of numpy.ndarrays, as returned from [`pcv.transform.get_color_matrix`](get_color_matrix.md).
- std_matrix - A numpy.ndarray as returned from [`pcv.transform.std_color_matrix`](std_color_matrix.md).
- corrected_matrix - An optional tuple of numpy.ndarrays, as returned from [`pcv.transform.get_color_matrix`](get_color_matrix.md) used on a color corrected image.

- **Context:**
- The aim of this visualization is to help evaluate the condition of a color card, input image, and color correction. Generally after color correction an image will look better but it may be useful to check the residuals shown in this plot between observed and expected values.


- **Example use:**
- Below

**Dataset images:**

![Screenshot](img/documentation_images/visualize_color_correction_scatter/am003_sv_input.png)

```python

from plantcv import plantcv as pcv

fig, axs = pcv.visualize.color_correction_plot(colmat, stdmat, ccmat)

```

**Color correction scatter visualizations:**

![Screenshot](img/documentation_images/visualize_color_correction_scatter/am003_sv_ex.png)


**Source Code:** [Here](https://github.com/danforthcenter/plantcv/blob/master/plantcv/plantcv/visualize/color_correction_scatter.py)
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ nav:
- 'Visualization Methods':
- 'Auto Threshold Methods': visualize_auto_threshold_methods.md
- 'Chlorophyll Fluorescence': visualize_chlorophyll_fluorescence.md
- 'Color Correction Scatter Plot': visualize_color_correction_scatter.md
- 'Color Chip Comparison Plot': visualize_color_chip_comparison.md
- 'Colorize Label Image': visualize_colorize_label_img.md
- 'Colorize Masks': visualize_colorize_masks.md
- 'Colorspaces': visualize_colorspace.md
Expand Down
5 changes: 4 additions & 1 deletion plantcv/plantcv/visualize/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
from plantcv.plantcv.visualize.obj_size_ecdf import obj_size_ecdf
from plantcv.plantcv.visualize.hyper_histogram import hyper_histogram
from plantcv.plantcv.visualize.pixel_scatter_vis import pixel_scatter_plot
from plantcv.plantcv.visualize.color_correction_scatter import color_correction_plot
from plantcv.plantcv.visualize.color_chip_comparison import color_chip_comparison
from plantcv.plantcv.visualize.chlorophyll_fluorescence import chlorophyll_fluorescence
from plantcv.plantcv.visualize.tile import tile

__all__ = ["pseudocolor", "colorize_masks", "histogram", "colorspaces", "auto_threshold_methods",
"overlay_two_imgs", "colorize_label_img", "obj_size_ecdf", "obj_sizes", "hyper_histogram",
"pixel_scatter_plot", "time_lapse_video", "chlorophyll_fluorescence", "tile"]
"pixel_scatter_plot", "color_correction_plot", "color_chip_comparison", "time_lapse_video",
"chlorophyll_fluorescence", "tile"]
152 changes: 152 additions & 0 deletions plantcv/plantcv/visualize/color_chip_comparison.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# Visualize a scatter plot representation of color correction

import pandas as pd
import altair as alt


def color_chip_comparison(std_matrix, *args):
"""
Plot 4 panels showing the difference in observed vs expected colors and optionally
the calibrated colors in a color card.
The color of each dot is given by the RGB value either of the original image, known color card, or corrected image.

Parameters
----------
std_matrix : numpy.ndarray
Output from pcv.transform.std_color_matrix
*args: list of numpy.ndarrays
Output from pcv.transform.get_color_matrix

Returns
-------
altair.vegalite.v5.api.VConcatChart of color chip greenness ranks between observed and expected values.
"""
# make standard color matrix into a rescaled dataframe
stddf = pd.DataFrame(std_matrix)
stddf.columns = ["chip", "R", "G", "B"]
stddf["card"] = "std"
stddf["std_R"] = stddf["R"] * 255
stddf["std_G"] = stddf["G"] * 255
stddf["std_B"] = stddf["B"] * 255
# initialize a list of like dataframes
df_list = [stddf]
# format and append all kwargs into list of dataframes
for i, mat in enumerate(args):
df = pd.DataFrame(mat)
df.columns = ["chip", "R", "G", "B"]
df["card"] = f"card {i + 1}"
df["std_R"] = stddf["std_R"]
df["std_G"] = stddf["std_G"]
df["std_B"] = stddf["std_B"]
df_list.append(df)
# rbind all dataframes from list
fulldf = pd.concat(*[df_list], ignore_index=True)
# rescale rgb values to 0-255
fulldf["R"] = fulldf["R"] * 255
fulldf["G"] = fulldf["G"] * 255
fulldf["B"] = fulldf["B"] * 255
# calculate greenness, in the future maybe a named metric.
fulldf["greenness"] = fulldf["G"] / (fulldf["R"] + fulldf["G"] + fulldf["B"])
# rank greenness, chips should have same order in any "healthy" card
fulldf["greenness_rank"] = fulldf.groupby("card")["greenness"].rank(
method="first", ascending=False
)
# make standard greenness and rank it
fulldf["std_greenness"] = fulldf["std_G"] / (
fulldf["std_R"] + fulldf["std_G"] + fulldf["std_B"]
)
fulldf["std_greenness_rank"] = fulldf.groupby("card")["std_greenness"].rank(
method="first", ascending=False
)
# label chips 1 to 24
fulldf["chip"] = fulldf["chip"] / 10
# initiate base of upper color chip chart
base = (
alt.Chart(fulldf)
.encode(
alt.X(
"card:O",
axis=alt.Axis(
grid=False, ticks=False, domain=False, labels=False, title=None
),
).scale(paddingInner=0),
alt.Y("greenness_rank:O", title="Greenness Rank").scale(paddingInner=0),
)
.properties(height=300, width=500)
)
# make rect layer of observed colors
tiles1 = base.mark_rect(width=alt.RelativeBandSize(0.6), align="left").encode(
color=alt.value(
alt.ExprRef(alt.expr.rgb(alt.datum.R, alt.datum.G, alt.datum.B))
),
)
# make rect layer of standard colors
tiles2 = base.mark_rect(width=alt.RelativeBandSize(0.3), align="right").encode(
color=alt.value(
alt.ExprRef(alt.expr.rgb(alt.datum.std_R, alt.datum.std_G, alt.datum.std_B))
),
)
# make text layer to label chip numbers
text = base.mark_text(baseline="middle", align="center").encode(
text="chip:Q", color=alt.value("white")
)
# combine rect and text layers
upper = tiles1 + tiles2 + text
# initialize list of margin plots
margin_plots = []
# for each kwarg matrix and std matrix make a margin plot of residual ranks
for i in range(0, len(args) + 1):
# select card
whichcard = f"card {i + 1}"
if i + 1 > len(args):
whichcard = "std"
sub1 = fulldf[fulldf["card"] == whichcard]
# initialize plot
subbase = (
alt.Chart(sub1)
.encode(alt.X("std_greenness_rank:Q"), alt.Y("std_greenness_rank:Q"))
.properties(
height=500 / (10 / 9 * len(args) + 1),
width=500 / (10 / 9 * len(args) + 1),
title=whichcard,
)
)
# make line+points layer of observed vs expected ranks
subpoints = subbase.mark_line(
point=True, strokeWidth=1.25, strokeDash=[5, 5]
).encode(
x=alt.X(
"greenness_rank:Q",
axis=alt.Axis(
grid=False, ticks=False, domain=False, labels=False, title=None
),
),
y=alt.Y(
"std_greenness_rank:Q",
axis=alt.Axis(
grid=False, ticks=False, domain=False, labels=False, title=None
),
),
)
# draw expected line with slope 1
sublinear = subbase.mark_line(color="black", strokeWidth=0.5).encode(
x=alt.X(
"std_greenness_rank:Q",
axis=alt.Axis(
grid=False, ticks=False, domain=False, labels=False, title=None
),
),
y=alt.Y(
"std_greenness_rank:Q",
axis=alt.Axis(
grid=False, ticks=False, domain=False, labels=False, title=None
),
),
)
# combine layers
iterchart = subpoints + sublinear
# add to list of margin plots for combination
margin_plots.append(iterchart)
# combine tile plot and margin plots
out = alt.vconcat(upper, alt.hconcat(*margin_plots, spacing=5))
return out
Loading