3D subplots spacing in PyPlot - python

I want to increase the size of the 3d subplots to occupy most of the empty white space. I am using Gridspec (maybe I'm not using it properly?). I have posted the minimal working example and the output image. You can see the plot is big, but the 3D subplots are smaller with a lot of space between them. How do I increase the size of each subplot to occupy all that empty space?
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(16, 17))
gs = gridspec.GridSpec(6, 4)
ax1 = fig.add_subplot(gs[0:2, 0:2], projection='3d')
ax2 = fig.add_subplot(gs[0:2,2:], projection='3d')
ax3 = fig.add_subplot(gs[2:4,0:2], projection='3d')
ax4 = fig.add_subplot(gs[2:4,2:], projection='3d')
ax5 = fig.add_subplot(gs[4:6,1:3], projection='3d')
axs = [ax1,ax2,ax3,ax4,ax5]
for ax in axs:
ax.set_xlabel('$\psi_2$', fontname='sans serif', fontsize=20)
ax.set_ylabel('$\psi_3$', fontname='sans serif', fontsize=20)
ax.set_zlabel('$\psi_4$', fontname='sans serif', fontsize=20)
ax.view_init(elev=28., azim=81)
plt.tight_layout()
gs.tight_layout(fig)
plt.show()

You can deactivate the tight layout and set each interval to a minimum of 0 horizontally and vertically. Negative values will cause each graph to overlap.
# plt.tight_layout()
# gs.tight_layout(fig)
fig.subplots_adjust(wspace=0, hspace=0)

Related

How to set space between plot and colormap table

I am using secondary y-axis and cmap color but when I plot together the color bar cross to my plot
here is my code
fig,ax1=plt.subplots()
ax1 = df_Combine.plot.scatter('Parameter2', 'NPV (MM €)', marker='s', s=500, ylim=(-10,60), c='Lifetime1 (a)', colormap='jet_r', vmin=0, vmax=25, ax=ax1)
graph.axhline(0, color='k')
plt.xticks(rotation=90)
ax2 = ax1.twinx()
ax2.plot(df_Combine_min_select1["CumEnergy1 (kWH)"])
plt.show()
and here is my plotting
anyone can help how to solve this issue?
Thank you
When you let pandas automatically create a colorbar, you don't have positioning options. Therefore, you can create the colorbar in a separate step and provide the pad= parameter to set a wider gap. Default, pad is 0.05, meaning 5% of the width of the subplot.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
fig, ax1 = plt.subplots()
df_Combine = pd.DataFrame({'Parameter2': np.random.rand(10) * 10,
'NPV (MM €)': np.random.rand(10),
'Lifetime1 (a)': np.random.rand(10) * 25,
})
ax1 = df_Combine.plot.scatter('Parameter2', 'NPV (MM €)', marker='s', s=500, ylim=(-10, 60), c='Lifetime1 (a)',
colormap='jet_r', vmin=0, vmax=25, ax=ax1, colorbar=False)
plt.colorbar(ax1.collections[0], ax=ax1, pad=0.1)
ax2 = ax1.twinx()
ax2.plot(np.random.rand(10))
plt.show()

How do you add a background image on a scatter plot in loglog axes in python?

