Matplotlib Colorbar scientific notation offset - python

When plotting a colorbar, the top label (I guess this would be called the offset) is mis-centred. This didn't use to happen, I have examples of old code where it was centred above the colorbar, but I have no clue what has changed.
Example:
import numpy as np
import matplotlib.pyplot as plt
z = np.random.random((10,10))
fig, ax = plt.subplots()
im = ax.imshow(z)
cb = fig.colorbar(im)
cb.formatter.set_powerlimits((0, 0))
cb.update_ticks()
plt.show()
Gives this:
As an example of how it used to look (taken from one of my old papers, so
different data etc.)
Using the most recent anaconda python 2.7, on MacOSX, mpl version 1.5.0
Edit: I should also note, tight_layout() does not improve this either, though it is missing from the working example.

You can simply use set_offset_position for the y-axis of the colorbar. Compare:
fig, ax = plt.subplots()
im = ax.imshow(np.random.random((10,10)))
cb = fig.colorbar(im)
cb.formatter.set_powerlimits((0, 0))
cb.ax.yaxis.set_offset_position('right')
cb.update_ticks()
plt.show()
versus
fig, ax = plt.subplots()
im = ax.imshow(np.random.random((10,10)))
cb = fig.colorbar(im)
cb.formatter.set_powerlimits((0, 0))
cb.ax.yaxis.set_offset_position('left')
cb.update_ticks()
plt.show()
All in all, it simply looks like the default has changed from right to left.

Using your above code and matplotlib version 1.4.3 I get the following plot
So this may be a version issue. One possible work around could be to use cb.ax.text()
# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
z = np.random.random((10,10))
fig, ax = plt.subplots()
im = ax.imshow(z)
cb = fig.colorbar(im)
cb.ax.text(-0.25, 1, r'$\times$10$^{-1}$', va='bottom', ha='left')
plt.show()
This way you have more control over the centring. The above code gives me the following plot
Note that I use an r at the start of the string so that $\times$ produces the correct symbol.

Related

Generate more plots separate in figure in one script in python

First of all, I apologies if this question was already asked and answered, I haven't found anything really specific about this so if you did, please share and I will delete this post.
What I would like to do is simply generate more separate plots after one another in separate figure in python, because I have an exercise sheet and the a) is to plot a poisson distribution and the b) is to plot a binomial distribution and so ever with c) and d), and I would like that the plots are gathered together in the same script but in separate figure.
I tried as simple as create a sin(x) and a cos(x) plot after one another but it didn't work, the sin and cos were displaying in the same plot.. My code was:
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = plt.plot(np.sin(x))
ax2 = plt.plot(np.cos(x))
ax1.set_xlabel('Time (s)')
ax1.set_title('sin')
ax1.legend()
ax2.set_xlabel('Time (s)')
ax2.set_title('cos')
ax2.legend()
plt.show()
Could anyone help me ?
How about this?
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212, sharex=ax1)
ax1.plot(np.sin(x))
ax2.plot(np.cos(x))
plt.show()
I suggest you should read a simple tutorial about subplots.
EDIT:
To create separate figures:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 100)
plt.figure()
plt.plot(np.sin(x))
plt.figure()
plt.plot(np.cos(x))
plt.show()

Twinx/Secondary-y: Do not start with first color

I have a color scheme that comes from
plt.style.use('ggplot')
so I don't want to manually pick colors, or pick them from a color cycler. However, when I have a secondary axis:
fig, ax = plt.subplots()
ax2 = ax.twinx()
ax.plot(np.array([1, 2]))
ax2.plot(np.array([3, 4]))
It will plot both lines in the same color. How do I tell ax2 that there is already n=1 lines drawn on that plot, such that it starts with the n+1th color?
I think manually calling next() on the prop_cycler as suggested in the other answer is a bit error prone because it's easy to forget. In order to automate the process, you can make both axes share the same cycler:
ax2._get_lines.prop_cycler = ax1._get_lines.prop_cycler
Yes, it is still an ugly hack because it depends on the internal implementation details instead of a defined interface. But in the absence of an official feature, this is probably the most robust solution. As you can see, you can add plots on the two axes in any order, without manual intervention.
Complete code:
import matplotlib.pyplot as plt
import numpy as np
plt.style.use('ggplot')
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax2._get_lines.prop_cycler = ax1._get_lines.prop_cycler
ax1.plot(np.array([1, 2, 3]))
ax2.plot(np.array([3, 5, 4]))
ax1.plot(np.array([0, 1, 3]))
ax2.plot(np.array([2, 4, 1]))
plt.show()
There is unfortunately no "recommended" way to manipulate the cycler state. See some in-depth discussion at Get matplotlib color cycle state.
You may however access the current cycler and advance it manually.
next(ax2._get_lines.prop_cycler)
Complete code:
import matplotlib.pyplot as plt
import numpy as np
plt.style.use('ggplot')
fig, ax = plt.subplots()
ax2 = ax.twinx()
ax.plot(np.array([1, 2, 3]))
next(ax2._get_lines.prop_cycler)
ax2.plot(np.array([3, 5,4]))
plt.show()
You can plot an empty list to ax2 before plotting your actual data. This causes the first colour in the cycle to be used to draw a line that doesn't really exist, moving on to the second colour for the real data.
plt.style.use("ggplot")
fig, ax = plt.subplots()
ax2 = ax.twinx()
ax.plot(np.array([1, 2]))
ax2.plot([]) # Plotting nothing.
ax2.plot(np.array([2, 1]))

