Set transparency (alpha) of matplotlib 3d grid - python

I would like to change the transparency of the grid in matplotlib 3d plot.
But I find that it is not as easy as in 2d, which is simply plt.grid(alpha=0.2).
Here I give a mini code
import numpy as np
import matplotlib.pyplot as plt
data = np.random.randn(3, 100)
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.scatter(data[0], data[1], data[2])
# How to change the grid transparency?
plt.show()
How to set the transparency of the x,y,z-grids?
I have tried:
Using ax.zaxis._axinfo['grid'].update({"alpha": 0.1}). But it appears that it does not have the key alpha.
I checked the source code of ax.grid() here in github. From the comments, it seems that the alpha functionality is not implemented for 3d case at all.

plt.grid does not seem to do anything for 3d plots. But you can set the color as a RGB+Alpha tuple using rcparams:
import numpy as np
import matplotlib.pyplot as plt
# fourth parameter is alpha=0.1
plt.rcParams['grid.color'] = (0.5, 0.5, 0.5, 0.1)
data = np.random.randn(3, 100)
fig = plt.figure()
ax = plt.axes(projection ="3d")
ax.scatter(data[0], data[1], data[2])
plt.show()
Result:

Related

How do I remove double ticks (leaving a single set) on a color bar in matplotlib's imshow? [duplicate]

I'm making some interactive plots and I would like to add a colorbar legend. I don't want the colorbar to be in its own axes, so I want to add it to the existing axes. I'm having difficulties doing this, as most of the example code I have found creates a new axes for the colorbar.
I have tried the following code using matplotlib.colorbar.ColorbarBase, which adds a colorbar to an existing axes, but it gives me strange results and I can't figure out how to specify attributes of the colorbar (for instance, where on the axes it is placed and what size it is)
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.cm import coolwarm
import numpy as np
x = np.random.uniform(1, 10, 10)
y = np.random.uniform(1, 10, 10)
v = np.random.uniform(1, 10, 10)
fig, ax = plt.subplots()
s = ax.scatter(x, y, c=v, cmap=coolwarm)
matplotlib.colorbar.ColorbarBase(ax=ax, cmap=coolwarm, values=sorted(v),
orientation="horizontal")
Using fig.colorbar instead ofmatplotlib.colorbar.ColorbarBase still doesn't give me quite what I want, and I still don't know how to adjust the attributes of the colorbar.
fig.colorbar(s, ax=ax, cax=ax)
Let's say I want to have the colorbar in the top left corner, stretching about halfway across the top of the plot. How would I go about doing that?
Am I better off writing a custom function for this, maybe using LineCollection?
This technique is usually used for multiple axis in a figure. In this context it is often required to have a colorbar that corresponds in size with the result from imshow. This can be achieved easily with the axes grid tool kit:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
data = np.arange(100, 0, -1).reshape(10, 10)
fig, ax = plt.subplots()
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.05)
im = ax.imshow(data, cmap='bone')
fig.colorbar(im, cax=cax, orientation='vertical')
plt.show()
The colorbar has to have its own axes. However, you can create an axes that overlaps with the previous one. Then use the cax kwarg to tell fig.colorbar to use the new axes.
For example:
import numpy as np
import matplotlib.pyplot as plt
data = np.arange(100, 0, -1).reshape(10, 10)
fig, ax = plt.subplots()
cax = fig.add_axes([0.27, 0.8, 0.5, 0.05])
im = ax.imshow(data, cmap='gist_earth')
fig.colorbar(im, cax=cax, orientation='horizontal')
plt.show()
Couldn't add this as a comment, but in case anyone is interested in using the accepted answer with subplots, the divider should be formed on specific axes object (rather than on the numpy.ndarray returned from plt.subplots)
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
data = np.arange(100, 0, -1).reshape(10, 10)
fig, ax = plt.subplots(ncols=2, nrows=2)
for row in ax:
for col in row:
im = col.imshow(data, cmap='bone')
divider = make_axes_locatable(col)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(im, cax=cax, orientation='vertical')
plt.show()

Plot the two matrices as colormaps on the same graph

