How to plot subplots horizontally and vertically aligned with respect to each other in matplotlib? - matplotlib

I have 3 subplots in matplotlib (2 rows and 3 columns).
I intend to have the first subplot in the 1st row covering the all 3 columns;
second subplot in the 2nd row left most aligned
third subplot in the 2nd row right most aligned.
Both second and third subplots horizontally aligned to the top with respect to each other.
However with the code below, I could not horizontally align them.
I also used gridspec.GridSpec with some width_ratios.
import numpy as np
import os
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
from matplotlib import gridspec
def plot_figure():
xticklabels_list = ['a','b','c','d','e','f'] * 6
rows=['row1']
plot1 = plt.figure(figsize=(5 + 1.5 * len(xticklabels_list), 5 + 1.5 * len(rows)))
gs = gridspec.GridSpec(2, 3, width_ratios=[1, 1, 1], height_ratios=[1, 1])
top_axis = plt.subplot(gs[0, :])
bottom_left_axis = plt.subplot(gs[-1, 0])
bottom_right_axis = plt.subplot(gs[-1, -1])
plot_at_bottom_left_axis(bottom_left_axis)
top_axis.set_xlim([0, 36])
top_axis.set_xticklabels([])
top_axis.tick_params(axis='x', which='minor', length=0, labelsize=35)
top_axis.set_xticks(np.arange(0, 36, 1))
top_axis.set_xticks(np.arange(0, 36, 1) + 0.5, minor=True)
top_axis.set_xticklabels(xticklabels_list, minor=True)
top_axis.xaxis.set_label_position('top')
top_axis.xaxis.set_ticks_position('top')
plt.tick_params(
axis='x', # changes apply to the x-axis
which='major', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False) # labels along the bottom edge are off
# CODE GOES HERE TO CENTER Y-AXIS LABELS...
top_axis.set_ylim([0, len(rows)])
top_axis.set_yticklabels([])
top_axis.tick_params(axis='y', which='minor', length=0, labelsize=40)
top_axis.set_yticks(np.arange(0, len(rows), 1))
top_axis.set_yticks(np.arange(0, len(rows), 1) + 0.5, minor=True)
top_axis.set_yticklabels(rows, minor=True) # fontsize
plt.tick_params(
axis='y', # changes apply to the x-axis
which='major', # both major and minor ticks are affected
left=False) # labels along the bottom edge are off
# Gridlines based on major ticks
top_axis.grid(which='major', color='black', zorder=3)
# Put the legend
legend_elements = [ Line2D([0], [0], marker='o', color='white', label='legend1', markerfacecolor='red',markersize=40),
Line2D([0], [0], marker='o', color='white', label='legend2', markerfacecolor='green',markersize=40)]
bottom_right_axis.set_axis_off()
bottom_right_axis.legend(handles=legend_elements, ncol=len(legend_elements), bbox_to_anchor=(1,1), loc='upper right',fontsize=40)
figFile = os.path.join('/Users/burcakotlu/Desktop', 'test.png')
plot1.savefig(figFile, dpi=100, bbox_inches="tight")
plt.cla()
plt.close(plot1)
def plot_at_bottom_left_axis(ax):
box = ax.get_position()
ax.set_position([0, 1, box.width * 1, box.height * 1], which='active')
diameter_labels = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
diameter_ticklabels = ['label1', '', '', '', 'label2', '', '', '', '', 'label3']
row_labels = ['circle']
ax.grid(which="major", color="w", linestyle='-', linewidth=3)
plt.setp(ax.spines.values(), color='white')
ax.set_aspect(1.0)
ax.set_facecolor('lightcyan')
# CODE GOES HERE TO CENTER X-AXIS LABELS...
ax.set_xlim([0, len(diameter_labels)])
ax.set_xticklabels([])
ax.tick_params(axis='x', which='both', length=0, labelsize=30)
ax.set_xticks(np.arange(0, len(diameter_labels), 1))
ax.set_xticks(np.arange(0, len(diameter_labels), 1) + 0.5, minor=True)
ax.set_xticklabels(diameter_ticklabels, minor=True)
ax.xaxis.set_ticks_position('bottom')
plt.tick_params(
axis='x', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False) # labels along the bottom edge are off
ax.set_xlabel('labels to be shown', fontsize=40, labelpad=10)
ax.set_ylim([0, len(row_labels)])
ax.set_yticklabels([])
ax.tick_params(axis='y', which='minor', length=0, labelsize=12)
ax.set_yticks(np.arange(0, len(row_labels), 1))
ax.set_yticks(np.arange(0, len(row_labels), 1) + 0.5, minor=True)
plt.tick_params(
axis='y', # changes apply to the x-axis
which='major', # both major and minor ticks are affected
left=False) # labels along the bottom edge are off
plot_figure()
Here is the resulting figure for the code above.