Flexible way to add subplots to figure and one colorbar to figure

I have tried and tried to search for a solution, but I can't seem to make it work, so here is my problem:
I am trying to make a script, where I can set a size (i.e. number of subplots in a figure) of the figure. It should always be a N*2 grid structure (with equal dimensions) for the subplots in the figure. In the grids, I want to plot some lines (with a specific color) and add a horizontal colorbar at the bottom of the figure. I have tried following the solution to the problem, mentioned in Matplotlib 2 Subplots, 1 Colorbar. Here is my solution:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import matplotlib.colors as colors
import matplotlib.cm as cmx
import random
lines = np.random.rand(100, 10)
fig, ax = plt.subplots(nrows=2,ncols=2, sharex=True)
ranks = np.linspace(0,len(lines[0,:]), len(lines[0,:]))
norm = matplotlib.colors.Normalize(
vmin=np.min(ranks),
vmax=np.max(ranks))
c_m = matplotlib.cm.cool
s_m = matplotlib.cm.ScalarMappable(cmap=c_m, norm=norm)
s_m.set_array([])
for line, rank in zip(xrange(0,len(lines[0,:])), ranks):
try:
no = random.randint(0,1)
no2 =random.randint(0,1)
im =ax[no,no2].plot(lines[:, line], c=s_m.to_rgba(rank))
except IOError as error:
print error
fig.subplots_adjust(bottom=0.2)
fig.colorbar(s_m, orientation='horizontal')
plt.show()
So my question is: How do I make a gridbased subplot (for line- and scatterplots), where I can add one colorbar horizontally at the bottom to stretch across both subplots in the bottom?
You should provide the ax argument to the colorbar function,
fig.colorbar(s_m, ax = ax.flatten(), orientation='horizontal')
This would then produce
So I figured it out and both Thomas Kühn and and ImportanceOfBeingErnest helped me see the errors:
First off, I changed the question to be replicable and with a mappable instead of ax[1,1]. Once doing that, I could see how it was actually directly transferrable to the question I had linked to, in my question. Here is my result:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import matplotlib.colors as colors
import matplotlib.cm as cmx
import os
import random
fnames = np.random.rand(100, 10)
fig, ax = plt.subplots(nrows=2,ncols=2, sharex=True, figsize=(4,4))
parameters = np.linspace(0,len(fnames[0,:]), len(fnames[0,:]))
norm = matplotlib.colors.Normalize(
vmin=np.min(parameters),
vmax=np.max(parameters))
c_m = matplotlib.cm.cool
s_m = matplotlib.cm.ScalarMappable(cmap=c_m, norm=norm)
s_m.set_array([])
for filename, parameter in zip(xrange(0,len(fnames[0,:])), parameters):
try:
no = random.randint(0,1)
no2 =random.randint(0,1)
ax[no,no2].plot(fnames[:, filename], c=s_m.to_rgba(parameter))
except IOError as error:
print error
for ax1 in ax.flatten():
ax1.set_xlabel('Y')
ax1.set_ylabel('X')
plt.title('Title')
fig.subplots_adjust(bottom=0.2)
cbar_ax = fig.add_axes([0.13, 0.08, 0.74, 0.03])
cbar = fig.colorbar(s_m, cax=cbar_ax, orientation='horizontal')
cbar.set_label('Focus: ')
plt.show()
Which gave this plot. Thanks for the tips. Would you recommend changing the grid structure from plt.subplots, to AxesGrid, found in mpl_toolkits.axes_grid1?

matplotlib plot points look fuzzy in Python, sharp in IPython

I'm really confused here; the same code in Python and in IPython Notebook produces two different PNG files with savefig:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(5,4))
ax = fig.add_subplot(1,1,1)
abc = np.random.uniform(size=(50000,3))
print abc.shape
x = (2*abc[:,0]-abc[:,1]-abc[:,2])/3.0
y = (abc[:,1]-abc[:,2])/np.sqrt(3)
ax.plot(x,y,'.',markersize=0.25)
ax.set_aspect('equal')
ax.set_xlabel('x')
ax.set_ylabel('y')
with open('/tmp/screenshots/foo.png','wb') as f:
fig.savefig(f, format='png')
IPython Notebook:
Python:
It's the same PC with the same version of Python in both cases. Is there a way to get the image formatting in IPython using both methods? The Python version produces fuzzy dots and looks poor.
Argh -- I figured it out, the dpi parameter gets chosen somehow differently in the two cases, and if I force it to dpi=72 then it looks nice:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(5,4))
ax = fig.add_subplot(1,1,1)
abc = np.random.uniform(size=(50000,3))
print abc.shape
x = (2*abc[:,0]-abc[:,1]-abc[:,2])/3.0
y = (abc[:,1]-abc[:,2])/np.sqrt(3)
ax.plot(x,y,'.',markersize=0.25)
ax.set_aspect('equal')
ax.set_xlabel('x')
ax.set_ylabel('y')
with open('/tmp/screenshots/foo.png','wb') as f:
fig.savefig(f, format='png', dpi=72)

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