How do you add a Background Image on a scatter plot with loglog axes? My problem is that the background image is also rescaled in log style which I don't want.
ax3 = fig2.add_subplot(1, 1, 1)
pathimage=directory+'\Robertson.PNG'
img = mpimg.imread(directory+'\Robertson.PNG')
ax3.scatter(rf_layer,qc_layer)
ax3.set_title(filename, y=1.1,fontsize=12)
ax3.set_yscale('log')
ax3.set_xscale('log')
ax3.legend(Legend,loc=9, bbox_to_anchor=(0.5, -0.2),ncol=len(layerdepth))
ax3.set_ylim([1, 100])
ax3.set_xlim([0.1, 10])
ax3.set_xlabel('Rf in %')
ax3.set_ylabel('qc in MPa')
ax3.imshow(img,extent=[0.1,10,1,100])
You can do this with a twin Axes, which is not set to loglog scale. In this case, we want to make both twin x and y axes, so we can stack the commands, as shown here:
ax4 = ax3.twinx().twiny()
An alternative is to just create a new Axes instance in the same position as the first (from #ImportanceOfBeingErnest in the comments). For example:
ax4 = fig.add_subplot(111, label="ax4")
We also need to make ax3 transparent so we can see through it to the image below (facecolor='None').
We also need to set the zorder to ax3 is on top of ax4.
Here is a working example:
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
# Dummy data
rf_layer = 0.1 + np.random.rand(20) * 9.9
qc_layer = 1. + np.random.rand(20) * 99.
fig2 = plt.figure()
# Make ax3 transparent so we can see image behind
ax3 = fig2.add_subplot(1, 1, 1, facecolor='None')
pathimage='./stinkbug.png'
img = mpimg.imread(pathimage)
ax3.scatter(rf_layer, qc_layer)
ax3.set_title('my title', y=1.1, fontsize=12)
ax3.set_yscale('log')
ax3.set_xscale('log')
ax3.set_ylim([1, 100])
ax3.set_xlim([0.1, 10])
ax3.set_xlabel('Rf in %')
ax3.set_ylabel('qc in MPa')
# Create second axes
ax4 = ax3.twinx().twiny()
# Or alternatively
# ax4 = fig.add_subplot(111, label="ax4")
# Add image to twin axes
ax4.imshow(img)
# Fix zorder so ax3 on top of ax4
ax3.set_zorder(10)
ax4.set_zorder(1)
# Turn off ticks from twin axes
ax4.set_yticks([])
ax4.set_xticks([])
plt.show()

How to insert the text below subplot in matplotlib?

I am using matplotlib to
#Plot
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure(figsize=(8,8))
gs1 = gridspec.GridSpec(1, 2)
gs1.update(wspace=0.025, hspace=0.05) # set the spacing between axes.
ax1 = plt.subplot(gs1[0])
ax2 = plt.subplot(gs1[1])
ax1.axis('off')
ax1.set_xlabel('(a)')
ax2.axis('off')
ax2.set_xlabel('(b)')
Because I must turn off axis in the figure, hence, I used ax1.axis('off'). Now, I want to insert the figure description such as (a),(b) below each subplot. I used xlabel but it cannot work due to function axis('off'). I can have other options by using .text function, but it requires the known position. In my case, the text must be below and center in each subplot. How can I implement it. Thanks
My expected result is
The problem is if axis("off") is set, the xlabel is removed from the figure (together with all other artists that are part of the axis).
However, you may use some normal text label just below the axes to mimic the xlabel.
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure(figsize=(8,8))
gs1 = gridspec.GridSpec(1, 2)
gs1.update(wspace=0.025, hspace=0.05) # set the spacing between axes.
ax1 = plt.subplot(gs1[0])
ax1.imshow([[0,1],[2,1]])
ax2 = plt.subplot(gs1[1])
ax2.imshow([[2,1],[0,1]])
ax1.axis('off')
ax2.axis('off')
ax1.text(0.5,-0.1, "(a) my label", size=12, ha="center",
transform=ax1.transAxes)
ax2.text(0.5,-0.1, "(b) my other label", size=12, ha="center",
transform=ax2.transAxes)
plt.show()
Changing the -0.1 will give you more or less space between the axes and the text.

How to use twinx and still get square plot

How do I show a plot with twin axes such that the aspect of the top and right axes are 'equal'. For example, the following code will produce a square plot
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.plot([0,1],[0,1])
But this changes as soon as you use the twinx function.
ax2 = ax.twinx()
ax2.set_ylim([0,2])
ax3 = ax.twiny()
ax3.set_xlim([0,2])
Using set_aspect('equal') on ax2 and ax3 seems to force it the the aspect of ax, but set_aspect(0.5) doesn't seem to change anything either.
Put simply, I would like the plot to be square, the bottom and left axes to run from 0 to 1 and the top and right axes to run from 0 to 2.
Can you set the aspect between two twined axes? I've tried stacking the axes:
ax3 = ax2.twiny()
ax3.set_aspect('equal')
I've also tried using the adjustable keyword in set_aspect:
ax.set_aspect('equal', adjustable:'box-forced')
The closest I can get is:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_aspect('equal', adjustable='box-forced')
ax.plot([0,1],[0,1])
ax2=ax.twinx()
ax3 = ax2.twiny()
ax3.set_aspect(1, adjustable='box-forced')
ax2.set_ylim([0,2])
ax3.set_xlim([0,2])
ax.set_xlim([0,1])
ax.set_ylim([0,1])
Which produces:
I would like to remove the extra space to the right and left of the plot
It seems overly complicated to use two different twin axes to get two independent set of axes. If the aim is to create one square plot with one axis on each side of the plot, you may use two axes, both at the same position but with different scales. Both can then be set to have equal aspect ratios.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.plot([0,1],[0,1])
ax2 = fig.add_axes(ax.get_position())
ax2.set_facecolor("None")
ax2.set_aspect('equal')
ax2.plot([2,0],[0,2], color="red")
ax2.tick_params(bottom=0, top=1, left=0, right=1,
labelbottom=0, labeltop=1, labelleft=0, labelright=1)
plt.show()

Plot alignment and formatting help in Matplotlib and Seaborn

I have a dataframe with 15 rows, which I plot using a seaborn heatmap. I have three plots, each with different scale for the heatmap. The first two plots are the first two rows, which are not aligned on the plot.
I have created a grid with 15 rows, I give each of the first two rows 1/15th of the grid so I don't know why it is not aligned.
Another problem with the first two rows of the heatmap is that the text formatting doesn't work either.
So I want to do two things:
Stretch the top two rows of the table to align it with the bottom one and;
To make the formatting work for the top two rows as well.
Maybe also add titles to my white xaxes (l1 and l2) that separate the the subgroups in the bottom plot (standard methods like ax.set_title does not work).
My code:
import seaborn as sns
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.gridspec as gs
gs = gs.GridSpec(15, 1) # nrows, ncols
f = plt.figure(figsize=(10, 15))
cmap = sns.diverging_palette(220, 10, as_cmap=True)
ax1 = f.add_subplot(gs[0:1, :])
ax2 = f.add_subplot(gs[1:2, :])
ax3 = f.add_subplot(gs[2:15, :])
ticksx = plt.xticks(fontsize = 18, fontweight='bold')
ticksy = plt.yticks(fontsize = 18, fontweight='bold')
wageplot = sns.heatmap(df[0:1], vmin=3000, vmax=10000, annot=False, square=True, cmap=cmap, ax=ax1, yticklabels=True, cbar=False, xticklabels=False)
tenureplot = sns.heatmap(df[1:2], vmin=45, vmax=100, annot=True, square=True, cmap=cmap, ax=ax2, yticklabels=True, cbar=False, xticklabels=False)
heatmap = sns.heatmap(df[2:15], vmin=0, vmax=1, annot=False, square=True, cmap=cmap, ax=ax3, yticklabels=True, cbar=True, xticklabels=True)
heatmap.set_xticklabels(cols, rotation=45, ha='right')
l1 = plt.axhline(y=1, linewidth=14, color='w', label='Female')
l2 = plt.axhline(y=5, linewidth=14, color='w', label='Education')
f.tight_layout()
I would appreciate if I can pointed to where can I get some information about how to program the needed grid. An example image:

Categories