Related

Plot circle at the title in matplotlib python

I have a 2 line title and first line has a number at the end of the line.
Can we plot a circle around the number?
Here is the code to generate the figure.
from matplotlib import rcParams
from matplotlib import pyplot as plt
import numpy as np
import os
rcParams.update({'figure.autolayout': True})
some_text = 'XXX'
any_number=15
title = '%s: %d\n YYY ZZZZ WWWWW' % (some_text,any_number)
fig = plt.figure(figsize=(8, 8), dpi=100)
plt.tick_params(axis='y', which='major', labelsize=60, width=3, length=10, pad=40)
plt.tick_params(axis='y', which='minor', labelsize=60, width=3, length=10, pad=40)
ax = plt.gca()
plt.title(title, fontsize=60, pad=40, loc='center', fontweight='semibold')
plt.style.use('ggplot')
ax.set_facecolor('white')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(True)
for edge_i in ['left']:
ax.spines[edge_i].set_edgecolor("black")
ax.spines[edge_i].set_linewidth(3)
ax.spines[edge_i].set_bounds(0, 1)
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
plt.yticks(np.arange(0, 1.01, step=0.2))
data_list= np.array([1,1,1,1,1,0.9, 0.8, 0.7, 0.8,0.85])
plt.bar(x, data_list, 0.9, color='indianred',edgecolor="black", linewidth=3,zorder=1)
plt.tick_params(
axis='x', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False, # ticks along the top edge are off
labelbottom=False) # labels along the bottom edge are off
figure_name = 'figure_with_circle.png'
figure_file = os.path.join('/Users/burcakotlu/Desktop',figure_name)
fig.savefig(figure_file, dpi=100, bbox_inches="tight")
plt.close(fig)
Here is the current figure and the wanted circle.
One could use the following without ax.bar():
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_title('title')
circle1 = plt.Circle((2,4.15), 0.2, color='k', clip_on=False, zorder=100, fill=False)
ax.add_patch(circle1)
ax.set_xlim(0,4)
ax.set_ylim(0,4)
plt.show()
I have found a way to plot circle together with bar plots without distorting bars. Here is the code below:
from matplotlib import rcParams
from matplotlib import pyplot as plt
import numpy as np
import os
import matplotlib.patches as patches
from matplotlib.offsetbox import AnchoredText
rcParams.update({'figure.autolayout': True})
some_text = 'XXX'
any_number=15
title = '%s: %d\n YYY ZZZZ WWWWW' % (some_text,any_number)
fig = plt.figure(figsize=(12,12), dpi=100)
plt.tick_params(axis='y', which='major', labelsize=60, width=3, length=10, pad=40)
plt.tick_params(axis='y', which='minor', labelsize=60, width=3, length=10, pad=40)
ax = plt.gca()
number_of_xxx = '12'
anchored_text_number_of_xxx = AnchoredText(number_of_xxx,
frameon=False, borderpad=0, pad=0.1,
loc='upper right',
bbox_to_anchor=[0.95, 1.3],
bbox_transform=plt.gca().transAxes,
prop={'fontsize': 60,
'fontweight': 'semibold'})
ax.add_artist(anchored_text_number_of_xxx)
circle1 = patches.Circle((0.88, 1.25), radius=0.1, transform=ax.transAxes, zorder=100, fill=False, color='gold', lw=8, clip_on=False)
ax.add_patch(circle1)
ax.set_title(title, fontsize=60, pad=40, loc='center', fontweight='semibold', zorder=50)
ax.set_facecolor('white')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(True)
for edge_i in ['left']:
ax.spines[edge_i].set_edgecolor("black")
ax.spines[edge_i].set_linewidth(3)
ax.spines[edge_i].set_bounds(0, 1)
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ax.set_yticks(np.arange(0, 1.01, step=0.2))
data_list= np.array([1,1,1,1,1,0.9, 0.8, 0.7, 0.8,0.85])
ax.bar(x, data_list, 0.9, color='indianred',edgecolor="black", linewidth=3,zorder=1)
ax.tick_params(
axis='x', # changes apply to the x-axis
which='both', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False, # ticks along the top edge are off
labelbottom=False) # labels along the bottom edge are off
figure_name = 'figure_with_circle.png'
figure_file = os.path.join('/Users/burcakotlu/Desktop',figure_name)
fig.savefig(figure_file, dpi=100, bbox_inches="tight")
plt.close(fig)

Matplotlib gives ValueError: Image size pixels is too large when I add one more subplot

