I generated a clustermap using seaborn.clustermap.
I'd like to draw/plot an horizontal line on top of the heatmap like in this figure
I simply tried to use matplotlib as:
plt.plot([x1, x2], [y1, y2], 'k-', lw = 10)
but the line is not displayed.
The object returned by seaborn.clustermap doesn't have any properties like in this similar question.
How can I plot the line?
Here is the code that generates a "random" clustermap similar to the one I posted:
import numpy as np
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
import random
data = np.random.random((50, 50))
df = pd.DataFrame(data)
row_colors = ["b" if random.random() > 0.2 else "r" for i in range (0,50)]
cmap = sns.diverging_palette(133, 10, n=7, as_cmap=True)
result = sns.clustermap(df, row_colors=row_colors, col_cluster = False, cmap=cmap, linewidths = 0)
plt.plot([5, 30], [5, 5], 'k-', lw = 10)
plt.show()
The axes object that you want is hiding in ClusterGrid.ax_heatmap. This code finds this axis and simply uses ax.plot() to draw the line. You could also use ax.axhline().
import numpy as np
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
import random
data = np.random.random((50, 50))
df = pd.DataFrame(data)
row_colors = ["b" if random.random() > 0.2 else "r" for i in range (0,50)]
cmap = sns.diverging_palette(133, 10, n=7, as_cmap=True)
result = sns.clustermap(df, row_colors=row_colors, col_cluster = False, cmap=cmap, linewidths = 0)
print dir(result) # here is where you see that the ClusterGrid has several axes objects hiding in it
ax = result.ax_heatmap # this is the important part
ax.plot([5, 30], [5, 5], 'k-', lw = 10)
plt.show()
Related
I am new to visualization in python. I am trying to plot the same dataset on the left but by using colors as gradient and gridlines to make it understandable. But I'm stuck and I don't know what I did, I just used the reference codes I got from other similar questions. Can someone help out?
import random
import matplotlib
import matplotlib.pyplot as plt
import tkinter as tk
from matplotlib.widgets import Slider
from matplotlib import colors
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib import style
import numpy as np
style.use('ggplot')
matplotlib.use('TkAgg')
def update(val):
pos = s_time.val
ax.axis([pos, pos+10, 20, 40])
fig.canvas.draw_idle()
def plot():
canvas = FigureCanvasTkAgg(fig,root)
canvas.get_tk_widget().pack(side=tk.TOP, fill = tk.BOTH, expand =1)
fig.subplots_adjust(bottom=0.25)
y_values = [random.randrange(41) for _ in range(40)]
x_values = [i for i in range(40)]
ax.axis([0, 9, 20, 40])
ax.plot(x_values, y_values)
#cmap = colors.ListedColormap(['red', 'blue','green'])
#bounds = [0,10,20,30]
#norm = colors.BoundaryNorm(bounds, cmap.N)
#ax1.imshow(ax, cmap=cmap, norm=norm)
im0 = ax1.pcolormesh([x_values,y_values], vmin=0, vmax=1, cmap="RdBu")
im = fig.colorbar(im0,cax=ax1)
ax1.grid(which='major', axis='both', linestyle='-', color='white', linewidth=0.5)
#ax1.set_yticks(np.arange(0, 40, 2.5))
ax_time = fig.add_axes([0.12, 0.1, 0.78, 0.03])
return ax_time
root = tk.Tk()
fig = plt.Figure(figsize = (10,10),dpi = 150)
ax=fig.add_subplot(121)
ax1=fig.add_subplot(122)
s_time = Slider(plot(), 'Time', 0, 30, valinit=0)
s_time.on_changed(update)
root.mainloop()
Disclaimer: Not sure if I understood the question correctly. Maybe you could provide links to the reference questions.
If you want to add a color gradient to a lineplot in matplotlib, to my knowledge the best bet is to use ax.scatter. A similar question was asked here:
Matplotlib: different color for every point of line plot
To mimic the appearance of a lineplot you need to interpolate your data linearly before passing it to the scatter function. The c keyword argument can be used to assign a color-value to each data point and the cmap argument determines the actual mapping from color-value to color.
Here is a minimally working example:
import matplotlib.pyplot as plt
import numpy as np
f, ax = plt.subplots(1, 1)
y_values = np.random.randint(0, 41, size=40)
x_values = np.arange(0, 40, 1)
x_interp = np.arange(0, 40, 0.01)
y_interp = np.interp(x_interp, x_values, y_values)
ax.grid(alpha=0.5)
artist = ax.scatter(x_interp, y_interp, c=y_interp, cmap='seismic', lw=0)
f.colorbar(artist, ax=ax)
Which yields the following plot
EDIT:
After clarification I interpret the question as:
"How do I add a background to a lineplot, that shows a color gradient corresponding to the values on the y-axis".
My suggestion is the following:
import matplotlib.pyplot as plt
import numpy as np
f, a = plt.subplots(1, 1)
value_range = (vmin, vmax) = (0, 40)
x_range = (xmin, xmax) = (0, 60)
X, Y = np.meshgrid(range(xmin, xmax, 1), range(vmin, vmax, 1))
y_data = np.random.randint(vmin, vmax, size=xmax-xmin)
x_data = np.arange(xmin, xmax, 1)
a.pcolormesh(Y, cmap="seismic", alpha=0.5, edgecolors='gray')
a.plot(x_data, y_data, "k-")
Which then yields the following plot
Consider the following:
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
y = np.array([1, 4, 3, 2, 7, 11])
colors = cm.hsv(y / float(max(y)))
plot = plt.scatter(y, y, c = y, cmap = 'hsv')
plt.clf()
plt.colorbar(plot)
plt.bar(range(len(y)), y, color = colors)
plt.show()
I want to colormap legend to appear on the top right of the graph (much smaller of course). My image at the moment looks rather clunky as the colormap is clashing somewhat with the actual bars.
Thanks.
Following this answer:
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
y = np.array([1, 4, 3, 2, 7, 11])
colors = cm.hsv(y / float(max(y)))
fig, ax = plt.subplots()
plot = ax.scatter(y, y, c = y, cmap = 'hsv')
plt.cla()
ax.bar(range(len(y)), y, color = colors)
cbaxes = inset_axes(ax, width="30%", height="3%", loc=2)
plt.colorbar(plot, cax=cbaxes, orientation='horizontal', ticks=[0,2,4,6,8,10])
I use plt.subplots to easily reference the Axes (ax). You can move the color bar and change its size by editing the last 2 lines (for instance changing loc can set which corner you want the colorbar to be in).
I would like to create a plot where dots are overlaid depending on whether or not they are within the 1st-3rd quartiles in seaborn. What function to use?
Something similar to the figure:
The following code creates a Seaborn swarmplot and then recolors the dots depending on their quartile. Looping through the collections created by the swarmplot, the y-data are retrieved. np.percentile calculates the borders of the quartiles and np.digitize calculates the corresponding quartiles. These quartiles can be used to define the color.
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from matplotlib.colors import ListedColormap
sns.set(style="whitegrid")
tips = sns.load_dataset("tips")
# cmap = plt.get_cmap('tab10')
cmap = ListedColormap(['gold', 'crimson', 'teal', 'orange'])
ax = sns.swarmplot(x="day", y="total_bill", data=tips)
for col in ax.collections:
y = col.get_offsets()[:,1]
perc = np.percentile(y, [25, 50, 75])
col.set_cmap(cmap)
col.set_array(np.digitize(y, perc))
plt.show()
The same approach can be used for a stripplot (optionally without jitter) to create a plot similar to the one in the question.
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from matplotlib.colors import ListedColormap
sns.set(style="whitegrid")
N = 200
x = np.repeat(list('abcdefg'), N)
y = np.random.normal(np.repeat(np.random.uniform(11, 15, 7), N), 1)
cmap = ListedColormap(['grey', 'turquoise', 'grey'])
ax = sns.stripplot(x=x, y=y, jitter=False, alpha=0.2)
for col in ax.collections:
y = col.get_offsets()[:, 1]
perc = np.percentile(y, [25, 75])
col.set_cmap(cmap)
col.set_array(np.digitize(y, perc))
plt.show()
I am trying to add a scatter plot to a line plot by using plandas plot function (in jupyter notebook).
I have tried the following code :
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
# plot the line
a = pd.DataFrame({'a': [3,2,6,4]})
ax = a.plot.line()
# try to add the scatterplot
b = pd.DataFrame({'b': [5, 2]})
plot = b.reset_index().plot.scatter(x = 'index', y = 'b', c ='r', ax = ax)
plt.show()
I also checked the following various SO answers but couldn't find the solution.
If anytone can help me, that ould be very appreciated.
EDIT:
somehow the accepted answers works, but i realise that in my case the reason it was not working might have to do with the fact i was using datetime.
like in this code, i cant see the red dots...
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime as dt
%matplotlib inline
fig, ax = plt.subplots()
# plot the line
a = pd.DataFrame({'a': [3,2,6,4]}, index = pd.date_range(dt(2019,1,1), periods = 4))
plot = a.plot.line(ax = ax)
# try to add the scatterplot
b = pd.DataFrame({'b': [5, 2]}, index = [x.timestamp() for x in pd.date_range(dt(2019,1,1), periods = 2)])
plot = b.reset_index().plot.scatter(x = 'index', y = 'b', c ='r', ax = ax)
plt.show()
Any idea whats wrong here?
This should do it (just add fig, ax = plt.subplots() in the beginning):
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
fig, ax = plt.subplots()
# plot the line
a = pd.DataFrame({'a': [3,2,6,4]})
a.plot.line(ax=ax)
# try to add the scatterplot
b = pd.DataFrame({'b': [5, 2]})
plot = b.reset_index().plot.scatter(x = 'index', y = 'b', c ='r', ax = ax)
plt.show()
Edit:
This will work for datetimes:
import matplotlib.pyplot as plt
from datetime import datetime as dt
# %matplotlib inline
fig, ax = plt.subplots()
# plot the line
a = pd.DataFrame({'a': [3,2,6,4]}, index = pd.date_range(dt(2019,1,1), periods = 4))
plot = plt.plot_date(x=a.reset_index()['index'], y=a['a'], fmt="-")
# try to add the scatterplot
b = pd.DataFrame({'b': [5, 2]}, index = pd.date_range(dt(2019,1,1), periods = 2))
plot = plt.scatter(x=b.reset_index()['index'], y=b['b'], c='r')
plt.show()
How do I use matplotlib.pyplot to colour the background of my plot based on an array (of True/False's)?
So for example, if my array was (T,F,F,F,T,T) and I choose the colours 'red' and 'blue', I need the background to be a red column, 3 blue colomns, followed by 2 more reds.
N = 2000
tf = np.random.normal(size = N)
ctf = np.array([np.sum(tf[:1+i]) for i in range(N)])
fig, ax = plt.subplots()
tf2 = tf[None,:]
ax.imshow(tf2, cmap='RdYlGn', aspect = 'auto')
ax.plot(ctf,'k')
You can use imshow:
import numpy as np
from matplotlib import pyplot as plt
fig, ax = plt.subplots()
data = np.array([True, False, True])[ None, :]
ax.imshow(data, cmap = 'RdBu', aspect="auto")
ax.axis('off')
fig.show()
edit: swapped axis to produce columns
edit2: add larger imshow
import numpy as np
from matplotlib import pyplot as plt
N = 2000
tf = np.random.normal(size = N)
ctf = np.array([np.sum(tf[:1+i]) for i in range(N)])
fig, ax = plt.subplots(2, sharex = 'all', \
gridspec_kw = dict(\
height_ratios = [5, 1]))
tf2 = tf[None,:]
ax[0].plot(ctf,'k')
ax[1].imshow(tf2, cmap='RdYlGn', aspect = 'auto')
plt.subplots_adjust(hspace = 0)
edit 3:
import numpy as np
from matplotlib import pyplot as plt
N = 2000
tf = np.random.normal(size = N)
ctf = np.array([np.sum(tf[:1+i]) for i in range(N)])
fig, ax = plt.subplots()
tf2 = tf[None,:]
ax.plot(ctf,'k')
ax.imshow(tf2, cmap='RdYlGn', aspect = 'auto', extent =[0, ctf.shape[0], ctf.min(), ctf.max()])
Sounds like you want to draw rectangles on your plot. (See matplotlib: how to draw a rectangle on image) If you want to have the Rectangles behind some other data, set their zorder to a negative number when you create them.