changing default x range in histogram matplotlib - python

I would like to change the default x range for the histogram plot. The range of the data is from 7 to 12. However, by default the histogram starts right at 7 and ends at 13. I want it to start at 6.5 and end at 12.5. However, the ticks should go from 7 to 12.How do I do it?
import asciitable
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import pylab
from pylab import xticks
data = asciitable.read(file)
hmag = data['col8']
visits = data['col14']
origin = data['col13']
n, bins, patches = plt.hist(hmag, 30, facecolor='gray', align='mid')
xticks(range(7,13))
pylab.rc("axes", linewidth=8.0)
pylab.rc("lines", markeredgewidth=2.0)
plt.xlabel('H mag', fontsize=14)
plt.ylabel('# of targets', fontsize=14)
pylab.xticks(fontsize=15)
pylab.yticks(fontsize=15)
plt.grid(True)
plt.savefig('hmag_histogram.eps', facecolor='w', edgecolor='w', format='eps')
plt.show()

plt.hist(hmag, 30, range=[6.5, 12.5], facecolor='gray', align='mid')

import matplotlib.pyplot as plt
...
plt.xlim(xmin=6.5, xmax = 12.5)

the following code is for making the same y axis limit on two subplots
f ,ax = plt.subplots(1,2,figsize = (30, 13),gridspec_kw={'width_ratios': [5, 1]})
df.plot(ax = ax[0], linewidth = 2.5)
ylim = [lower_limit,upper_limit]
ax[0].set_ylim(ylim)
ax[1].hist(data,normed =1, bins = num_bin, color = 'yellow' ,alpha = 1)
ax[1].set_ylim(ylim)
just a reminder, plt.hist(range=[low, high]) the histogram auto crops the range if the specified range is larger than the max&min of the data points. So if you want to specify the y-axis range number, i prefer to use set_ylim

Related

Adding a colorbar to pyplot [duplicate]

