Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

sfladi
Copy link

@sfladi sfladi commented Jul 18, 2024

Overview

Correction to the way the color LookupTable (LUT) is tranfered from the actor/mappable to the ScalarBars, when both background_color and below_range_color and/or above_range_color are specified.

resolves #6390

Details

  • Added manual assignments of below_range_color and above_range_color to the scalar bar color LookupTable in ScalarBars.add_scalar_bar(), as LookupTable.DeepCopy(...) [presumably] only handles the underlying VTK implementation.

@pyvista-bot pyvista-bot added the bug Uh-oh! Something isn't working as expected. label Jul 18, 2024
Copy link

codecov bot commented Jul 18, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 97.41%. Comparing base (6cfe560) to head (29e454a).
Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6393   +/-   ##
=======================================
  Coverage   97.41%   97.41%           
=======================================
  Files         143      143           
  Lines       27831    27833    +2     
=======================================
+ Hits        27111    27113    +2     
  Misses        720      720           

@MatthewFlamm
Copy link
Contributor

MatthewFlamm commented Jul 18, 2024

@tkoyama010 I suspect that the caching for the documentation is now broken. Are you able to clear the cache manually or increment the key in some way to invalidate it for future runs?

Added: Otherwise we can use the no-gallery-cache label, but I suspect we will need to add it to all PRs this way.

@tkoyama010
Copy link
Member

tkoyama010 commented Jul 18, 2024

@tkoyama010 I suspect that the caching for the documentation is now broken. Are you able to clear the cache manually or increment the key in some way to invalidate it for future runs?

Added: Otherwise we can use the no-gallery-cache label, but I suspect we will need to add it to all PRs this way.

I cleared the cache manually. If a similar problem occurs again in the future, let's deal with it.

Copy link
Member

@tkoyama010 tkoyama010 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your first contribution. We would like to add a test for this, so could you please provide the sample code that led you to find this bug?

@sfladi
Copy link
Author

sfladi commented Jul 18, 2024

Thank you for your first contribution. We would like to add a test for this, so could you please provide the sample code that led you to find this bug?

I basically described this in the issue #6390 under "Steps to reproduce the bug".

But I will provide a more concise example once I am back at my PC.

@sfladi
Copy link
Author

sfladi commented Jul 22, 2024

Here is a minimal example that produces a visualization including a scalar bar with selected background_color and out of range colors (below_color and above_color). We compare the LookupTable out of range colors of the actor and the scalar bar. This fails for the current release version of pyvista and succeeds with this merge request.

The code below explicitly calls pv.Plotter.add_scalar_bar(), as this function wraps pv.plotting.scalar_bars.ScalarBars.add_scalar_bar()), which is where the proposed changes are implemented.

import numpy as np
import pyvista as pv

# parameters
cmap = "viridis"
below_color = "magenta"
above_color = "red"
background_color = "cyan"
data = np.arange(10, dtype=float)
clim = [2.0, 8.0]

# create minimal DataSet
mesh = pv.PointSet(np.stack((data, np.zeros_like(data), np.zeros_like(data)), axis=-1))
mesh["Data"] = data

# visualization
plotter = pv.Plotter()
actor = plotter.add_mesh(
    mesh,
    clim=clim,
    below_color=below_color,
    above_color=above_color,
    copy_mesh=True,
    cmap=cmap,
    show_scalar_bar=False,
)
scalar_bar = plotter.add_scalar_bar(
    mapper=actor.mapper,
    background_color=background_color,
    fill=True,
    outline=True,
)

# compare out of range colors for the actors and the scalar bar
scalar_bar_lut = scalar_bar.GetLookupTable()
assert actor.mapper.lookup_table.below_range_color == scalar_bar_lut.below_range_color
assert actor.mapper.lookup_table.above_range_color == scalar_bar_lut.above_range_color
# plotter.show()

@sfladi
Copy link
Author

sfladi commented Jul 24, 2024

It occured to be that simply copying the out of range colors from the mapper lookuptable to the colorbar lookuptable might be too simple of a fix.
For transparent out of range colors, a tranformation like in L446 of

