-
Notifications
You must be signed in to change notification settings - Fork 288
Delta e image plot #1922
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
joshqsumner
wants to merge
33
commits into
v5.0
Choose a base branch
from
delta_e_image_plot
base: v5.0
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Delta e image plot #1922
Changes from 27 commits
Commits
Show all changes
33 commits
Select commit
Hold shift + click to select a range
279246e
adding new plot
joshqsumner 10a5733
Merge branch 'color-correction-scatterplot' into color_chip_comparison
joshqsumner 4c99f50
documentation
joshqsumner b92d000
export function
joshqsumner 5e45a95
unnamed args
joshqsumner 949ffe4
Merge branch 'color-correction-scatterplot' into color_chip_comparison
joshqsumner c08b12b
adding test
joshqsumner 1efcec4
black linting
joshqsumner fe2354e
Merge branch 'main' into color_chip_comparison
joshqsumner e3c3c28
Merge branch 'main' into color_chip_comparison
joshqsumner e6bf2cb
Merge branch 'v5.0' into color_chip_comparison
joshqsumner 1519fb3
Merge branch 'quick_color_check-to-qc' into color_chip_comparison
joshqsumner 15bdcb9
move new visualization functions to qc
joshqsumner 97f96af
whitespace
joshqsumner ebfe12c
add plot_deltaE function
joshqsumner 2b5deb2
Merge branch 'deltaE' into delta_e_image_plot
joshqsumner 2ba203d
docs for delta E plotting
joshqsumner 563c2ad
tests for delta E plotting
joshqsumner b1a82ab
deepsource
joshqsumner eead4bc
fstring formatting
joshqsumner 1d07c86
Merge branch 'quick_color_check-to-qc' into color_chip_comparison
joshqsumner 8cc79c1
Merge branch 'color_chip_comparison' into delta_e_image_plot
joshqsumner edecbdf
Merge branch 'v5.0' into delta_e_image_plot
joshqsumner e901e2b
Merge branch 'v5.0' into color_chip_comparison
joshqsumner 875d68f
Merge branch 'quick_color_check-to-qc' into color_chip_comparison
joshqsumner 774e65c
Merge branch 'color_chip_comparison' into delta_e_image_plot
joshqsumner bed8a5e
Merge branch 'v5.0' into delta_e_image_plot
nfahlgren 65edd74
Apply suggestions from code review
nfahlgren a943859
Remove function import
nfahlgren 62194ce
Fix indentation
nfahlgren c764d41
Remove extra whitespace
nfahlgren 044a10e
Add new functions to updating
nfahlgren 087be45
updating docs images
joshqsumner File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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.
File renamed without changes
File renamed without changes
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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.qc.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:** | ||
|
|
||
|  | ||
|
|
||
| ```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.qc.color_chip_comparison(tgt_matrix, cc1_matrix, | ||
| cc2_matrix, cc3_matrix, | ||
| cc4_matrix, cc5_matrix, | ||
| cc6_matrix) | ||
|
|
||
| ``` | ||
|
|
||
| **Color chip comparison visualizations:** | ||
|
|
||
|  | ||
|
|
||
|
|
||
| **Source Code:** [Here](https://github.com/danforthcenter/plantcv/blob/master/plantcv/plantcv/qc/color_chip_comparison.py) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| ## Plot Delta E | ||
|
|
||
| This function creates an interactive bar chart visualizing per-chip Delta E (color difference) values from a color checker card. Each bar is colored by a standard interpretation category: green (<1) indicates imperceptible differences, progressing through yellow (<2, <10) to orange and red (<49, >49) for increasingly noticeable differences. Reference lines at the category boundaries are drawn for quick visual assessment. Standard chip color swatches from the target color matrix are displayed below the x-axis to aid chip identification. | ||
|
|
||
| **plantcv.qc.plot_deltaE**(*deltaE_matrix*) | ||
|
|
||
| **returns** chart, an altair.vegalite.v5.api.LayerChart object | ||
|
|
||
| - **Parameters:** | ||
| - deltaE_matrix - numpy.ndarray of per-chip Delta E values, shaped to match the color card layout (e.g., (6, 4) for a 24-chip Macbeth card or (3, 5) for a 15-chip AstroBotany card), as returned from [`pcv.transform.deltaE`](https://github.com/danforthcenter/plantcv/blob/main/plantcv/plantcv/transform/detect_color_card.py). | ||
|
|
||
| - **Context:** | ||
| - Used to evaluate the quality of color calibration by visualizing how closely observed chip colors match their expected values. Lower Delta E values indicate better color fidelity. This function is best used during workflow development to interactively inspect calibration results before and after color correction or between different color correction methods. | ||
|
|
||
| - **Example use:** | ||
| - Below | ||
|
|
||
| **Dataset image:** | ||
|
|
||
|  | ||
|
|
||
| ```python | ||
|
|
||
| from plantcv import plantcv as pcv | ||
| from plantcv.plantcv.transform.detect_color_card import deltaE | ||
|
|
||
| # Calculate Delta E values for each chip relative to the standard color matrix | ||
| # Note this is | ||
| de_matrix = deltaE(rgb_img=img, color_chip_size="classic") | ||
|
|
||
| # Plot the Delta E values | ||
| chart = pcv.qc.plot_deltaE(deltaE_matrix=de_matrix) | ||
|
|
||
| ``` | ||
|
|
||
| **Delta E bar chart:** | ||
|
|
||
|  | ||
|
|
||
|
|
||
| **Source Code:** [Here](https://github.com/danforthcenter/plantcv/blob/main/plantcv/plantcv/qc/plot_delta_e.py) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,9 @@ | ||
| from plantcv.plantcv.qc.exposure import exposure | ||
| from plantcv.plantcv.qc.quick_color_check import quick_color_check | ||
| from plantcv.plantcv.qc.color_correction_scatter import color_correction_plot | ||
| from plantcv.plantcv.qc.color_chip_comparison import color_chip_comparison | ||
| from plantcv.plantcv.qc.plot_delta_e import plot_deltaE | ||
|
|
||
|
|
||
| __all__ = ["exposure", "quick_color_check"] | ||
| __all__ = ["exposure", "quick_color_check", "color_correction_plot", "color_chip_comparison", | ||
| "plot_deltaE"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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. | ||
|
|
||
|
nfahlgren marked this conversation as resolved.
Outdated
|
||
| 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) | ||
|
nfahlgren marked this conversation as resolved.
Outdated
|
||
| # 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 | ||
|
nfahlgren marked this conversation as resolved.
Outdated
|
||
| # 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 | ||
File renamed without changes.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.