I have been struggling today almost all day with Image size pixels is too large error when I try to combine multiple plots into one figure using matplotlib add_subplot function.
I can plot each plot individually but when I combine them I face with this problem.
Here is the simplified code to replicate this Value error.
from matplotlib import pyplot as plt
import numpy as np
import os
def plot_in_subplots():
fig= plt.figure(figsize=(15, 10))
axis1=fig.add_subplot(311)
# Uncomment line below to replicate ValueError: Image size of 3719x61904113 pixels is too large. It must be less than 2^16 in each direction.
# axis2=fig.add_subplot(312)
plot_bar_plot_in_given_axis(axis1)
# plot_in_given_axis(axis2)
figFile = os.path.join('/Users/burcakotlu/Desktop/Test_subplot.png')
fig.savefig(figFile, dpi=100, bbox_inches="tight")
plt.cla()
plt.close(fig)
def plot_in_given_axis(ax):
xticklabels_list = ['a','b','c','d','e','f'] * 6
rows=['row1']
ax.set_xlim([0, 36])
ax.set_xticklabels([])
ax.tick_params(axis='x', which='minor', length=0, labelsize=35)
ax.set_xticks(np.arange(0, 36, 1))
ax.set_xticks(np.arange(0, 36, 1) + 0.5, minor=True)
ax.set_xticklabels(xticklabels_list, minor=True)
ax.xaxis.set_label_position('top')
ax.xaxis.set_ticks_position('top')
plt.tick_params(
axis='x', # changes apply to the x-axis
which='major', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False) # labels along the bottom edge are off
ax.set_ylim([0, len(rows)])
ax.set_yticklabels([])
ax.tick_params(axis='y', which='minor', length=0, labelsize=40)
ax.set_yticks(np.arange(0, len(rows), 1))
ax.set_yticks(np.arange(0, len(rows), 1) + 0.5, minor=True)
ax.set_yticklabels(rows, minor=True) # fontsize
plt.tick_params(
axis='y', # changes apply to the x-axis
which='major', # both major and minor ticks are affected
left=False) # labels along the bottom edge are off
ax.grid(which='major', color='black', zorder=3)
def plot_bar_plot_in_given_axis(ax):
x_axis_labels = ['a', 'b', 'c', 'd', 'e', 'f']
real_values1 = [266655.0, 0.0, 14072.0, 4137.0, 6752.5, 0.0]
real_values2 = [273342.5, 0.0, 12598.5, 4240.0, 7425.5, 0.0]
unreal_values1 = [326188.16, 0.0, 15828.42, 4666.825000000001, 8109.87, 0.0]
unreal_values2 = [344462.07, 0.0, 16368.664999999999, 5180.2, 8721.64, 0.0]
q_values = [2.5309603790195403e-28, 1.0, 1.8194829804783173e-33, 0.003603381046779825, 1.0, 1.0]
name1 = 'X'
name2 = 'Y'
color1 = 'r'
color2 = 'b'
width = 0.1
ind = np.arange(len(x_axis_labels))
legend=None
rects3=None
rects4=None
rects1 = ax.bar(ind, real_values1, width=width, edgecolor='black', color=color1)
rects2 = ax.bar(ind + width, real_values2, width=width, edgecolor='black', color=color2)
if ((unreal_values1 is not None) and unreal_values1):
rects3 = ax.bar(ind+ 2*width, unreal_values1, width=width, edgecolor='black', color=color1, hatch = 'X')
if ((unreal_values2 is not None) and unreal_values2):
rects4 = ax.bar(ind +3*width, unreal_values2, width=width, edgecolor='black', color=color2, hatch = 'X')
ax.tick_params(axis='x', labelsize=35)
ax.tick_params(axis='y', labelsize=35)
locs, labels = plt.yticks()
ax.set_ylim(0, locs[-1] + 5000)
ax.set_title('%s vs. %s' %(name1,name2), fontsize=20,fontweight='bold')
ax.set_xticklabels(x_axis_labels, fontsize=35)
plt.ylabel('Y axis label', fontsize=35, fontweight='normal')
ax.set_xticks(ind + (3 * width) / 2)
realStrand1Name = 'Real %s' % (name1)
realStrand2Name = 'Real %s' % (name2)
simulationsStrand1Name = 'Unreal %s' % (name1)
simulationsStrand2Name = 'Unreal %s' % (name2)
if ((rects1 is not None) and (rects2 is not None) and (rects3 is not None) and (rects4 is not None)):
if ((len(rects1) > 0) and (len(rects2) > 0) and (len(rects3) > 0) and (len(rects4) > 0)):
legend = ax.legend((rects1[0], rects2[0], rects3[0], rects4[0]),
(realStrand1Name, realStrand2Name, simulationsStrand1Name, simulationsStrand2Name),prop={'size': 25}, ncol=1, loc='best')
ax.set_facecolor('white')
ax.spines["bottom"].set_color('black')
ax.spines["left"].set_color('black')
ax.spines["top"].set_color('black')
ax.spines["right"].set_color('black')
if (legend is not None):
frame = legend.get_frame()
frame.set_facecolor('white')
frame.set_edgecolor('black')
if q_values is not None:
for q_value, rect1, rect2 in zip(q_values,rects1,rects2):
# Get X and Y placement of label from rect.
y_value = max(rect1.get_height(),rect2.get_height())
x_value = rect1.get_x() + rect1.get_width()
space = 3
va = 'bottom'
if y_value < 0:
space *= -1
va = 'top'
if ((q_value is not None) and (q_value)<=0.05):
plt.annotate(
'***', # Use `label` as label
(x_value, y_value), # Place label at end of the bar
xytext=(0, space), # Vertically shift label by `space`
textcoords="offset points", # Interpret `xytext` as offset in points
ha='center', # Horizontally center label
va=va,
fontsize=20) # Vertically align label differently for
plot_in_subplots()
Please uncomment this line to replicate ValueError: Image size of 3719x61904113 pixels is too large. It must be less than 2^16 in each direction.
axis2=fig.add_subplot(312)
Here are the plots I want to combine using add_subplot
I have upgraded to Matplotlib 3.4.2.
I changed plt.xxx into ax.xxx (object oriented) and using gridspec, I'm almost there. Thanks.
from matplotlib import pyplot as plt
from matplotlib import gridspec
import numpy as np
import os
def plot_in_subplots():
fig= plt.figure(figsize=(30, 10))
gs = gridspec.GridSpec(10, 4, width_ratios=[1,1,1,1], height_ratios=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
axis1 = plt.subplot(gs[0:7, 1:3])
axis2 = plt.subplot(gs[9, :])
# bottom_left_axis = plt.subplot(gs[-1,0])
# bottom_right_axis = plt.subplot(gs[-1,-1])
# axis1=fig.add_subplot(211)
# axis2=fig.add_subplot(212)
plot_bar_plot_in_given_axis(axis1)
plot_in_given_axis(axis2)
figFile = os.path.join('/Users/burcakotlu/Desktop/Test_subplot.png')
fig.savefig(figFile, dpi=100, bbox_inches="tight")
plt.cla()
plt.close(fig)
def plot_in_given_axis(ax):
xticklabels_list = ['a','b','c','d','e','f'] * 6
rows=['row1']
ax.set_xlim([0, 36])
ax.set_xticklabels([])
ax.tick_params(axis='x', which='minor', length=0, labelsize=35)
ax.set_xticks(np.arange(0, 36, 1))
ax.set_xticks(np.arange(0, 36, 1) + 0.5, minor=True)
ax.set_xticklabels(xticklabels_list, minor=True)
ax.xaxis.set_label_position('top')
ax.xaxis.set_ticks_position('top')
ax.tick_params(
axis='x', # changes apply to the x-axis
which='major', # both major and minor ticks are affected
bottom=False, # ticks along the bottom edge are off
top=False) # labels along the bottom edge are off
ax.set_ylim([0, len(rows)])
ax.set_yticklabels([])
ax.tick_params(axis='y', which='minor', length=0, labelsize=40)
ax.set_yticks(np.arange(0, len(rows), 1))
ax.set_yticks(np.arange(0, len(rows), 1) + 0.5, minor=True)
ax.set_yticklabels(rows, minor=True) # fontsize
ax.tick_params(
axis='y', # changes apply to the x-axis
which='major', # both major and minor ticks are affected
left=False) # labels along the bottom edge are off
ax.grid(which='major', color='black', zorder=3)
def plot_bar_plot_in_given_axis(ax):
x_axis_labels = ['a', 'b', 'c', 'd', 'e', 'f']
real_values1 = [266655.0, 0.0, 14072.0, 4137.0, 6752.5, 0.0]
real_values2 = [273342.5, 0.0, 12598.5, 4240.0, 7425.5, 0.0]
unreal_values1 = [326188.16, 0.0, 15828.42, 4666.825000000001, 8109.87, 0.0]
unreal_values2 = [344462.07, 0.0, 16368.664999999999, 5180.2, 8721.64, 0.0]
q_values = [2.5309603790195403e-28, 1.0, 1.8194829804783173e-33, 0.003603381046779825, 1.0, 1.0]
name1 = 'X'
name2 = 'Y'
color1 = 'r'
color2 = 'b'
width = 0.1
ind = np.arange(len(x_axis_labels))
legend=None
rects3=None
rects4=None
rects1 = ax.bar(ind, real_values1, width=width, edgecolor='black', color=color1)
rects2 = ax.bar(ind + width, real_values2, width=width, edgecolor='black', color=color2)
if ((unreal_values1 is not None) and unreal_values1):
rects3 = ax.bar(ind+ 2*width, unreal_values1, width=width, edgecolor='black', color=color1, hatch = 'X')
if ((unreal_values2 is not None) and unreal_values2):
rects4 = ax.bar(ind +3*width, unreal_values2, width=width, edgecolor='black', color=color2, hatch = 'X')
ax.tick_params(axis='x', labelsize=35)
ax.tick_params(axis='y', labelsize=35)
locs=ax.get_yticks()
ax.set_ylim(0, locs[-1] + 5000)
ax.set_title('%s vs. %s' %(name1,name2), fontsize=20,fontweight='bold')
ax.set_xticklabels(x_axis_labels, fontsize=35)
ax.set_ylabel('Y axis label', fontsize=35, fontweight='normal')
ax.set_xticks(ind + (3 * width) / 2)
realStrand1Name = 'Real %s' % (name1)
realStrand2Name = 'Real %s' % (name2)
simulationsStrand1Name = 'Unreal %s' % (name1)
simulationsStrand2Name = 'Unreal %s' % (name2)
if ((rects1 is not None) and (rects2 is not None) and (rects3 is not None) and (rects4 is not None)):
if ((len(rects1) > 0) and (len(rects2) > 0) and (len(rects3) > 0) and (len(rects4) > 0)):
legend = ax.legend((rects1[0], rects2[0], rects3[0], rects4[0]),
(realStrand1Name, realStrand2Name, simulationsStrand1Name, simulationsStrand2Name),prop={'size': 25}, ncol=1, loc='best')
ax.set_facecolor('white')
ax.spines["bottom"].set_color('black')
ax.spines["left"].set_color('black')
ax.spines["top"].set_color('black')
ax.spines["right"].set_color('black')
if (legend is not None):
frame = legend.get_frame()
frame.set_facecolor('white')
frame.set_edgecolor('black')
if q_values is not None:
for q_value, rect1, rect2 in zip(q_values,rects1,rects2):
# Get X and Y placement of label from rect.
y_value = max(rect1.get_height(),rect2.get_height())
x_value = rect1.get_x() + rect1.get_width()
space = 3
va = 'bottom'
if y_value < 0:
space *= -1
va = 'top'
if ((q_value is not None) and (q_value)<=0.05):
ax.annotate(
'***', # Use `label` as label
(x_value, y_value), # Place label at end of the bar
xytext=(0, space), # Vertically shift label by `space`
textcoords="offset points", # Interpret `xytext` as offset in points
ha='center', # Horizontally center label
va=va,
fontsize=20,
transform=ax.transAxes) # Vertically align label differently for
plot_in_subplots()

Is there a way to label each wedge of pie chart in this grid?

I want to have multiple pie charts in a grid.
Each pie chart will have a different number of wedges, values, and labels.
The code below shows multiple labels in one pie chart.
Is there a way to label each wedge of pie-charts in this grid?
import matplotlib.pyplot as plt
import numpy as np
def heatmap_with_circles(data_array,row_labels,column_labels,ax=None, cmap=None, norm=None, cbar_kw={}, cbarlabel="", **kwargs):
for row_index, row in enumerate(row_labels,0):
for column_index, column in enumerate(column_labels,0):
print('row_index: %d column_index: %d' %(row_index,column_index))
if row_index==0 and column_index==0:
colors=['indianred','orange','gray']
values=[10,20,30]
else:
values=[45,20,38]
colors=['pink','violet','green']
wedges, text = plt.pie(values,labels=['0', '2', '3'],labeldistance = 0.25,colors=colors)
print('len(wedges):%d wedges: %s, text: %s' %(len(wedges), wedges, text))
radius = 0.45
[w.set_center((column_index,row_index)) for w in wedges]
[w.set_radius(radius) for w in wedges]
# We want to show all ticks...
ax.set_xticks(np.arange(data_array.shape[1]))
ax.set_yticks(np.arange(data_array.shape[0]))
fontsize=10
ax.set_xticklabels(column_labels, fontsize=fontsize)
ax.set_yticklabels(row_labels, fontsize=fontsize)
#X axis labels at top
ax.tick_params(top=True, bottom=False,labeltop=True, labelbottom=False,pad=5)
plt.setp(ax.get_xticklabels(), rotation=55, ha="left", rotation_mode="anchor")
# We want to show all ticks...
ax.set_xticks(np.arange(data_array.shape[1]+1)-.5, minor=True)
ax.set_yticks(np.arange(data_array.shape[0]+1)-.5, minor=True)
ax.grid(which="minor", color="black", linestyle='-', linewidth=2)
ax.tick_params(which="minor", bottom=False, left=False)
data_array=np.random.rand(3,4)
row_labels=['Row1', 'Row2', 'Row3']
column_labels=['Column1', 'Column2', 'Column3','Column4']
fig, ax = plt.subplots(figsize=(1.9*len(column_labels),1.2*len(row_labels)))
ax.set_aspect(1.0)
ax.set_facecolor('white')
heatmap_with_circles(data_array,row_labels,column_labels, ax=ax)
plt.tight_layout()
plt.show()
After updating heatmap_with_circles
def heatmap_with_circles(data_array,row_labels,column_labels,ax=None, cmap=None, norm=None, cbar_kw={}, cbarlabel="", **kwargs):
labels = ['x', 'y', 'z']
for row_index, row in enumerate(row_labels,0):
for column_index, column in enumerate(column_labels,0):
print('row_index: %d column_index: %d' %(row_index,column_index))
if row_index==0 and column_index==0:
colors=['indianred','orange','gray']
values=[10,20,30]
else:
values=[45,20,38]
colors=['pink','violet','green']
# wedges, texts = plt.pie(values,labels=['0', '2', '3'],labeldistance = 0.45,colors=colors)
wedges, texts = plt.pie(values,labeldistance = 0.25,colors=colors)
print('text:%s len(wedges):%d wedges: %s' %(texts, len(wedges), wedges))
radius = 0.45
[w.set_center((column_index,row_index)) for w in wedges]
[w.set_radius(radius) for w in wedges]
[text.set_position((text.get_position()[0]+column_index,text.get_position()[1]+row_index)) for text in texts]
[text.set_text(labels[text_index]) for text_index, text in enumerate(texts,0)]
I got the following image :)
You could loop through the texts of each pie, get its xy position, add column_index and row_index, and set that as new position.
Some small changes to the existing code:
ax.grid(which="minor", ..., clip_on=False) to make sure the thick lines are shown completely, also near the border
ax.set_xlim(xmin=-0.5) to set the limits
import matplotlib.pyplot as plt
import numpy as np
def heatmap_with_circles(data_array, row_labels, column_labels, ax=None):
ax = ax or plt.gca()
for row_index, row in enumerate(row_labels, 0):
for column_index, column in enumerate(column_labels, 0):
colors = np.random.choice(['indianred', 'orange', 'gray', 'pink', 'violet', 'green'], 3, replace=False)
values = np.random.randint(10, 41, 3)
wedges, text = plt.pie(values, labels=['1', '2', '3'], labeldistance=0.25, colors=colors)
radius = 0.45
for w in wedges:
w.set_center((column_index, row_index))
w.set_radius(radius)
w.set_edgecolor('white')
# w.set_linewidth(1)
for t in text:
x, y = t.get_position()
t.set_position((x + column_index, y + row_index))
# We want to show all ticks...
ax.set_xticks(np.arange(data_array.shape[1]))
ax.set_yticks(np.arange(data_array.shape[0]))
fontsize = 10
ax.set_xticklabels(column_labels, fontsize=fontsize)
ax.set_yticklabels(row_labels, fontsize=fontsize)
# X axis labels at top
ax.tick_params(top=True, bottom=False, labeltop=True, labelbottom=False, pad=5)
plt.setp(ax.get_xticklabels(), rotation=55, ha="left", rotation_mode="anchor")
# We want to show all minor ticks...
ax.set_xticks(np.arange(data_array.shape[1] + 1) - .5, minor=True)
ax.set_yticks(np.arange(data_array.shape[0] + 1) - .5, minor=True)
ax.set_xlim(xmin=-.5)
ax.set_ylim(ymin=-.5)
ax.grid(which="minor", color="black", linestyle='-', linewidth=2, clip_on=False)
ax.tick_params(axis="both", which="both", length=0) # hide tick marks
data_array = np.random.rand(3, 4)
row_labels = ['Row1', 'Row2', 'Row3']
column_labels = ['Column1', 'Column2', 'Column3', 'Column4']
fig, ax = plt.subplots(figsize=(1.9 * len(column_labels), 1.2 * len(row_labels)))
ax.set_aspect(1.0)
ax.set_facecolor('white')
heatmap_with_circles(data_array, row_labels, column_labels, ax=ax)
plt.tight_layout()
plt.show()