I have two numpy multi dimmensional matrices that have five features each like this
array1 = array([ 1. , 0.97572023, 0.97671645, 0.99772446,
0.99326534, 0.94841498]....)
array2 = array([ 0.97572023, 1. , 0.99343976, 0.9844228 ,
0.9880037 , 0.96203135]....)
I want to plot these multidimesional matrices as colormaps and label each feature on the graph..Whats the best way to plot multidimensional array.
from matplotlib import pyplot as plt
from matplotlib import cm as cm
fig = plt.figure()
ax1 = fig.add_subplot(111)
cmap = cm.get_cmap('jet', 30)
cax = ax1.imshow(df, interpolation="nearest", cmap=cmap)
ax1.grid(True)
plt.title('Abalone Feature Correlation')
labels=['feat1','feat2','feat3','feat4','feat5']
ax1.set_xticklabels(labels,fontsize=6)
ax1.set_yticklabels(labels,fontsize=6)
# Add colorbar, make sure to specify tick locations to match desired ticklabels
fig.colorbar(cax, ticks=[0.1,0.2,0.3,0.4,0.5,0.6,.75,.8,.85,.90,.95,1])
plt.show()
I am using this function but the features are not displayed properly..The labels and the points are not displayed correctly.Any help?
Instructing matplotlib to use specific ticks for the imshow plot ensures that labels appear in the right places,
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import cm as cm
# Generate some data for the sake of example
array = np.random.uniform(0, 1, (5, 5))
fig = plt.figure()
ax1 = fig.add_subplot(111)
cmap = cm.get_cmap('jet', 30)
cax = ax1.imshow(array, interpolation="nearest", cmap=cmap)
ax1.grid(True)
plt.title('Abalone Feature Correlation')
labels=['feat1', 'feat2', 'feat3', 'feat4', 'feat5']
# Explicitly set ticks for the plot
ax1.set_xticks(np.arange(len(labels)))
ax1.set_yticks(np.arange(len(labels)))
ax1.set_xticklabels(labels,fontsize=6)
ax1.set_yticklabels(labels,fontsize=6)
# Add colorbar, make sure to specify tick locations to match desired ticklabels
fig.colorbar(cax, ticks=[0.1,0.2,0.3,0.4,0.5,0.6,.75,.8,.85,.90,.95,1])
plt.show()

How can I embed an image on each of my subplots in matplotlib?

I'm trying to put a little arrow in the corner of each of my subplots. Below is the sample code I'm using:
import matplotlib.pyplot as plt
import matplotlib.image as image
from numpy import linspace
xs = linspace(0, 1, 100)
im = image.imread('arrow.png')
def multi_plot():
fig, axes = plt.subplots(4, 1)
x = 0
for axis in axes:
axis.plot(xs, xs**2)
axis.imshow(im, extent=(0.4, 0.6, .5, .7), zorder=-1, aspect='auto')
plt.show()
multi_plot()
Unfortunately, this produces 4 subplots that are entirely dominated by the arrows and the plots themselves are not seen.
Example output - Incorrect:
What do I need to do so that each individual subplot has a small image and the plot itself can be seen?
I think it's worthwhile thinking about putting the image in a box and place it similar to the legend, using a loc argument. The advantage is that you don't need to care about extents and data coordinates at all. You also wouldn't need to take care of what happens when zooming or panning the plot. Further it allows to keep the image in it's original resolution (zoom=1 in below code).
import matplotlib.pyplot as plt
import matplotlib.image as image
from numpy import linspace
from matplotlib.offsetbox import OffsetImage,AnchoredOffsetbox
xs = linspace(0, 1, 100)
im = image.imread('arrow.png')
def place_image(im, loc=3, ax=None, zoom=1, **kw):
if ax==None: ax=plt.gca()
imagebox = OffsetImage(im, zoom=zoom*0.72)
ab = AnchoredOffsetbox(loc=loc, child=imagebox, frameon=False, **kw)
ax.add_artist(ab)
def multi_plot():
fig, axes = plt.subplots(4, 1)
for axis in axes:
axis.plot(xs, xs**2)
place_image(im, loc=2, ax=axis, pad=0, zoom=1)
plt.show()
multi_plot()
You'll notice that the limits on the x and y axis have been set to the extent of the imshow, rather than 0-1, which your plot needs to see the line.
You can control this by using axis.set_xlim(0, 1) and axis.set_ylim(0, 1).
import matplotlib.pyplot as plt
import matplotlib.image as image
from numpy import linspace
xs = linspace(0, 1, 100)
im = image.imread('arrow.png')
def multi_plot():
fig, axes = plt.subplots(4, 1)
x = 0
for axis in axes:
axis.plot(xs, xs**2)
axis.imshow(im, extent=(0.4, 0.6, .5, .7), zorder=-1, aspect='auto')
axis.set_xlim(0, 1)
axis.set_ylim(0, 1)
plt.show()
multi_plot()
Alternatively, if you want to maintain the extra 5% margin around your data that matplotlib uses by default, you can move the imshow command to before the plot command, then the latter will control the axis limits.
import matplotlib.pyplot as plt
import matplotlib.image as image
from numpy import linspace
xs = linspace(0, 1, 100)
im = image.imread('arrow.png')
def multi_plot():
fig, axes = plt.subplots(4, 1)
x = 0
for axis in axes:
axis.imshow(im, extent=(0.4, 0.6, .5, .7), zorder=-1, aspect='auto')
axis.plot(xs, xs**2)
plt.show()
multi_plot()

