Remove White Space above and below Seaborn Heatmap Streamlit - python

I am generating heatmap in seaborn and displaying it on a Streamlit dashboard. The generated image has a lot of whitespaces above and below.
#creating heatmap
df= df[['x','y','z']]
df_temp = df.pivot_table(index=x,
columns=y,
values= z)
plt.figure(figsize=(13, 80))
clr = sns.color_palette("RdBu", 7)
ax = sns.heatmap(df_temp, annot=True, fmt='.1f',cmap=clr, cbar=False);
#set x axis label on top
ax.xaxis.set_ticks_position('top')
# split axes of heatmap to put colorbar
ax_divider = make_axes_locatable(ax)
# define size and padding of axes for colorbar
cax = ax_divider.append_axes('top', size = '0.2%', pad = '1%')
# make colorbar for heatmap.
# Heatmap returns an axes obj but you need to get a mappable obj (get_children)
colorbar(ax.get_children()[0], cax = cax, orientation = 'horizontal')
# locate colorbar ticks
cax.xaxis.set_ticks_position('top')
Image output
I use st.pyplot to render this on Streamlit dashbaord
Any help would be greatly appreciated.
P.S it displays correctly in Jupyter notebook

Related

Matplotlib Plot and Colorbar issues

I have the below plot, however, I am struggling with the 3 questions below....
How can I move X-axis labels (1-31) to the top of the plot?
How can I change formating of the color bar from (7000 to 7k etc.)
How can I change the color from gray to another cmap like "Reds"?
Can I change the figure size? plt.figure(figsize=(20,10)) does not work?
data1 = pd.read_csv("a2data/data1.csv")
data2 = pd.read_csv("a2data/data2.csv")
merged_df = pd.concat([data1, data2])
merged_df.set_index(['month', 'day'], inplace=True)
merged_df.sort_index(inplace=True)
merged_df2=merged_df.groupby(['month', 'day']).deaths.mean().unstack('day')
plt.imshow(merged_df2)
plt.xticks(np.arange(merged_df2.shape[1]), merged_df2.columns)
plt.yticks(np.arange(merged_df2.shape[0]), merged_df2.index)
plt.colorbar(orientation="horizontal")
plt.show()
Let's try:
# create a single subplot to access the axis
fig, ax = plt.subplots()
# passing the `cmap` for custom color
plt.imshow(df, cmap='hot', origin='upper')
# draw the colorbar
cb = plt.colorbar(orientation="horizontal")
# extract the ticks on colorbar
ticklabels = cb.get_ticks()
# reformat the ticks
cb.set_ticks(ticklabels)
cb.set_ticklabels([f'{int(x//1000)}K' for x in ticklabels])
# move x ticks to the top
ax.xaxis.tick_top()
plt.show()
Output:
Try this to invert the y axis:
ax = plt.yticks(np.arange(merged_df2.shape[0]), merged_df2.index)
plt.colorbar(orientation="horizontal")
ax.invert_yaxis()
plt.show()
I think for the color, you can find better in the pyplot documentation, https://matplotlib.org/3.3.1/api/_as_gen/matplotlib.pyplot.plot.html#matplotlib.pyplot.plot

Why colorbar cannot work with heatmap fuse to scatter?

I work with two graphics, and they are fuse. It's a heatmap fuse to a scatter but the heatmap doesn't have colorbar and I want to show this color. When I try to do it it give me an error:
RuntimeError: No mappable was found to use for colorbar creation. First define a mappable such as an image (with imshow) or a contour set (with contourf).
Here's the code:
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv("data/forestfires.csv")
x_number_list = df.X.tolist()
y_number_list = df.Y.tolist()
x_number_list = np.array(x_number_list)
y_number_list = np.array(y_number_list)
area_number_list = df.area.tolist()
area_number_list = [int(round(x+1,0)) for x in area_number_list]
temperature_number_list = df.temp.tolist()
temperature_number_list = np.array(temperature_number_list)
heatmap, xedges, yedges = np.histogram2d(y_number_list, x_number_list, weights=temperature_number_list)
fig, ax1 = plt.subplots(figsize=(7,7))
ax1.imshow(heatmap, interpolation='bicubic', cmap='hot', origin='lower')
ax1.scatter(x_number_list, y_number_list, s=area_number_list, color=(157/255, 173/255, 245/255, 0.9))
ax1.set_ylim(y_number_list.min()-0.5, y_number_list.max()+0.5)
ax1.set_xlim(x_number_list.min()-0.5, x_number_list.max()+0.5)
cb = plt.colorbar()
plt.show()
here's the result of the plot:
All data I use in this program are number. I work on jupyter and I use the lastest version on python.
You need to specify where you want to have to colorbar and what you want the colorbar to show. I would do it in the following fashion.
Change
ax1.imshow(heatmap, interpolation='bicubic', cmap='hot', origin='lower')
to
im = ax1.imshow(heatmap, interpolation='bicubic', cmap='hot', origin='lower')
and then specify the colorbar as
cb = fig.colorbar(im, ax=ax1)

2 subplots sharing y-axis (no space between) with single color bar

