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
Related
Say I have data that I want to box plot and overlay with a swarm plot in seaborn, whose colors of the points add additional information on the data.
Question: How can I get box plots to be close to each other for a given x axis value (as is done in hue) without refactorizing x to the hue value and the x axis value?
For example, here I want to overlay the points to the box plot and want the points further colored by ‘sex’. Example:
plt.figure(figsize = (5, 5))
sns.boxplot(x = 'class', y = 'age',
hue = 'embarked', dodge = True, data = df)
sns.swarmplot(x = 'class', y = 'age',
dodge = True,
color = '0.25',
hue = 'sex', data = df)
plt.legend(bbox_to_anchor = (1.5, 1))
EDIT:
The idea would be to have something that looks like the 'S' box for 'Third' in the plot (I made a fake example in powerpoint, so hue in both boxplot and swarmplot are the same to overlay the points on the appropriate boxes).
Is there a way to make this plot without first refactorizing the x-axis to ‘first-S’, ‘first-C’, ‘first-Q’, ‘second-S’, etc and then add hue by ’sex’ in both plots?
Using original x as col and hue as x
To work with two types of hue, seaborn's alternative is to create a FacetGrid. The original x= then becomes the col= (or the row=), and one of the hues becomes the new x=.
Here is an example. Note that aspect= controls the width of the individual subplots (the width being height*aspect).
from matplotlib import pyplot as plt
import seaborn as sns
df = sns.load_dataset('titanic')
g = sns.catplot(kind='box', x='embarked', y='age', hue='sex', col='class',
dodge=True, palette='spring',
height=5, aspect=0.5, data=df)
g.map_dataframe(sns.swarmplot, x='embarked', y='age', hue='sex', palette=['0.25'] * 2, size=2, dodge=True)
for ax in g.axes.flat:
# use title as x-label
ax.set_xlabel(ax.get_title())
ax.set_title('')
# remove y-axis except for the left-most columns
if len(ax.get_ylabel()) == 0:
ax.spines['left'].set_visible(False)
ax.tick_params(axis='y', left=False)
plt.subplots_adjust(wspace=0)
plt.show()
Only using hue for the swarmplot, without dodge
Here is a variant, where the boxplot doesn't use hue, but the swarmplot does. A bit more padding can be added inside the subplots, and the boxplots can be made touching via width=1. Suppressing the outliers of the boxplot looks cleaner, as they would overlap with the outlier of the swarmplot.
from matplotlib import pyplot as plt
import seaborn as sns
import pandas as pd
df = sns.load_dataset('titanic')
df['embarked'] = pd.Categorical(df['embarked'], ['S', 'C', 'Q']) # force a strict order
g = sns.catplot(kind='box', x='embarked', y='age', col='class',
dodge=True, palette='summer', width=1, showfliers=False,
height=5, aspect=0.5, data=df)
g.map_dataframe(sns.swarmplot, x='embarked', y='age', hue='sex', palette=['b', 'r'], size=2, dodge=False)
g.add_legend()
for ax in g.axes.flat:
# use title as x-label
ax.set_xlabel(ax.get_title())
ax.set_title('')
# remove y-axis except for the left-most columns
if len(ax.get_ylabel()) == 0:
ax.spines['left'].set_visible(False)
ax.tick_params(axis='y', left=False)
xmin, xmax = ax.get_xlim()
ax.set_xlim(xmin - 0.2, xmax + 0.2) # add a bit more spacing between the groups
plt.subplots_adjust(wspace=0)
plt.show()
I am trying to create a heatmap by putting gridlines to some particular positions which I have done. Suppose, I tried to make gridlines in positions 358 and 589 in a matrix of length 640,640. After that, I wanted to change the label from 358 to a defined value of 999 and 589 to a specified value of 1023. However, I cannot change the x and y labels in the center position of two gridlines. For example, I have tried the following:
data = np.random.rand(640, 640)
fig, ax = plt.subplots()
im = ax.imshow(data,cmap='coolwarm')
ax.set_xticks([358,589])
ax.set_yticks([358,589])
ax.set_xticklabels([999,1023])
ax.set_yticklabels([999,1023])
ax.grid(which='major',color='black',linestyle='--',linewidth=1,alpha=0.5)
plt.show()
That create a image as follows:
Heatmap with customized labelling
But I want the labeling in the middle of two gridlines instead of the gridline positions. How can that be done?
By default, both the tick labels and the grid lines are decided via the major ticks. To change this, you could use the minor ticks to position the grid lines and the major ticks for the tick labels:
from matplotlib import pyplot as plt
import numpy as np
data = np.random.randn(640, 640).cumsum(axis=0).cumsum(axis=1)
fig, ax = plt.subplots()
im = ax.imshow(data, cmap='coolwarm')
positions = np.array([358, 589])
ax.set_xticks(positions, minor=True)
ax.set_yticks(positions, minor=True)
borders = np.append(0, positions)
mids = (borders[:-1] + borders[1:]) / 2
ax.set_xticks(mids, [999, 1023], minor=False)
ax.set_yticks(mids, [999, 1023], minor=False)
ax.grid(which='minor', color='black', linestyle='--', linewidth=1, alpha=0.9)
plt.show()
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
I want to make the x axis of the graph the same as below.
Ignore the color, I just want the x axis frequency to be in increments of 5.
To get the xticks from the first plot just use:
fig, ax = plt.subplots()
ax = df.plot(kind='bar', stacked=True)
xticks = ax.get_xticklabels()
Then apply it to the other plot with
ax2 = df.plot(...)
ax2.set_xticklabels(xticks)
Similarly to this question, I am using the subplots keyword in matplotlib except I am drawing pie charts and using pandas.
The labels on my subplots crash with the slice labels when the labels are close to horizontal:
first = pd.Series({'True':2316, 'False': 64})
second = pd.Series({'True':2351, 'False': 29})
df = pd.concat([first, second], axis=1, keys=['First pie', 'Second pie'])
axes = df.plot(kind='pie', subplots=True)
for ax in axes:
ax.set_aspect('equal')
I can alleviate this somewhat by doing as the docs do and adding an explicit figsize, but it still looks pretty cramped:
axes = df.plot(kind='pie', figsize=[10, 4], subplots=True)
for ax in axes:
ax.set_aspect('equal')
Is there a nice way to do better. Something to do with tight_layout maybe?
I think you need padding of lables in y-axis so use labelpad i.e ax.yaxis.labelpad = 20
axes = df.plot(kind='pie', figsize=[10, 4], subplots=True)
for ax in axes:
ax.set_aspect('equal')
ax.yaxis.labelpad = 20
You can move the label to the left using ax.yaxis.set_label_coords(), and then adjust the coords to a value that suits you.
The two inputs to set_label_coords are the x and y coordinate of the label, in Axes fraction coordinates.
For your plot, I found (-0.15, 0.5) to work well (i.e. x=-0.15 means 15% of the axes width to the left of the axes, and y=0.5 means half way up the axes). In general then, assuming you always want the label to be centered on the y axis, you only need to adjust the x coordinate.
I also added some space between the plots using subplots_adjust(wspace=0.5) so that the axes label didn't then overlap with the False label from the other pie.
import pandas as pd
import matplotlib.pyplot as plt
first = pd.Series({'True':2316, 'False': 64})
second = pd.Series({'True':2351, 'False': 29})
df = pd.concat([first, second], axis=1, keys=['First pie', 'Second pie'])
axes = df.plot(kind='pie', subplots=True)
for ax in axes:
ax.set_aspect('equal')
ax.yaxis.set_label_coords(-0.15, 0.5)
plt.subplots_adjust(wspace=0.5)
plt.show()