lut = pyvista.LookupTable()
lut.DeepCopy(mapper.lookup_table)
ctable = _vtk.vtk_to_numpy(lut.GetTable())
alphas = ctable[:, -1][:, np.newaxis] / 255.0
use_table = ctable.copy()
use_table[:, -1] = 255.0
ctable = (use_table * alphas) + background_color * (1 - alphas)
lut.SetTable(_vtk.numpy_to_vtk(ctable, array_type=_vtk.VTK_UNSIGNED_CHAR))

could be desirable, e.g.:

below_alpha = mapper_lut.below_range_color.opacity / 255
below_color = np.array(mapper_lut.below_range_color.int_rgba)
below_color[-1] = 255  
background_color = np.array(background_color.int_rgba)

scalar_bar_lut.below_range_color = Color(
    (below_alpha * below_color + (1 - below_alpha) * background_color).astype(int)
)

I will update my feature branch to incorporate this additional logic, if that is okay.

The test code snippet provided in my previous comment would still hold for opaque out of range colors.

@sfladi
Copy link
Author

sfladi commented Jul 24, 2024

I looked some further into this as the following was unclear to me:

  • Why is L446 of pyvista.plotting.scalar_bars implemented in the way that the colors of a transparent scalar_bar are manually "blended" with a specified background color?

  • And why does pv.Plotter.add_scalar_bar have separate background_color and fill arguments?

First of all, L446 has no effect on opaque scalar bars, only transparent ones.

Furthermore, any transparent ScalarBar will naturally blend with the background during rendering, making L446 effectively irrelevant, unless fill=False.

This leads us to the edge case of pv.Plotter.add_scalar_bar(..., background_color=some_other_color, fill=False):
This apparently allows you to blend a transparent ScalarBar with some_other_color, while not actually adding that color as ScalarBar background.
This may be usefull in displaying the "true" ScalarBar colors with background_color="w" in a render scene, where the render window background is a different color.
Is that the actually a use case or am I missing something here?

Therefore, my question would be:

  • Should the functionality of L446 exclusively be applied for fill=False, including extending the background color blending to out of range colors?
  • Or could the functionality of L446 be removed entirely?

@user27182
Copy link
Contributor

I looked some further into this as the following was unclear to me:

  • Why is L446 of pyvista.plotting.scalar_bars implemented in the way that the colors of a transparent scalar_bar are manually "blended" with a specified background color?
  • And why does pv.Plotter.add_scalar_bar have separate background_color and fill arguments?

First of all, L446 has no effect on opaque scalar bars, only transparent ones.

Furthermore, any transparent ScalarBar will naturally blend with the background during rendering, making L446 effectively irrelevant, unless fill=False.

This leads us to the edge case of pv.Plotter.add_scalar_bar(..., background_color=some_other_color, fill=False): This apparently allows you to blend a transparent ScalarBar with some_other_color, while not actually adding that color as ScalarBar background. This may be usefull in displaying the "true" ScalarBar colors with background_color="w" in a render scene, where the render window background is a different color. Is that the actually a use case or am I missing something here?

Thank you for your contribution. This is a great analysis of what should be expected from user inputs and the behaviour of the plots. I am not knowledgable enough about the scalar bars to properly respond, but L446 was last modified 3 years ago as part of b3362c2, it's quite possible that there are gaps in the testing and/or implementation. This comment suggests that there is/was missing test coverage.

Therefore, my question would be:

  • Should the functionality of L446 exclusively be applied for fill=False, including extending the background color blending to out of range colors?
  • Or could the functionality of L446 be removed entirely?

A good way to figure this out is to systematically write test cases (e.g. in test_scalar_bars.py or test_plotting.py) with the user inputs and expected outputs. Any tests that fail would likely provide an answer to these questions. Or if there are problems/inconsistencies with the API feel free to suggest improvements. Let us know how if there's anything we can do to help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Uh-oh! Something isn't working as expected.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Setting background_color for a scalar bar overwrites/invalidates out of range colors
5 participants