How to change the position of some x axis tick labels on top of the bottom x axis in matplotlib?

This is my current script:
#!/usr/bin/env python3
import math
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
"""
Setup for a typical explanatory-style illustration style graph.
"""
h = 2
x = np.linspace(-np.pi, np.pi, 100)
y = 2 * np.sin(x)
rc = {
# Tick in the middle of the axis line.
'xtick.direction' : 'inout',
'ytick.direction' : 'inout',
# Bold is easier to read when we have few ticks.
'font.weight': 'bold',
'xtick.labelbottom': False,
'xtick.labeltop': True,
}
with plt.rc_context(rc):
fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_title(
'2 sin(x), not $\\sqrt{2\\pi}$',
# TODO make LaTeX part bold?
# https://stackoverflow.com/questions/14324477/bold-font-weight-for-latex-axes-label-in-matplotlib
fontweight='bold',
# Too close otherwise.
# https://stackoverflow.com/questions/16419670/increase-distance-between-title-and-plot-in-matplolib/56738085
pad=20
)
# Custom visible plot area.
# ax.set_xlim(-3, 3)
ax.set_ylim(-2.5, 2.5)
# Axes
# Axes on center:
# https://stackoverflow.com/questions/31556446/how-to-draw-axis-in-the-middle-of-the-figure
ax.spines['left'].set_position('zero')
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_visible(False)
# Axes with arrow:
# https://stackoverflow.com/questions/33737736/matplotlib-axis-arrow-tip
ax.plot(1, 0, ls="", marker=">", ms=10, color="k",
transform=ax.get_yaxis_transform(), clip_on=False)
ax.plot(0, 1, ls="", marker="^", ms=10, color="k",
transform=ax.get_xaxis_transform(), clip_on=False)
# Ticks
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
# Make ticks a bit longer.
ax.tick_params(width=1, length=10)
# Select tick positions
# https://stackoverflow.com/questions/12608788/changing-the-tick-frequency-on-x-or-y-axis-in-matplotlib
xticks = np.arange(math.ceil(min(x)), math.floor(max(x)) + 1, 1)
yticks = np.arange(math.ceil(min(y)) - 1, math.floor(max(y)) + 2, 1)
# Remove 0.
xticks = np.setdiff1d(xticks, [0])
yticks = np.setdiff1d(yticks, [0])
ax.xaxis.set_ticks(xticks)
ax.yaxis.set_ticks(yticks)
# Another approach. But because I want to be able to remove the 0,
# anyways, I just explicitly give all ticks instead.
# ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(1.0))
# ax.yaxis.set_major_locator(matplotlib.ticker.MultipleLocator(1.0))
# Annotations.
ax.plot([0, np.pi/2], [h, h], '--r')
ax.plot([np.pi/2, np.pi/2], [h, 0], '--r')
ax.plot(np.pi/2, h, marker='o', linewidth=2, markersize=10,
markerfacecolor='w', markeredgewidth=1.5, markeredgecolor='black')
plt.savefig(
'main.png',
format='png',
bbox_inches='tight'
)
plt.clf()
And this is the output:
And this is what I want (hacked with GIMP), notice how the negative tick labels are on a different side of the axes now.
I tried adding:
for tick in ax.xaxis.get_majorticklabels():
tick.set_verticalalignment("bottom")
as shown in answers to: How to move a tick's label in matplotlib? but that does not move the tick labels up enough, and makes the labels show on top of the axes instead.
Tested on matplotlib 3.2.2.
The following code will adjust the vertical alignment of the ticks depending one whether they are at a negative or positive x-value. However that's not enough because the labels are actually anchored at the bottom of the tick line. I'm therefore adjusting their y-position a little bit, but you have to play with the value to get the desired output
# adjust the xticks so that they are on top when x<0 and on the bottom when x≥0
ax.spines['top'].set_visible(True)
ax.spines['top'].set_position('zero')
ax.spines['bottom'].set_visible(True)
ax.spines['bottom'].set_position('zero')
ax.xaxis.set_tick_params(which='both', top=True, labeltop=True,
bottom=True, labelbottom=True)
fig.canvas.draw()
for tick in ax.xaxis.get_major_ticks():
print(tick.get_loc())
if tick.get_loc()<0:
tick.tick1line.set_visible(False)
tick.label1.set_visible(False)
else:
tick.tick2line.set_visible(False)
tick.label2.set_visible(False)
full code:
import math
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
"""
Setup for a typical explanatory-style illustration style graph.
"""
h = 10
x = np.linspace(-np.pi, np.pi, 100)
y = h * np.sin(x)
rc = {
# Tick in the middle of the axis line.
'xtick.direction' : 'inout',
'ytick.direction' : 'inout',
# Bold is easier to read when we have few ticks.
'font.weight': 'bold',
'xtick.labelbottom': False,
'xtick.labeltop': True,
}
with plt.rc_context(rc):
fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_title(
'2 sin(x), not $\\sqrt{2\\pi}$',
# TODO make LaTeX part bold?
# https://stackoverflow.com/questions/14324477/bold-font-weight-for-latex-axes-label-in-matplotlib
fontweight='bold',
# Too close otherwise.
# https://stackoverflow.com/questions/16419670/increase-distance-between-title-and-plot-in-matplolib/56738085
pad=20
)
# Custom visible plot area.
# ax.set_xlim(-3, 3)
ax.set_ylim(-2.5, 2.5)
# Axes
# Axes on center:
# https://stackoverflow.com/questions/31556446/how-to-draw-axis-in-the-middle-of-the-figure
ax.spines['left'].set_position('zero')
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_visible(False)
# Axes with arrow:
# https://stackoverflow.com/questions/33737736/matplotlib-axis-arrow-tip
ax.plot(1, 0, ls="", marker=">", ms=10, color="k",
transform=ax.get_yaxis_transform(), clip_on=False)
ax.plot(0, 1, ls="", marker="^", ms=10, color="k",
transform=ax.get_xaxis_transform(), clip_on=False)
# Ticks
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
# Make ticks a bit longer.
ax.tick_params(width=1, length=10)
# Select tick positions
# https://stackoverflow.com/questions/12608788/changing-the-tick-frequency-on-x-or-y-axis-in-matplotlib
xticks = np.arange(math.ceil(min(x)), math.floor(max(x)) + 1, 1)
yticks = np.arange(math.ceil(min(y)) - 1, math.floor(max(y)) + 2, 1)
# Remove 0.
xticks = np.setdiff1d(xticks, [0])
yticks = np.setdiff1d(yticks, [0])
ax.xaxis.set_ticks(xticks)
ax.yaxis.set_ticks(yticks)
# Another approach. But because I want to be able to remove the 0,
# anyways, I just explicitly give all ticks instead.
# ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(1.0))
# ax.yaxis.set_major_locator(matplotlib.ticker.MultipleLocator(1.0))
for g,t in zip(ax.get_xticks(),ax.get_xticklabels()):
if g<0:
t.set_va('bottom')
else:
t.set_va('top')
t.set_transform(ax.transData)
t.set_position((g,0.15*-(g/abs(g))))
# Annotations.
ax.plot([0, np.pi/2], [h, h], '--r')
ax.plot([np.pi/2, np.pi/2], [h, 0], '--r')
ax.plot(np.pi/2, h, marker='o', linewidth=2, markersize=10,
markerfacecolor='w', markeredgewidth=1.5, markeredgecolor='black')
# adjust the xticks so that they are on top when x<0 and on the bottom when x≥0
ax.spines['top'].set_visible(True)
ax.spines['top'].set_position('zero')
ax.spines['bottom'].set_visible(True)
ax.spines['bottom'].set_position('zero')
ax.xaxis.set_tick_params(which='both', top=True, labeltop=True,
bottom=True, labelbottom=True)
fig.canvas.draw()
for tick in ax.xaxis.get_major_ticks():
print(tick.get_loc())
if tick.get_loc()<0:
tick.tick1line.set_visible(False)
tick.label1.set_visible(False)
else:
tick.tick2line.set_visible(False)
tick.label2.set_visible(False)