I have a sequence of line plots for two variables (x,y) for a number of different values of a variable z. I would normally add the line plots with legends like this:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
# suppose mydata is a list of tuples containing (xs, ys, z)
# where xs and ys are lists of x's and y's and z is a number.
legns = []
for(xs,ys,z) in mydata:
pl = ax.plot(xs,ys,color = (z,0,0))
legns.append("z = %f"%(z))
ax.legends(legns)
plt.show()
But I have too many graphs and the legends will cover the graph. I'd rather have a colorbar indicating the value of z corresponding to the color. I can't find anything like that in the galery and all my attempts do deal with the colorbar failed. Apparently I must create a collection of plots before trying to add a colorbar.
Is there an easy way to do this? Thanks.
EDIT (clarification):
I wanted to do something like this:
import matplotlib.pyplot as plt
import matplotlib.cm as cm
fig = plt.figure()
ax = fig.add_subplot(111)
mycmap = cm.hot
# suppose mydata is a list of tuples containing (xs, ys, z)
# where xs and ys are lists of x's and y's and z is a number between 0 and 1
plots = []
for(xs,ys,z) in mydata:
pl = ax.plot(xs,ys,color = mycmap(z))
plots.append(pl)
fig.colorbar(plots)
plt.show()
But this won't work according to the Matplotlib reference because a list of plots is not a "mappable", whatever this means.
I've created an alternative plot function using LineCollection:
def myplot(ax,xs,ys,zs, cmap):
plot = lc([zip(x,y) for (x,y) in zip(xs,ys)], cmap = cmap)
plot.set_array(array(zs))
x0,x1 = amin(xs),amax(xs)
y0,y1 = amin(ys),amax(ys)
ax.add_collection(plot)
ax.set_xlim(x0,x1)
ax.set_ylim(y0,y1)
return plot
xs and ys are lists of lists of x and y coordinates and zs is a list of the different conditions to colorize each line. It feels a bit like a cludge though... I thought that there would be a more neat way to do this. I like the flexibility of the plt.plot() function.
(I know this is an old question but...) Colorbars require a matplotlib.cm.ScalarMappable, plt.plot produces lines which are not scalar mappable, therefore, in order to make a colorbar, we are going to need to make a scalar mappable.
Ok. So the constructor of a ScalarMappable takes a cmap and a norm instance. (norms scale data to the range 0-1, cmaps you have already worked with and take a number between 0-1 and returns a color). So in your case:
import matplotlib.pyplot as plt
sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.normalize(min=0, max=1))
plt.colorbar(sm)
Because your data is in the range 0-1 already, you can simplify the sm creation to:
sm = plt.cm.ScalarMappable(cmap=my_cmap)
EDIT: For matplotlib v1.2 or greater the code becomes:
import matplotlib.pyplot as plt
sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.normalize(vmin=0, vmax=1))
# fake up the array of the scalar mappable. Urgh...
sm._A = []
plt.colorbar(sm)
EDIT: For matplotlib v1.3 or greater the code becomes:
import matplotlib.pyplot as plt
sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.Normalize(vmin=0, vmax=1))
# fake up the array of the scalar mappable. Urgh...
sm._A = []
plt.colorbar(sm)
EDIT: For matplotlib v3.1 or greater simplifies to:
import matplotlib.pyplot as plt
sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.Normalize(vmin=0, vmax=1))
plt.colorbar(sm)
Here's one way to do it while still using plt.plot(). Basically, you make a throw-away plot and get the colorbar from there.
import matplotlib as mpl
import matplotlib.pyplot as plt
min, max = (-40, 30)
step = 10
# Setting up a colormap that's a simple transtion
mymap = mpl.colors.LinearSegmentedColormap.from_list('mycolors',['blue','red'])
# Using contourf to provide my colorbar info, then clearing the figure
Z = [[0,0],[0,0]]
levels = range(min,max+step,step)
CS3 = plt.contourf(Z, levels, cmap=mymap)
plt.clf()
# Plotting what I actually want
X=[[1,2],[1,2],[1,2],[1,2]]
Y=[[1,2],[1,3],[1,4],[1,5]]
Z=[-40,-20,0,30]
for x,y,z in zip(X,Y,Z):
# setting rgb color based on z normalized to my range
r = (float(z)-min)/(max-min)
g = 0
b = 1-r
plt.plot(x,y,color=(r,g,b))
plt.colorbar(CS3) # using the colorbar info I got from contourf
plt.show()
It's a little wasteful, but convenient. It's also not very wasteful if you make multiple plots as you can call plt.colorbar() without regenerating the info for it.
Here is a slightly simplied example inspired by the top answer given by Boris and Hooked (Thanks for the great idea!):
1. Discrete colorbar
Discrete colorbar is more involved, because colormap generated by mpl.cm.get_cmap() is not a mappable image needed as a colorbar() argument. A dummie mappable needs to generated as shown below:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
n_lines = 5
x = np.linspace(0, 10, 100)
y = np.sin(x[:, None] + np.pi * np.linspace(0, 1, n_lines))
c = np.arange(1, n_lines + 1)
cmap = mpl.cm.get_cmap('jet', n_lines)
fig, ax = plt.subplots(dpi=100)
# Make dummie mappable
dummie_cax = ax.scatter(c, c, c=c, cmap=cmap)
# Clear axis
ax.cla()
for i, yi in enumerate(y.T):
ax.plot(x, yi, c=cmap(i))
fig.colorbar(dummie_cax, ticks=c)
plt.show();
This will produce a plot with a discrete colorbar:
2. Continuous colorbar
Continuous colorbar is less involved, as mpl.cm.ScalarMappable() allows us to obtain an "image" for colorbar().
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
n_lines = 5
x = np.linspace(0, 10, 100)
y = np.sin(x[:, None] + np.pi * np.linspace(0, 1, n_lines))
c = np.arange(1, n_lines + 1)
norm = mpl.colors.Normalize(vmin=c.min(), vmax=c.max())
cmap = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.jet)
cmap.set_array([])
fig, ax = plt.subplots(dpi=100)
for i, yi in enumerate(y.T):
ax.plot(x, yi, c=cmap.to_rgba(i + 1))
fig.colorbar(cmap, ticks=c)
plt.show();
This will produce a plot with a continuous colorbar:
[Side note] In this example, I personally don't know why cmap.set_array([]) is necessary (otherwise we'd get error messages). If someone understand the principles under the hood, please comment :)
As other answers here do try to use dummy plots, which is not really good style, here is a generic code for a
Discrete colorbar
A discrete colorbar is produced in the same way a continuous colorbar is created, just with a different Normalization. In this case a BoundaryNorm should be used.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
n_lines = 5
x = np.linspace(0, 10, 100)
y = np.sin(x[:, None] + np.pi * np.linspace(0, 1, n_lines))
c = np.arange(1., n_lines + 1)
cmap = plt.get_cmap("jet", len(c))
norm = matplotlib.colors.BoundaryNorm(np.arange(len(c)+1)+0.5,len(c))
sm = plt.cm.ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([]) # this line may be ommitted for matplotlib >= 3.1
fig, ax = plt.subplots(dpi=100)
for i, yi in enumerate(y.T):
ax.plot(x, yi, c=cmap(i))
fig.colorbar(sm, ticks=c)
plt.show()

