Skip to content
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

Scalar ranges for colors on a 3-D object. #35

Closed
gunjan71011 opened this issue Jul 31, 2019 · 10 comments
Closed

Scalar ranges for colors on a 3-D object. #35

gunjan71011 opened this issue Jul 31, 2019 · 10 comments
Assignees
Labels
data-arrays Adding, using, and accessing data arrays on meshes plotting General plotting/rendering topics

Comments

@gunjan71011
Copy link

Greetings! I had a difficulty with trying to find a way to set ranges for a scalar for a 3-D object. For example for a 3D grid the z values would be the scalar and if my minimum and maximum values are 2000 to 10,000, can I make lets say, 2000-4000 red in color, 4000-5000 a green in color and etc...?
As far as I know, I know that you can change the color map pretty easily by using plotter.addmesh(cmap = 'color'), and you can set the overall range also pretty easily by using the plotter.update_scalar_bar_range(clim=[0,10000]).
Could you guys have any feedback on this? Thank you!

@banesullivan
Copy link
Member

Hi @gunjan71011! For this situation, you would need to make your own colormap using Matplotlib and pass that colormap as the cmap argument.

Perhaps try an example like this: https://matplotlib.org/gallery/images_contours_and_fields/custom_cmap.html

And then pass it to PyVista similar to this example: https://docs.pyvista.org/examples/02-plot/cmap.html

FYI: there is a clim argument for the add_mesh method so you don’t need to use update_scalar_bar_range()

Sent with GitHawk

@banesullivan banesullivan added the plotting General plotting/rendering topics label Jul 31, 2019
@banesullivan banesullivan self-assigned this Jul 31, 2019
@gunjan71011
Copy link
Author

Thanks for the clim argument tip! So I payed around with customizing and making my own cmap and putting it into pyvista, however, I still can't get the colors to exactly be between a range of values, more specifically I want it to be between certain ranges of the scalar values used to scale my figure. I can create a colorbar with the exact values I want using matplotlib just fine, but i think you can only use color maps on pyvista using the cmap argument. Would you have any more feedback? Thank you!

@banesullivan
Copy link
Member

banesullivan commented Aug 1, 2019

Could you provide your code to make the matplotlib colormap?

@gunjan71011
Copy link
Author

gunjan71011 commented Aug 1, 2019

from matplotlib.colors import ListedColormap
from matplotlib import cm
import numpy as np

viridis = cm.get_cmap('viridis', 256)
newcolors = viridis(np.linspace(0, 1, 256))
blue = np.array([12/256, 238/256, 246/256, 1])
black = np.array([11/256, 11/256, 11/256, 1])
grey = np.array([189/256, 189/256, 189/256, 1])
yellow = np.array([255/256, 247/256, 0/256, 1])
red = np.array([1,0,0,1])
newcolors[0] = black                    #If my scaler is 0 i want it to be black in color
newcolors[1:30] = blue                 #If my scaler is between 1 and 30 I want it to be blue in color
newcolors[30:55] = yellow
newcolors[55:80] = grey
newcolors[80:] = red                      #Above 80 I want it to be red. The thing is I don't think these numbers actually represent the scalar values. But I would like it to.
newcmp = ListedColormap(newcolors)

Got this idea from:
https://matplotlib.org/3.1.1/tutorials/colors/colormap-manipulation.html

@banesullivan banesullivan added the data-arrays Adding, using, and accessing data arrays on meshes label Aug 1, 2019
@banesullivan
Copy link
Member

Here's an example - the colormap needed a bit more work:

import pyvista as pv
from pyvista import examples
from matplotlib.colors import ListedColormap
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
pv.set_plot_theme('doc')

mesh = examples.download_st_helens()
mesh['values'] = pv.plotting.normalize(mesh['Elevation']) * 100
# Make the custom colormap
blue = np.array([12/256, 238/256, 246/256, 1])
black = np.array([11/256, 11/256, 11/256, 1])
grey = np.array([189/256, 189/256, 189/256, 1])
yellow = np.array([255/256, 247/256, 0/256, 1])
red = np.array([1,0,0,1])

mapping = np.linspace(mesh['values'].min(), mesh['values'].max(), 256)
newcolors = np.empty((256, 4))

newcolors[mapping >= 80] = red
newcolors[mapping < 80] = grey
newcolors[mapping < 55] = yellow
newcolors[mapping < 30] = blue
newcolors[mapping < 1] = black
mycolormap = ListedColormap(newcolors)

# Plot with Matplotlib for a sanity check
image = mesh['values'].reshape(mesh.dimensions[:2], order='f')
plt.pcolormesh(image, cmap=mycolormap)
plt.colorbar()

download

# Plot with PyVista in 3D!
mesh.warp_by_scalar('Elevation').plot(scalars='values', cmap=mycolormap)

download

@banesullivan banesullivan added the add-to-gallery For examples that need to be added to the gallery in the docs label Aug 1, 2019
@banesullivan
Copy link
Member

banesullivan commented Aug 1, 2019

Please note that you likely won't be able to plot your mesh with Matplotlib - that only works if the input dataset is a 2D pyvista.UniformGrid object

banesullivan added a commit to pyvista/pyvista that referenced this issue Aug 1, 2019
@banesullivan
Copy link
Member

FYI: I added this to the example gallery: https://docs.pyvista.org/examples/02-plot/cmap.html#custom-made-colormaps

@gunjan71011
Copy link
Author

would you know how can fix the issue to normalize my data? The line "mesh['values'] = pv.plotting.normalize(mesh['Elevation']) * 100" keeps giving the error: module 'pyvista.plotting' has no attribute 'normalize'

@banesullivan
Copy link
Member

Hm - you must be on an older version of PyVista. That's a simple function that you could just copy/paste:

def normalize(x, minimum=None, maximum=None):
    if minimum is None:
        minimum = np.nanmin(x)
    if maximum is None:
        maximum = np.nanmax(x)
    return (x - minimum) / (maximum - minimum)

But note that you will not need that normalizing function when you do this with your data - I simply used that to make an example with similar ranges to yours.

@gunjan71011
Copy link
Author

Thanks Bane, that was really helpful!

@banesullivan banesullivan removed the add-to-gallery For examples that need to be added to the gallery in the docs label Feb 3, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
data-arrays Adding, using, and accessing data arrays on meshes plotting General plotting/rendering topics
Projects
None yet
Development

No branches or pull requests

2 participants