I use python and want to make a heatmap with 1900 to 2000 on the x-axis. So I have a two dimensional function, say f(t,x), where t is between 1900 and 2000. Then I define g(x)= [f(t,x) for t in range(1900,2000)] and put everything in an array by z=numpy.array([g(x) for x in range(50)]). Then I plot the heatmap by pylab.color(z), but then I lose my dependency on years, because it is now in an array which start at zero. The x-axis is then from 0 to 100. How can I add 1900 to the x-axis, not in the label, but such that the range becomes 1900-2000. Thanks in advance.
If you're using pcolormesh (or pcolor, but pcolormesh is faster), you'll need to pass in explicit x and y arrays as well as your z array.
If you're using imshow, you'll need to use the extent kwarg.
As an example of using pcolormesh or pcolor:
import numpy as np
import matplotlib.pyplot as plt
z = np.arange(40).reshape(4, 10)
x = np.linspace(1900, 2000, 10)
y = np.linspace(20, 50, 4)
fig, ax = plt.subplots()
ax.pcolormesh(x, y, z, cmap='gist_earth')
plt.show()
As an example of using imshow (Note that you'd need to use aspect='auto' as well to make imshow and pcolormesh match exactly):
import numpy as np
import matplotlib.pyplot as plt
z = np.arange(40).reshape(4, 10)
x = np.linspace(1900, 2000, 10)
y = np.linspace(20, 50, 4)
fig, ax = plt.subplots()
ax.imshow(z, cmap='gist_earth', interpolation='nearest', origin='lower',
extent=[x.min(), x.max(), y.min(), y.max()])
plt.show()
Related
This is what I want to create.
This is what I get.
This is the code I have written.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
x = np.linspace(-90, 90, 181)
y = np.linspace(-90, 90, 181)
x_grid, y_grid = np.meshgrid(x, y)
z = np.e**x_grid
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection="3d")
ax.plot_surface(x_grid, y_grid, z, cmap=cm.rainbow)
I also tried to normalize z and the colormap.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
import matplotlib as mpl
x = np.linspace(-90, 90, 181)
y = np.linspace(-90, 90, 181)
x_grid, y_grid = np.meshgrid(x, y)
z = np.e**x_grid
cmap = mpl.cm.rainbow
norm = mpl.colors.Normalize(vmin=0, vmax=1)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection="3d")
ax.plot_surface(x_grid, y_grid, z/np.max(z), norm=norm, cmap=cm.rainbow)
Question: How can I adjust the colormap to make it less discrete and more continuous for these simultaneously tiny and large values in z?
Welcome to Stackoverflow!!
Your problem is related to the fact that you are working with exponential numbers, but you're using a linear colormap. For x=90 you have z=1.2e+39, reaaaally large.
You were very close with your second attempt! I just changed 1 line in there, instead of
norm = mpl.colors.Normalize(vmin=0, vmax=1)
I used
norm = mpl.colors.LogNorm()
And the result I got was the following:
Now, you can tweak this as much as you like in order to get the colors you want :) Just don't forget that your colormap should be normalized in a logarithmic fashion, so that it counters the exponential behaviour of your function in this case.
Hope this helps!
I am trying to vary opacity on each marker in a 3D scatter plot. I hit an issue with this where it was saying the color was not the correct length (even though it was). Moving to the simplest case it can be recreated with this.
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(subplot_kw={'projection': '3d'})
elements = 100
x = np.linspace(0, 10, elements)
ax.scatter(x, x, x, alpha=np.linspace(1, 0.5, elements), c=['b' for _ in range(elements)], label='label')
fig.legend()
plt.show()
If the label keyword argument is removed it works. If you do a 2D scatter plot it works regardless of the label. I am wondering if this is a bug but wanted to see if I was missing something first.
To accomplish what you want, try to use set_facecolors instead of directly using the alpha and color in the scatter plot.
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(subplot_kw={'projection': '3d'})
elements = 200
z = np.linspace(0, 2*np.pi, elements)
x = np.cos(z)
y = np.sin(z)
h = ax.scatter(x, y, z, label='label')
h.set_facecolors([[0., 0., 1., alpha] for alpha in np.linspace(0.1, 0.7, len(x))])
fig.legend()
plt.show()
What I want is quite simply adding to a normal pyplot.plot a horizontal line with the width equal to a range of values that I give. Preferably I also want to be able to adjust the transparency of this "block", that is the wide horizontal line.
I'd recommend to just use pyplot.fill_between():
import matplotlib.pyplot as pl
import numpy as np
fig = pl.figure()
ax = fig.add_subplot(111)
x = np.random.random(10)
y = np.random.random(10)
ax.scatter(x, y)
ax.fill_between(ax.get_xlim(), min(y), max(y), color='k', alpha=0.2)
I'm trying to plot some data with Matplotlib (Python library) and to add an horizontal line, that would not cover the full axis range but start around the middle and finish on the right axis.
I am using:
plt.axhline(y=1.75,xmin=0.5)
where y specifies the height of the line in data units, but xmin (as well as xmax) need to be defined in axis units (=0 for the beginning of axis and =1 at the end). Though I only know the point I want my line to start in data units, is there a method/function to convert from one to the other?
Just draw a line with plt
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0.2,10,100)
fig, ax = plt.subplots()
ax.plot(x, 1/x)
ax.plot(x, np.log(x))
ax.set_aspect('equal')
ax.grid(True, which='both')
y = 1.25
xmin = 2
xmax = ax.get_xlim()[1]
ax.plot([xmin, xmax], [y, y], color='k')
which gives me:
I have a range of points x and y stored in numpy arrays.
Those represent x(t) and y(t) where t=0...T-1
I am plotting a scatter plot using
import matplotlib.pyplot as plt
plt.scatter(x,y)
plt.show()
I would like to have a colormap representing the time (therefore coloring the points depending on the index in the numpy arrays)
What is the easiest way to do so?
Here is an example
import numpy as np
import matplotlib.pyplot as plt
x = np.random.rand(100)
y = np.random.rand(100)
t = np.arange(100)
plt.scatter(x, y, c=t)
plt.show()
Here you are setting the color based on the index, t, which is just an array of [1, 2, ..., 100].
Perhaps an easier-to-understand example is the slightly simpler
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(100)
y = x
t = x
plt.scatter(x, y, c=t)
plt.show()
Note that the array you pass as c doesn't need to have any particular order or type, i.e. it doesn't need to be sorted or integers as in these examples. The plotting routine will scale the colormap such that the minimum/maximum values in c correspond to the bottom/top of the colormap.
Colormaps
You can change the colormap by adding
import matplotlib.cm as cm
plt.scatter(x, y, c=t, cmap=cm.cmap_name)
Importing matplotlib.cm is optional as you can call colormaps as cmap="cmap_name" just as well. There is a reference page of colormaps showing what each looks like. Also know that you can reverse a colormap by simply calling it as cmap_name_r. So either
plt.scatter(x, y, c=t, cmap=cm.cmap_name_r)
# or
plt.scatter(x, y, c=t, cmap="cmap_name_r")
will work. Examples are "jet_r" or cm.plasma_r. Here's an example with the new 1.5 colormap viridis:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(100)
y = x
t = x
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.scatter(x, y, c=t, cmap='viridis')
ax2.scatter(x, y, c=t, cmap='viridis_r')
plt.show()
Colorbars
You can add a colorbar by using
plt.scatter(x, y, c=t, cmap='viridis')
plt.colorbar()
plt.show()
Note that if you are using figures and subplots explicitly (e.g. fig, ax = plt.subplots() or ax = fig.add_subplot(111)), adding a colorbar can be a bit more involved. Good examples can be found here for a single subplot colorbar and here for 2 subplots 1 colorbar.
To add to wflynny's answer above, you can find the available colormaps here
Example:
import matplotlib.cm as cm
plt.scatter(x, y, c=t, cmap=cm.jet)
or alternatively,
plt.scatter(x, y, c=t, cmap='jet')
Subplot Colorbar
For subplots with scatter, you can trick a colorbar onto your axes by building the "mappable" with the help of a secondary figure and then adding it to your original plot.
As a continuation of the above example:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y = x
t = x
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.scatter(x, y, c=t, cmap='viridis')
ax2.scatter(x, y, c=t, cmap='viridis_r')
# Build your secondary mirror axes:
fig2, (ax3, ax4) = plt.subplots(1, 2)
# Build maps that parallel the color-coded data
# NOTE 1: imshow requires a 2-D array as input
# NOTE 2: You must use the same cmap tag as above for it match
map1 = ax3.imshow(np.stack([t, t]),cmap='viridis')
map2 = ax4.imshow(np.stack([t, t]),cmap='viridis_r')
# Add your maps onto your original figure/axes
fig.colorbar(map1, ax=ax1)
fig.colorbar(map2, ax=ax2)
plt.show()
Note that you will also output a secondary figure that you can ignore.
Single colorbar for multiple subplots
sometimes it is preferable to have a single colorbar to indicate data values visualised on multiple subplots.
In this case, a Normalize() object needs to be created using the minimum and maximum data values across both plots.
Then a colorbar object can be created from a ScalarMappable() object, which maps between scalar values and colors.
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
y = x
t1 = x # Colour data for first plot
t2 = 2*x # Color data for second plot
all_data = np.concatenate([t1, t2])
# Create custom Normalise object using the man and max data values across both subplots to ensure colors are consistent on both plots
norm = plt.Normalize(np.min(all_data), np.max(all_data))
fig, axs = plt.subplots(1, 2)
axs[0].scatter(x, y, c=t1, cmap='viridis', norm=norm)
axs[1].scatter(x**2, y, c=t2, cmap='viridis', norm=norm)
# Create the colorbar
smap = plt.cm.ScalarMappable(cmap='viridis', norm=norm)
cbar = fig.colorbar(smap, ax=axs, fraction=0.1, shrink = 0.8)
cbar.ax.tick_params(labelsize=11)
cbar.ax.set_ylabel('T', rotation=0, labelpad = 15, fontdict = {"size":14})
plt.show()
subplots_colorbar