Use custom tick marks on axes coordinates

I'm plotting some function in matplotlib. But I want to change the usual x and y coordinates. For example I plot y=sin(x) in [-pi, pi]. But the x-axis shows 1, 2, 3,... in this way whereas I want x: -pi, 0, pi,... Is it possible?
My Code
import matplotlib as mpl
mpl.rc('text', usetex = True)
mpl.rc('font', family = 'serif')
import matplotlib.pyplot as plt
import numpy as np
plt.gca().set_aspect('equal', adjustable='box')
plt.style.use(['ggplot','dark_background'])
x = np.arange(-np.pi,np.pi,0.001)
y = np.sin(x)
plt.xlabel('$x$')
plt.ylabel('$y$')
plt.plot(x,y, label='$y=\sin x$')
plt.legend()
plt.show()
Output
How to change the marks on the axes coordinates? Thank you.
Yes, you can have custom tick marks on the axis, and set them equally spaced; for this you need to set the tick marks as a sequence, together with the values associated:
import matplotlib as mpl
mpl.rc('text', usetex = True)
mpl.rc('font', family = 'serif')
import matplotlib.pyplot as plt
import numpy as np
plt.gca().set_aspect('equal', adjustable='box')
plt.style.use(['ggplot','dark_background'])
x = np.arange(-np.pi,np.pi,0.001)
y = np.sin(x)
# the following two sequences contain the values and their assigned tick markers
xx = [-np.pi + idx*np.pi/4 for idx in range(10)]
xx_t = ['$-\\pi$', '$\\frac{-3\\pi}{4}$', '$\\frac{-\\pi}{2}$', '$\\frac{-\\pi}{4}$', '0',
'$\\frac{\\pi}{4}$', '$\\frac{\\pi}{2}$', '$\\frac{3\\pi}{4}$', '$\\pi$']
plt.xticks(xx, xx_t) # <-- the mapping happens here
plt.xlabel('$x$')
plt.ylabel('$y$')
plt.plot(x,y, label='$y=\sin x$')
plt.legend()
plt.show()
Here you can display up to whichever range of pi you want to. Just add the following lines to your code after plt.plot
xlabs = [r'%d$\pi$'%i if i!=0 else 0 for i in range(-2, 3, 1)]
xpos = np.linspace(-2*np.pi, 2*np.pi, 5)
plt.xticks(xpos, xlabs)
Output

Intervals on x axis

I want to change the size of the of the intervals between numbers.
The x axis obviously goes from 10 to 26. But I want every whole number to be displayed: 10, 11, 12, 13 etc...
I also want bins to have a width of .5 so that I can have a bin from 10.5 to 11 or 24 to 24.5 etc...because otherwise, python outputs the histogram with the bins random and undetermined.
Here's what I have:
import random
import numpy
from matplotlib import pyplot
import numpy as np
data = np.genfromtxt('result.csv',delimiter=',',skip_header=1, dtype=float)
magg=[row[5] for row in data]
magr=[row[6] for row in data]
bins = numpy.linspace(10, 26)
pyplot.hist(magg, bins, alpha=0.5, color='g', label='mag of g')
pyplot.hist(magr, bins, alpha=0.5, color='r', label='mag of r')
pyplot.legend(loc='upper left')
pyplot.show()
Use an axes locator, in particular, MultipleLocator. Building of your example, it becomes this:
import matplotlib.pyplot as plt
import numpy as np
x = np.random.random_integers(low=10, high=27, size=37)
bins = np.linspace(10, 26)
fig, ax = plt.subplots()
hist = ax.hist(x, bins, alpha=0.5, color='g', label='mag of g')
ax.xaxis.set_major_locator(plt.MultipleLocator(1))

matplotlib hist() autocropping range

