Is it possible to draw a broken axis graph with seaborn? - python

I need to draw a broken x axis graph (e.g. the graph below) with existing data, my question is whether it's possible to use seaborn APIs to do that?

Not as pretty as I'd like but works.
%matplotlib inline # If you are running this in a Jupyter Notebook.
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 20, 500)
y = np.sin(x)
f, (ax1, ax2) = plt.subplots(ncols=2, nrows=1, sharey=True)
ax = sns.tsplot(time=x, data=y, ax=ax1)
ax = sns.tsplot(time=x, data=y, ax=ax2)
ax1.set_xlim(0, 6.5)
ax2.set_xlim(13.5, 20)

A tighter version (also replaced the deprecated tsplot). Can control the distance between the plots by the wspace parameter in the plt.subplots_adjust(wspace=0, hspace=0) line.
%matplotlib inline
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 20, 500)
y = np.sin(x)
f, (ax1, ax2) = plt.subplots(ncols=2, nrows=1, sharey=True)
ax = sns.lineplot(x=x, y=y, ax=ax1)
ax = sns.lineplot(x=x, y=y, ax=ax2)
ax1.set_xlim(0, 6.5)
ax2.set_xlim(13.5, 20)
plt.subplots_adjust(wspace=0, hspace=0)

Related

Aligning x-axis with sharex using subplots and colorbar with matplotlib

I'm trying to create a set of subplots with a shared x axis using pyplot. This is all fine and dandy when the graphs are simple and all the x-axes align fine. However when I include a subplot that includes a colorbar, this compresses the width of that particular subplot to include the colorbar, resulting in the subplots no longer sharing the x-axis.
I've searched the web with no success with this. I've tried several different methods, but the simplest example I include below. I plot the exact same data in each subplot, but plot one with a colorbar. You can see the data no longer align along the x-axis.
Thanks in advance for your help!
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
import pandas as pd
x = np.linspace(0, 10, num=100)
y = x ** 2 + 10 * np.random.randn(100)
f, (ax1, ax2) = plt.subplots(2,1,sharex=True,figsize=(8,12))
im1 = ax1.scatter(x, y, c=y, cmap='magma')
divider = make_axes_locatable(ax1)
cax = divider.append_axes("right", size="5%", pad=.05)
plt.colorbar(im1, cax=cax)
im2 = ax2.plot(x, y,'.')
plt.show()
Suggest using constrained_layout=True: https://matplotlib.org/stable/tutorials/intermediate/constrainedlayout_guide.html
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, num=100)
y = x ** 2 + 10 * np.random.randn(100)
f, (ax1, ax2) = plt.subplots(2,1,sharex=True,figsize=(8,12),
constrained_layout=True)
im1 = ax1.scatter(x, y, c=y, cmap='magma')
f.colorbar(im1, ax=ax1)
im2 = ax2.plot(x, y,'.')
This is one hacky way to do it.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
import pandas as pd
x = np.linspace(0, 10, num=100)
y = x ** 2 + 10 * np.random.randn(100)
f, (ax1, ax2) = plt.subplots(2,1,sharex=True,figsize=(8,12))
im1 = ax1.scatter(x, y, c=y, cmap='magma')
divider = make_axes_locatable(ax1)
cax = divider.append_axes("right", size="5%", pad=.05)
plt.colorbar(im1, cax=cax)
im2 = ax2.plot(x, y,'.')
divider2 = make_axes_locatable(ax2)
cax2 = divider2.append_axes("right", size="5%", pad=.05)
cax2.remove()
plt.show()
results in
You can account for the needed with of the colorbar already when you create the subplots. Instead of using the divider, generate four subplots with different widths using gridspec_kw. You can then delete the unneeded cax for the second subplot:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, num=100)
y = x ** 2 + 10 * np.random.randn(100)
##creating four subplots with unequally divided widths:
f, axes = plt.subplots(
2,2, sharex='col', figsize=(8,12),
gridspec_kw = {'width_ratios' : (10,1)},
)
ax1,ax2 = axes[:,0]
##remove unneeded Axes instance:
axes[1,1].remove()
im1 = ax1.scatter(x, y, c=y, cmap='magma')
plt.colorbar(im1, cax=axes[0,1])
im2 = ax2.plot(x, y,'.')
f.savefig('sharex_colorbar.png')
The result looks like this:
As an alternative to deleting the unneded subplot instances, you can also first generate the gridspec explicitly and generate only the needed subplots. This might be more suitable if you have many plots:
from matplotlib.gridspec import GridSpec
gs = GridSpec(nrows=2, ncols=2, width_ratios = (10,1))
f = plt.figure(figsize=(8,12))
ax1 = f.add_subplot(gs[0,0])
ax2 = f.add_subplot(gs[1,0],sharex=ax1)
cax = f.add_subplot(gs[0,1])
im1 = ax1.scatter(x, y, c=y, cmap='magma')
plt.colorbar(im1, cax=cax)