Sorting out labels in subplots, created with fig.add_axes

I am new to python and am currently playing around with mathplotlib. Below is my code for the plot, shown on the bottom figure.
import matplotlib.pyplot as plt
f = plt.figure(figsize=(15, 15))
ax1 = f.add_axes([0.1, 0.5, 0.8, 0.5],
xticklabels=[])
ax2 = f.add_axes([0.1, 0.4, 0.8, 0.1])
ax1.plot(particles[0, :, 0])
ax1.plot(particles[1, :, 0])
ax2.plot(distances[:])
# Prettifying the plot
plt.xlabel("t", fontsize=25)
plt.tick_params( # modifying plot ticks
axis='x',
labelsize=20)
plt.ylabel("x", fontsize=25)
plt.tick_params( # modifying plot ticks
axis='y',
labelsize=20)
# Plot title
plt.title('Harmonic oscillator in ' + str(dim) + 'D with ' + str(num_step) + ' timesteps', fontsize=30)
# Saving the plot
#plt.savefig("results/2D_dif.png")
The two graphs have the dimensions and positions as I wish, but as you can see, the labels and the title are off. I wish to have the same label style, as was applied to the bottom plot, with the y-label of the upper plot reading "x", and the title "Harmonic oscillator ..." being on top of the first graph.
I thank you kindly for your help!
Here plt is acting on the most recently created axes instance (ax2 in this case). This is why the fonts haven't changed for ax1!
So, to get what you want you need to explicitly act on both ax1 and ax2. Something like the following should do the trick:
for ax in ax1, ax2:
# Prettifying the plot
ax.set_xlabel("t", fontsize=25)
ax.tick_params( # modifying plot ticks
axis='x',
labelsize=20)
ax.set_ylabel("x", fontsize=25)
ax.tick_params( # modifying plot ticks
axis='y',
labelsize=20)
# Plot title
ax.set_title('Harmonic oscillator in ' + str(dim) + 'D with ' + str(num_step) + ' timesteps', fontsize=30)