I am trying to make a histgram over a specific range but the matplotlib.pyplot.hist() function keeps cropping the range to the bins with entries in them. A toy example:
import numpy as np
import matplotlib.pyplot as plt
x = np.random.uniform(-100,100,1000)
nbins = 100
xmin = -500
xmax = 500
fig = plt.figure();
ax = fig.add_subplot(1, 1, 1)
ax.hist(x, bins=nbins,range=[xmin,xmax])
plt.show()
Gives a plot with a range [-100,100]. Why is the range not [-500,500] as specified?
(I am using the Enthought Canopy 1.4 and sorry but I do not have a high enough rep to post an image of the plot.)
Actually, it works if you specify with range an interval shorter than [-100, 100]. For example, this work :
import numpy as np
import matplotlib.pyplot as plt
x = np.random.uniform(-100, 100, 1000)
plt.hist(x, bins=30, range=(-50, 50))
plt.show()
If you want to plot the histogram on a range larger than [x.min(), x.max()] you can change xlim propertie of the plot.
import numpy as np
import matplotlib.pyplot as plt
x = np.random.uniform(-100, 100, 1000)
plt.hist(x, bins=30)
plt.xlim(-500, 500)
plt.show()
the following code is for making the same y axis limit on two subplots
f ,ax = plt.subplots(1,2,figsize = (30, 13),gridspec_kw={'width_ratios': [5, 1]})
df.plot(ax = ax[0], linewidth = 2.5)
ylim = [df['min_return'].min()*1.1,df['max_return'].max()*1.1]
ax[0].set_ylim(ylim)
ax[1].hist(data,normed =1, bins = num_bin, color = 'yellow' ,alpha = 1)
ax[1].set_ylim(ylim)

Matplotlib - add colorbar to a sequence of line plots