plot two seaborn heatmap graphs side by side

I'm attempting to plot two seaborn graphs side by side as other graphs (successfully) have done in previous questions, only difference I can see is that heatmaps seems to be throwing an issue. The code to produce the error is:
import numpy as np; np.random.seed(0)
import seaborn as sns
uniform_data = np.random.rand(10, 12)
uniform_data2 = np.random.rand(100, 120)
fig, ax =plt.subplots(1,2)
ax = sns.heatmap(uniform_data)
ax = sns.heatmap(uniform_data2)
Which produces the below
You just have to use the ax parameter
fig, (ax1, ax2) = plt.subplots(1,2)
sns.heatmap(uniform_data, ax=ax1)
sns.heatmap(uniform_data2, ax=ax2)
plt.show()
You have created an array of axes using fig, ax = plt.subplots(1,2). You are then overwriting that array with the result of sns.heatmap. Instead, you want to specify which axes you want to plot to using the ax= argument of sns.heatmap:
import numpy as np; np.random.seed(0)
import seaborn as sns
uniform_data = np.random.rand(10, 12)
uniform_data2 = np.random.rand(100, 120)
fig, ax =plt.subplots(1,2)
sns.heatmap(uniform_data, ax=ax[0])
sns.heatmap(uniform_data2, ax=ax[1])
plt.show()
Which gives:

Python subplots not working properly