Does anyone have a matplotlib example of two plots sharing the y-axis (with no space between the plots) with a single color bar pertaining to both subplots? I have not been able to find examples of this yet.
I created the following code based on your question. Personally I do not like it to have no space between the subplots at all. If you do want to change this at some point all you need to do is to replace plt.subplots_adjust(wspace = -.059) with plt.tight_layout().
Hope this helps
import numpy
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
#Random data
data = numpy.random.random((10, 10))
fig = plt.figure()
ax1 = fig.add_subplot(1,2,1, aspect = "equal")
ax2 = fig.add_subplot(1,2,2, aspect = "equal", sharey = ax1) #Share y-axes with subplot 1
#Set y-ticks of subplot 2 invisible
plt.setp(ax2.get_yticklabels(), visible=False)
#Plot data
im1 = ax1.pcolormesh(data)
im2 = ax2.pcolormesh(data)
#Define locations of colorbars for both subplot 1 and 2
divider1 = make_axes_locatable(ax1)
cax1 = divider1.append_axes("right", size="5%", pad=0.05)
divider2 = make_axes_locatable(ax2)
cax2 = divider2.append_axes("right", size="5%", pad=0.05)
#Create and remove the colorbar for the first subplot
cbar1 = fig.colorbar(im1, cax = cax1)
fig.delaxes(fig.axes[2])
#Create second colorbar
cbar2 = fig.colorbar(im2, cax = cax2)
#Adjust the widths between the subplots
plt.subplots_adjust(wspace = -.059)
plt.show()
The result is the following:

Change color of cbar legend text python

Is it possible to change the text color of the cbar legend values ? We want to use a black background but the text is falling away. We use Matplotlib for plotting.
We can change the text color of the label, but not of the values.
cbar = m.colorbar(cs,location='right',pad="10%")
cbar.set_label('dBZ', color="white")
Thank you in advanced.
Kevin Broeren
You can change the color of the color bar values using set_yticklabels since they are tick labels for the color bar axis. Here's an example:
import matplotlib.pyplot as plt
from numpy.random import randn
# plot something
fig, ax = plt.subplots()
cax = ax.imshow(randn(100,100))
# create the color bar
cbar = fig.colorbar(cax)
cbar.set_label('dBZ', color = "white")
# update the text
t = cbar.ax.get_yticklabels();
labels = [item.get_text() for item in t]
cbar.ax.set_yticklabels(labels, color = 'white')
plt.show()
The first answer to this question has an explanation of why you need to do it this way.

get_position() does strange things when using a colorbar

I have a matrix of data in which the x and y axes are logarithmic. I'm trying to use imshow to display the matrix, but since I want log axes I'm setting the ticks in the imshow axes to [], and then overlaying another set of axes:
import matplotlib.pyplot as plt
import numpy as np
# the x,y max and min are the log values
array = np.zeros((2,2))
array[1,1] = -1
fig = plt.figure()
ax = plt.imshow(
array,
extent = (0,1, 1, 0),
interpolation = 'nearest').get_axes()
ax.invert_yaxis()
# add a colorbar
# cb = plt.colorbar() # <----- THIS CAUSES TROUBLE
# cb.set_label('zbar')
ax.set_aspect(1)
ax.xaxis.set_ticks([])
ax.yaxis.set_ticks([])
position = ax.get_position()
aspect = ax.get_aspect()
# overlay another set of axes
ax_log = fig.add_subplot(111, frameon = False)
ax_log.set_xscale('log')
ax_log.set_yscale('log')
ax_log.axis((10**0, 10**1, 10**0, 10**1)) # old min and max but exponentiated
ax_log.set_position(position)
ax_log.set_aspect(aspect)
plt.savefig('test.png', bbox_inches = 'tight')
plt.close()
without the colorbar this works fine:
but when I uncomment the lines adding a colorbar, I get a weird shift:
It looks like the colorbar somehow shifts the image slightly to the left, but given that I'm calling get_position() after I create the colorbar this seems weird. Am I overlooking an easier way to make this plot? Is there some easy fix?
Searching around a bit, I found a workaround, maybe there's a better one...
The issue seems to be that plt.colorbar() will 'steal' space from the plot it's drawn on. It's still a bit strange, because I'd still expect get_position() to return the proper coordinates. But as a workaround I used GridSpec and the raw Colorbar constructor.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpec
from matplotlib.colorbar import Colorbar
# the x,y max and min are the log values
array = np.zeros((2,2))
array[1,1] = -1
fig = plt.figure()
gs = GridSpec(10,11) # create a 10 x 11 grid
ax = plt.subplot(gs[:,0:-1]) # make subplot on 10 x 10 part
im = plt.imshow(
array,
extent = (0,1, 1, 0),
interpolation = 'nearest',
axes = ax)
ax.invert_yaxis()
# add a colorbar
cb_ax = plt.subplot(gs[:,-1]) # put the colorbar on the last column
cb = Colorbar(ax = cb_ax, mappable = im ) # use the raw colorbar constructor
cb.set_label('zbar')
ax.set_aspect(1)
ax.xaxis.set_ticks([])
ax.yaxis.set_ticks([])
position = ax.get_position()
aspect = ax.get_aspect()
# overlay another set of axes
ax_log = fig.add_subplot(111, frameon = False) # can't use gridspec?
ax_log.set_xscale('log')
ax_log.set_yscale('log')
ax_log.axis((10**0, 10**1, 10**0, 10**1)) # old min and max but exponentiated
ax_log.set_position(position)
ax_log.set_aspect(aspect)
plt.savefig('test.pdf', bbox_inches = 'tight')
plt.close()
It's also quite strange that I can't use the GridSpec object to initialize the second set of axes (doing so makes the image disappear).

Categories

Resources