I have a sequence of line plots for two variables (x,y) for a number of different values of a variable z. I would normally add the line plots with legends like this:
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
# suppose mydata is a list of tuples containing (xs, ys, z)
# where xs and ys are lists of x's and y's and z is a number.
legns = []
for(xs,ys,z) in mydata:
pl = ax.plot(xs,ys,color = (z,0,0))
legns.append("z = %f"%(z))
ax.legends(legns)
plt.show()
But I have too many graphs and the legends will cover the graph. I'd rather have a colorbar indicating the value of z corresponding to the color. I can't find anything like that in the galery and all my attempts do deal with the colorbar failed. Apparently I must create a collection of plots before trying to add a colorbar.
Is there an easy way to do this? Thanks.
EDIT (clarification):
I wanted to do something like this:
import matplotlib.pyplot as plt
import matplotlib.cm as cm
fig = plt.figure()
ax = fig.add_subplot(111)
mycmap = cm.hot
# suppose mydata is a list of tuples containing (xs, ys, z)
# where xs and ys are lists of x's and y's and z is a number between 0 and 1
plots = []
for(xs,ys,z) in mydata:
pl = ax.plot(xs,ys,color = mycmap(z))
plots.append(pl)
fig.colorbar(plots)
plt.show()
But this won't work according to the Matplotlib reference because a list of plots is not a "mappable", whatever this means.
I've created an alternative plot function using LineCollection:
def myplot(ax,xs,ys,zs, cmap):
plot = lc([zip(x,y) for (x,y) in zip(xs,ys)], cmap = cmap)
plot.set_array(array(zs))
x0,x1 = amin(xs),amax(xs)
y0,y1 = amin(ys),amax(ys)
ax.add_collection(plot)
ax.set_xlim(x0,x1)
ax.set_ylim(y0,y1)
return plot
xs and ys are lists of lists of x and y coordinates and zs is a list of the different conditions to colorize each line. It feels a bit like a cludge though... I thought that there would be a more neat way to do this. I like the flexibility of the plt.plot() function.
(I know this is an old question but...) Colorbars require a matplotlib.cm.ScalarMappable, plt.plot produces lines which are not scalar mappable, therefore, in order to make a colorbar, we are going to need to make a scalar mappable.
Ok. So the constructor of a ScalarMappable takes a cmap and a norm instance. (norms scale data to the range 0-1, cmaps you have already worked with and take a number between 0-1 and returns a color). So in your case:
import matplotlib.pyplot as plt
sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.normalize(min=0, max=1))
plt.colorbar(sm)
Because your data is in the range 0-1 already, you can simplify the sm creation to:
sm = plt.cm.ScalarMappable(cmap=my_cmap)
EDIT: For matplotlib v1.2 or greater the code becomes:
import matplotlib.pyplot as plt
sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.normalize(vmin=0, vmax=1))
# fake up the array of the scalar mappable. Urgh...
sm._A = []
plt.colorbar(sm)
EDIT: For matplotlib v1.3 or greater the code becomes:
import matplotlib.pyplot as plt
sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.Normalize(vmin=0, vmax=1))
# fake up the array of the scalar mappable. Urgh...
sm._A = []
plt.colorbar(sm)
EDIT: For matplotlib v3.1 or greater simplifies to:
import matplotlib.pyplot as plt
sm = plt.cm.ScalarMappable(cmap=my_cmap, norm=plt.Normalize(vmin=0, vmax=1))
plt.colorbar(sm)
Here's one way to do it while still using plt.plot(). Basically, you make a throw-away plot and get the colorbar from there.
import matplotlib as mpl
import matplotlib.pyplot as plt
min, max = (-40, 30)
step = 10
# Setting up a colormap that's a simple transtion
mymap = mpl.colors.LinearSegmentedColormap.from_list('mycolors',['blue','red'])
# Using contourf to provide my colorbar info, then clearing the figure
Z = [[0,0],[0,0]]
levels = range(min,max+step,step)
CS3 = plt.contourf(Z, levels, cmap=mymap)
plt.clf()
# Plotting what I actually want
X=[[1,2],[1,2],[1,2],[1,2]]
Y=[[1,2],[1,3],[1,4],[1,5]]
Z=[-40,-20,0,30]
for x,y,z in zip(X,Y,Z):
# setting rgb color based on z normalized to my range
r = (float(z)-min)/(max-min)
g = 0
b = 1-r
plt.plot(x,y,color=(r,g,b))
plt.colorbar(CS3) # using the colorbar info I got from contourf
plt.show()
It's a little wasteful, but convenient. It's also not very wasteful if you make multiple plots as you can call plt.colorbar() without regenerating the info for it.
Here is a slightly simplied example inspired by the top answer given by Boris and Hooked (Thanks for the great idea!):
1. Discrete colorbar
Discrete colorbar is more involved, because colormap generated by mpl.cm.get_cmap() is not a mappable image needed as a colorbar() argument. A dummie mappable needs to generated as shown below:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
n_lines = 5
x = np.linspace(0, 10, 100)
y = np.sin(x[:, None] + np.pi * np.linspace(0, 1, n_lines))
c = np.arange(1, n_lines + 1)
cmap = mpl.cm.get_cmap('jet', n_lines)
fig, ax = plt.subplots(dpi=100)
# Make dummie mappable
dummie_cax = ax.scatter(c, c, c=c, cmap=cmap)
# Clear axis
ax.cla()
for i, yi in enumerate(y.T):
ax.plot(x, yi, c=cmap(i))
fig.colorbar(dummie_cax, ticks=c)
plt.show();
This will produce a plot with a discrete colorbar:
2. Continuous colorbar
Continuous colorbar is less involved, as mpl.cm.ScalarMappable() allows us to obtain an "image" for colorbar().
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
n_lines = 5
x = np.linspace(0, 10, 100)
y = np.sin(x[:, None] + np.pi * np.linspace(0, 1, n_lines))
c = np.arange(1, n_lines + 1)
norm = mpl.colors.Normalize(vmin=c.min(), vmax=c.max())
cmap = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.jet)
cmap.set_array([])
fig, ax = plt.subplots(dpi=100)
for i, yi in enumerate(y.T):
ax.plot(x, yi, c=cmap.to_rgba(i + 1))
fig.colorbar(cmap, ticks=c)
plt.show();
This will produce a plot with a continuous colorbar:
[Side note] In this example, I personally don't know why cmap.set_array([]) is necessary (otherwise we'd get error messages). If someone understand the principles under the hood, please comment :)
As other answers here do try to use dummy plots, which is not really good style, here is a generic code for a
Discrete colorbar
A discrete colorbar is produced in the same way a continuous colorbar is created, just with a different Normalization. In this case a BoundaryNorm should be used.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
n_lines = 5
x = np.linspace(0, 10, 100)
y = np.sin(x[:, None] + np.pi * np.linspace(0, 1, n_lines))
c = np.arange(1., n_lines + 1)
cmap = plt.get_cmap("jet", len(c))
norm = matplotlib.colors.BoundaryNorm(np.arange(len(c)+1)+0.5,len(c))
sm = plt.cm.ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([]) # this line may be ommitted for matplotlib >= 3.1
fig, ax = plt.subplots(dpi=100)
for i, yi in enumerate(y.T):
ax.plot(x, yi, c=cmap(i))
fig.colorbar(sm, ticks=c)
plt.show()

Categories