I am trying to plot three different graphs in three sub-plots within a single figure. Also I want the first figure to be of double width than the other two. Accordingly I have used
gs = gridspec.GridSpec(2, 2, width_ratios=[2,1], height_ratios=[1,1])
But the output has all the figures plotted on ax3.
My code is given here
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import matplotlib.gridspec as gridspec
gs = gridspec.GridSpec(2, 2, width_ratios=[2,1], height_ratios=[1,1])
ax1=plt.subplot(gs[:,:-1])
ax2=plt.subplot(gs[:-1,-1])
ax3=plt.subplot(gs[-1,-1])
# ax 1
X=np.linspace(0,10,100)
Y=np.sin(X)
ax1 = plt.gca()
ax1.scatter(X, Y)
ax1.axis("tight")
ax1.set_title('ax1')
ax1.set_xlim([0,10])
ax1.set_ylim([-1,1])
plt.xticks([])
plt.yticks([])
# ax 2
ax2 = plt.gca()
vel=np.random.rand(1000)
n, bins, patches = plt.hist(vel, 10, normed=True, histtype='stepfilled', facecolor='green', alpha=1.0)
ax2.set_title('Velocity Distribution')
ax2.axis("tight")
plt.xticks([0,0.05,0.10])
plt.yticks([0,10,20])
# ax 3
Z=np.exp(X)
ax3.plot(X,Z,'red',lw=5)
plt.show()
Can somebody tell me how I can rectify this. Thank you in advance.
Fixed several lines. Please compare with your code.
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import matplotlib.gridspec as gridspec
gs = gridspec.GridSpec(2, 2, width_ratios=[2,1], height_ratios=[1,1])
ax1=plt.subplot(gs[:,:-1])
ax2=plt.subplot(gs[:-1,-1])
ax3=plt.subplot(gs[-1,-1])
# ax 1
X=np.linspace(0,10,100)
Y=np.sin(X)
#ax1 = plt.gca()
ax1.scatter(X, Y)
ax1.axis("tight")
ax1.set_title('ax1')
ax1.set_xlim([0,10])
ax1.set_ylim([-1,1])
# You can use ax1.set_xticks() and ax1.set_xticklabels() instead.
ax1.set_xticks([])
ax1.set_yticks([])
#plt.xticks([])
#plt.yticks([])
# ax 2
#ax2 = plt.gca()
vel=np.random.rand(1000)
n, bins, patches = ax2.hist(vel, 10, normed=True, histtype='stepfilled', facecolor='green', alpha=1.0)
ax2.set_title('Velocity Distribution')
ax2.axis("tight")
# You can use ax2.set_xticks() and ax2.set_xticklabels() instead.
ax2.set_xticks([0,0.5,1])
ax2.set_yticks([0,1,2])
#plt.xticks([0,0.05,0.10])
#plt.yticks([0,10,20])
# ax 3
Z=np.exp(X)
ax3.plot(X, Z,'red', lw=5)
# You can use ax3.set_xticks() and ax3.set_xticklabels() instead.
ax3.set_xticks([0, 5, 10])
ax3.set_yticks([0, 10000, 20000])
ax3.set_yticklabels(['0', '10K', '20K'])
plt.show()

Same size of axes if one of them has set_aspectratio to "equal"

Imagine the following simple situation:
import numpy as np
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.plot(np.arange(10))
ax1.set_aspect("equal")
ax2.plot(np.arange(10), np.arange(0, 1, .1))
plt.show()
What would be the best/easiest solution so that ax2 has the same width/height as ax1, no matter what the aspectratio of ax2 is?
For your specific case, you can set the aspect ratio of ax2 to 10, such as bellow:
import numpy as np
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.plot(np.arange(10))
ax1.set_aspect("equal")
ax2.plot(np.arange(10), np.arange(0, 1, .1))
# Determining the ranges
x1,x2 = ax2.get_xlim()
y1,y2 = ax2.get_ylim()
xRange = x2-x1
yRange = y2-y1
ax2.set_aspect(xRange/yRange)
plt.show()
Cheers

Add minor gridlines to matplotlib plot using seaborn

I'm a fan of the Seaborn package for making nice-looking plots using Matplotlib. But I can't seem to figure out how to show minor gridlines in my plots.
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sbn
x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(x)
fig, ax = plt.subplots(1, 1)
ax.scatter(x, y)
ax.grid(b=True, which='major')
ax.grid(b=True, which='minor')
gives:
Any thoughts here? Also any thoughts on how to adjust the style of the Seaborn gridlines that do show up...in particular, I'd love to make them narrower.
Wound up combining CT Zhu's answer with tcaswell's hint:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sbn
x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(x)
fig, ax = plt.subplots(1, 1)
ax.scatter(x, y)
ax.get_xaxis().set_minor_locator(mpl.ticker.AutoMinorLocator())
ax.get_yaxis().set_minor_locator(mpl.ticker.AutoMinorLocator())
ax.grid(b=True, which='major', color='w', linewidth=1.0)
ax.grid(b=True, which='minor', color='w', linewidth=0.5)
That's because the minor ticks are not yet defined, so we need to add for example:
ax.set_xticks(np.arange(0,8)-0.5, minor=True)
ax.set_yticks([-1.25, -0.75, -0.25,0.24,0.75,1.25], minor=True)

Categories