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:
Related
I have the following script for generating a figure with two subplots: one line plot, and one bar plot.
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
plt.close('all')
np.random.seed(42)
n = 1000
idx = pd.date_range(end='2020-02-27', periods=n)
df = pd.Series(np.random.randint(-5, 5, n),
index=idx)
curve = df.cumsum()
bars = df.resample('M').sum()
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
curve.plot(ax=ax1)
bars.plot(kind='bar', ax=ax2)
fig.set_tight_layout(True)
I would like to share the x axis between the two subplots, however the command ax2 = fig.add_subplot(212, sharex=ax1) will result in an empty graph for the line plot like the following figure.
Here is my version based on Matplotlib (without pandas api for plotting), may be it would be helpful.
I explicitly set the width of bars.
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
%matplotlib inline
plt.close('all')
np.random.seed(42)
n = 1000
idx = pd.date_range(end='2020-02-27', periods=n)
df = pd.Series(np.random.randint(-5, 5, n), index=idx)
curve = df.cumsum()
bars = df.resample('M').sum()
#fig = plt.figure()
#ax1 = fig.add_subplot(211)
#ax2 = fig.add_subplot(212)
#curve.plot(ax=ax1)
#bars.plot(kind='bar', ax=ax2)
fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, gridspec_kw={'hspace': 0})
ax1.plot(curve.index, curve.values)
ax2.bar(bars.index, bars.values, width = (bars.index[0] - bars.index[1])/2)
fig.set_tight_layout(True)
_ = plt.xticks(bars.index, bars.index, rotation=90)
I'm trying to put side-by-side numpy array displayed as image and seaborn distplot of the same array. I've came up with the following function:
def visualize(arr):
f, (ax1, ax2) = plt.subplots(1, 2, gridspec_kw = {'width_ratios': [1, 3]})
ax1.imshow(arr)
flat = arr.flatten()
x = flat[~np.isnan(flat)]
sns.distplot(x, ax=ax2)
plt.show()
which produces:
As you can see, the image has smaller height than the plot. How can I modify my function in order to have the same height for the plot and the imshow?
I want the following placement of the image and the plot:
There are just so many ways to tackle this. All of the following will give more or less the same image
A. Reduce the available space
You may reduce the available space such that both plots are constrained to the same vertical margins. This can be done by
reducing figure height
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6,2.3), ...)
using subplots_adjust to limit the margins
fig.subplots_adjust(top=0.7, bottom=0.3)
B. Use InsetPosition
You may use mpl_toolkits.axes_grid1.inset_locator.InsetPosition to adjust the coordinates of the second axes to match those of the first one.
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import InsetPosition
def visualize(arr):
fig, (ax1, ax2) = plt.subplots(1, 2,
gridspec_kw = {'width_ratios': [1, 3]})
ax1.imshow(arr)
flat = arr.flatten()
x = flat[~np.isnan(flat)]
sns.distplot(x, ax=ax2)
ip = InsetPosition(ax1, [1.5,0,3,1])
ax2.set_axes_locator(ip)
plt.show()
arr = np.random.randn(200,120)
visualize(arr)
C. Use an axes divider
You may create only the axes for the image and then use mpl_toolkits.axes_grid1.make_axes_locatable to create a new axes next to it.
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
def visualize(arr):
fig, ax = plt.subplots()
divider = make_axes_locatable(ax)
ax2 = divider.new_horizontal(size="300%", pad=0.5)
fig.add_axes(ax2)
ax.imshow(arr)
flat = arr.flatten()
x = flat[~np.isnan(flat)]
sns.distplot(x, ax=ax2)
plt.show()
arr = np.random.randn(200,120)
visualize(arr)
D. calculate the desired aspect ratio
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
def visualize(arr):
gkw = {'width_ratios':[1, 3] }
fig, (ax1, ax2) = plt.subplots(1, 2, gridspec_kw = gkw )
ax1.imshow(arr)
flat = arr.flatten()
x = flat[~np.isnan(flat)]
sns.distplot(x, ax=ax2)
ya = np.diff(np.array(ax2.get_ylim()))[0]
xa = np.diff(np.array(ax2.get_xlim()))[0]
wa = gkw['width_ratios'][0]/float(gkw['width_ratios'][1])
ia = arr.shape[0]/float(arr.shape[1])
ax2.set_aspect(float(wa*ia/(ya/xa)))
plt.show()
arr = np.random.randn(200,120)
visualize(arr)
E. Dynamically copy positions
You may get the position of the left plot and copy its y-coordinates to the right subplot's position. This is a nice add-on to existing code. The drawback is necessary because subsequent changes to the figure size require to recalculate the positions.
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
def visualize(arr):
gkw = {'width_ratios':[1, 3] }
fig, (ax1, ax2) = plt.subplots(1, 2, gridspec_kw = gkw )
ax1.imshow(arr)
flat = arr.flatten()
x = flat[~np.isnan(flat)]
sns.distplot(x, ax=ax2)
def on_resize(evt=None):
ax1.apply_aspect()
bb1 = ax1.get_position()
bb2 = ax2.get_position()
bb2.y0 = bb1.y0; bb2.y1 = bb1.y1
ax2.set_position(bb2)
fig.canvas.mpl_connect("resize_event", on_resize)
on_resize()
plt.show()
arr = np.random.randn(200,120)
visualize(arr)
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)
I'm trying to share the x-axis and y-axis of my sumplots, I've tried using the sharey and sharex several different ways but haven't gotten the correct result.
ax0 = plt.subplot(4,1,1)
for i in range(4):
plt.subplot(4,1,i+1,sharex = ax0)
plt.plot(wavelength[i],flux)
plt.xlim([-1000,1000])
plt.ylim([0,1.5])
plt.subplots_adjust(wspace=0, hspace=0)
plt.show()
If I understood you correctly, want to have four stacked plots, sharing the x-axis and the y-axis. This you can do with plt.subplots and the keywords sharex=True and sharey=True. See example below:
import numpy as np
import matplotlib.pyplot as plt
fig, axlist = plt.subplots(4, 1, sharex=True, sharey=True)
for ax in axlist:
ax.plot(np.random.random(100))
plt.show()
I would like to create a tsplot, where the x and the y axis are the same length. in other words the aspect ratio of the graph should be 1.
this dos not work:
fig, ax = plt.subplots()
fig.set_size_inches(2, 2)
sns.tsplot(data=df, condition=' ', time='time', value='value', unit=' ', ax=ax)
You could change the aspect ratio of your plots by controlling the aspect
parameter of a matplotlib object as shown:
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
np.random.seed(22)
sns.set_style("whitegrid")
gammas = sns.load_dataset("gammas")
fig = plt.figure()
ax = fig.add_subplot(111, aspect=2) #Use 'equal' to have the same scaling for x and y axes
sns.tsplot(time="timepoint", value="BOLD signal", unit="subject",
condition="ROI", data=gammas, ax=ax)
plt.tight_layout()
plt.show()
A little more direct is ax.set_box_aspect(1)1