specific outliers on a heat map- matplotlib

I am generating a heat map with data that has a fixed outlier number and I need to show these outliers as a colour out of the colour palette of the cmap I use which is "hot". With the use of cmap.set_bad('green') and np.ma.masked_values(data, outlier), I get a plot which looks right but the color bar is not getting synced with the data properly even if I use cmap.set_over('green').
Here is the code I have been trying:
plt.xlim(0,35)
plt.ylim(0,35)
img=plt.imshow(data, interpolation='none',norm=norm, cmap=cmap,vmax=outlier)
cb_ax=fig.add_axes([0.85, 0.1, 0.03, 0.8])
cb=mpl.colorbar.ColorbarBase(cb_ax,cmap=cmap,norm=norm,extend='both',spacing='uniform')
cmap.set_over('green')
cmap.set_under('green')
Here is the data (outlier is 1.69 obviously):
Data;A;B;C;D;E;F;G;H;I;J;K
A;1.2;0;0;0;0;1.69;0;0;1.69;1.69;0
B;0;0;0;0;0;1.69;0;0;1.69;1.69;0
C;0;0;0;0;0;1.69;0;0.45;1.69;1.69;0.92
D;1;0;-0.7;-1.2;0;1.69;0;0;1.69;1.69;0
E;0;0;0;0;0;1.69;0;0;1.69;1.69;0
F;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69
G;0;0;0;0;0;1.69;0;0;1.69;1.69;0
H;0;0;0;0;0;1.69;0;0;1.69;1.69;0
I;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69
J;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69
K;0;0;0;0;0;1.69;0;0;1.69;1.69;0
Appreciate any help
What's happening is that you're using a masked array where the outliers are masked.
Therefore, they don't show up on the colorbar as being "over". (i.e. as far as matplotlib is concerned, the masked values are invalid, not over the threshold)
As a stand-alone example to reproduce your problem:
import numpy as np
import matplotlib.pyplot as plt
threshold = 0.8
data = np.random.random((10,10))
data = np.ma.masked_greater(data, threshold)
fig, ax = plt.subplots()
im = ax.imshow(data, cmap=plt.cm.hot, interpolation='none')
cbar = fig.colorbar(im, extend='max')
cbar.cmap.set_over('green')
plt.show()
If we simply don't make this a masked array, and instead specify the vmax kwarg to imshow:
import numpy as np
import matplotlib.pyplot as plt
threshold = 0.8
data = np.random.random((10,10))
fig, ax = plt.subplots()
im = ax.imshow(data, cmap=plt.cm.hot, interpolation='none', vmax=threshold)
cbar = fig.colorbar(im, extend='max')
cbar.cmap.set_over('green')
plt.show()
Basically, this is the difference between set_over (or under) and set_bad.
If you did still want to use a masked array, you could just call cbar.cmap.set_bad('green') as well as set_over, and you'd get the effect you want (though all "bad" values, not just ones over the threshold, would be green). If you take that route, you'll need to manually specify the vmax. Otherwise it will be taken as the maximum of the unmasked portions of the array.
I think you need to set extend to "both" and feed in a Normalize object:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas
from io import StringIO # python 3
#from StringIO import StringIO # python 2
datastring = StringIO("""\
Data;A;B;C;D;E;F;G;H;I;J;K
A;1.2;0;0;0;0;1.69;0;0;1.69;1.69;0
B;0;0;0;0;0;1.69;0;0;1.69;1.69;0
C;0;0;0;0;0;1.69;0;0.45;1.69;1.69;0.92
D;1;0;-0.7;-1.2;0;1.69;0;0;1.69;1.69;0
E;0;0;0;0;0;1.69;0;0;1.69;1.69;0
F;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69
G;0;0;0;0;0;1.69;0;0;1.69;1.69;0
H;0;0;0;0;0;1.69;0;0;1.69;1.69;0
I;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69
J;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69;1.69
K;0;0;0;0;0;1.69;0;0;1.69;1.69;0
""")
threshold = 1.68
data = pandas.read_table(datastring, sep=';', index_col='Data')
cmap = mpl.cm.coolwarm
norm = mpl.colors.Normalize(vmin=-1 * threshold, vmax=threshold)
cmap.set_over('slategray')
cmap.set_under('forestgreen')
fig, ax = plt.subplots()
ax.set_aspect('equal')
cb_ax=fig.add_axes([0.85, 0.1, 0.03, 0.8])
img = ax.imshow(data, cmap=cmap, norm=norm, interpolation='none')
cb = mpl.colorbar.ColorbarBase(cb_ax, cmap=cmap, norm=norm, extend='both')
Gives me:

Standalone colorbar (matplotlib)

I'm rendering some graphics in python with matplotlib, and will include them into a LaTeX paper (using LaTex's nice tabular alignment instead of fiddling with matplotlib's ImageGrid, etc.). I would like to create and save a standalone colorbar with savefig, without needing to use imshow.
(the vlim, vmax parameters, as well as the cmap could be provided explicitly)
The only way I could find was quite complicated and (from what I understand) draws a hard-coded rectangle onto the canvas:
http://matplotlib.org/examples/api/colorbar_only.html
Is there an elegant way to create a standalone colorbar with matplotlib?
You can create some dummy image and then hide it's axe. Draw your colorbar in a customize Axes.
import pylab as pl
import numpy as np
a = np.array([[0,1]])
pl.figure(figsize=(9, 1.5))
img = pl.imshow(a, cmap="Blues")
pl.gca().set_visible(False)
cax = pl.axes([0.1, 0.2, 0.8, 0.6])
pl.colorbar(orientation="h", cax=cax)
pl.savefig("colorbar.pdf")
the result:
Using the same idea as in HYRY's answer, if you want a "standalone" colorbar in the sense that it is independent of the items on a figure (not directly connected with how they are colored), you can do something like the following:
from matplotlib import pyplot as plt
import numpy as np
# create dummy invisible image
# (use the colormap you want to have on the colorbar)
img = plt.imshow(np.array([[0,1]]), cmap="Oranges")
img.set_visible(False)
plt.colorbar(orientation="vertical")
# add any other things you want to the figure.
plt.plot(np.random.rand(30))
So, based on this answer here, if you're like me and want to avoid this ugly fake plt.imshow(), you can do this in basically two lines:
import matplotlib as mpl
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
col_map = plt.get_cmap('nipy_spectral')
mpl.colorbar.ColorbarBase(ax, cmap=col_map, orientation = 'vertical')
# As for a more fancy example, you can also give an axes by hand:
c_map_ax = fig.add_axes([0.2, 0.8, 0.6, 0.02])
c_map_ax.axes.get_xaxis().set_visible(False)
c_map_ax.axes.get_yaxis().set_visible(False)
# and create another colorbar with:
mpl.colorbar.ColorbarBase(c_map_ax, cmap=col_map, orientation = 'horizontal')
That reference to http://matplotlib.org/examples/api/colorbar_only.html solved it for me. That example is a little verbose, so here is an easy way to make a standalone colorbar (for posterity)...
import matplotlib.pyplot as plt
import matplotlib as mpl
fig = plt.figure()
ax = fig.add_axes([0.05, 0.80, 0.9, 0.1])
cb = mpl.colorbar.ColorbarBase(ax, orientation='horizontal',
cmap='RdBu')
plt.savefig('just_colorbar', bbox_inches='tight')
Of course, you can specify many other aspects of the Colorbar
import matplotlib.pyplot as plt
import matplotlib as mpl
fig = plt.figure()
ax = fig.add_axes([0.05, 0.80, 0.9, 0.1])
cb = mpl.colorbar.ColorbarBase(ax, orientation='horizontal',
cmap='gist_ncar',
norm=mpl.colors.Normalize(0, 10), # vmax and vmin
extend='both',
label='This is a label',
ticks=[0, 3, 6, 9])
plt.savefig('just_colorbar', bbox_inches='tight')
This solution can be also used to draw the colorbar independenly of the content of ax.
Just set fraction = .05.
Code
import matplotlib as mpl
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 1)
fraction = 1 # .05
norm = mpl.colors.Normalize(vmin=-3, vmax=99)
cbar = ax.figure.colorbar(
mpl.cm.ScalarMappable(norm=norm, cmap='Blues'),
ax=ax, pad=.05, extend='both', fraction=fraction)
ax.axis('off')
plt.show()
To add to #blaylockbk's answer (which is a great solution, even to add to an already created figure), for me the cmap argument won't take strings for colormap names, but cmap = plt.cm.viridis works, if anyone run into the same problem as I.

Categories