In this figure, in the 1st plot, the grid divides the plot in "windows" and each window is divided in subwindows (made with let's say 5 data).
Then the slope of each subwindow is calculated and saved.
Next I divide the polar plane in 16 quadrants and calculate which quadrant correspond to each slope. So, I get something like this:
1,1,1,1,1,1,1,1,1,1,1,2,2,2,3,4
4,1,-1,-2,...
In the dataset above, each number is the quadrant that represents the slope of a subwindow and each row represents a window (The histograms are calculated with this dataset).
What I'm looking for is that the figure at the top, the 2nd plot shows the histogram of each window under its corresponding window.
All I could get is this from the matplotlib page but none of those examples are close to what I need because I need the histograms next to each other without blocking each other.
Sometimes, depending on the parameters used, it could be more than 800 histograms in the same plot.
Here's an example of how you can display multiple plots side-by-side below a larger one using Gridspec:
import numpy as np
import matplotlib.pyplot as plt
# generate some data
x = np.arange(0, 10, 0.2)
y = np.sin(x)
# plot it
fig = plt.figure(figsize=(8, 6))
ax0 = plt.subplot2grid((2, 4), (0, 0), colspan=4)
ax0.plot(x, y)
ax1 = plt.subplot2grid((2, 4), (1, 0))
ax1.hist(y)
ax2 = plt.subplot2grid((2, 4), (1, 1))
ax2.hist(y)
ax2.set_yticklabels([])
ax2.set_yticks([])
ax3 = plt.subplot2grid((2, 4), (1, 2))
ax3.hist(y)
ax3.set_yticklabels([])
ax3.set_yticks([])
ax4 = plt.subplot2grid((2, 4), (1, 3))
ax4.hist(y)
ax4.set_yticklabels([])
ax4.set_yticks([])
plt.subplots_adjust(wspace=0) # no space left between hists in 2nd row
Results in:
Related
I am using the Subplot2Grid functionality within Matplotlib to combine two figures with different orientations, 4 bar plots (full width) and then 3 scatter plots splitting the full width into 3 columns, plus an extra space for a legend. The different sections have axes that need to align so I have used sharex = ax1 and sharey = ax1 within Subplot2Grid to implement this successfully.
However, I now cannot seem to control the axis labels the same as I would just using regular subplots function, having the x-axis tick labels showing only on the final bar plot and the y-axis tick labels showing only on the left-most scatter plot.
Plotting using Subplot2Grid, extra axis labels showing
I have tried the ax.set_xticklabels('') to try and switch them off, but the sharex/sharey seems to override them? I have also put the ax.set_xticklabels('') at the end of the code (after they are defined in ax4) and it switches them all off, not just the axis the one that is called (ax1, ax2 or ax3)
Relevant parts of the code are below:
# figure setup
fig = plt.figure()
fig.set_figheight(15)
fig.set_figwidth(9)
ax1 = plt.subplot2grid(shape=(6, 3), loc=(0, 0), colspan=3)
ax2 = plt.subplot2grid(shape=(6, 3), loc=(1, 0), colspan=3,sharex=ax1)
ax3 = plt.subplot2grid(shape=(6, 3), loc=(2, 0), colspan=3,sharex=ax1)
ax4 = plt.subplot2grid(shape=(6, 3), loc=(3, 0), colspan=3,sharex=ax1)
ax5 = plt.subplot2grid(shape=(6, 3), loc=(5, 0))
ax6 = plt.subplot2grid(shape=(6, 3), loc=(5, 1),sharex=ax5,sharey=ax5)
ax7 = plt.subplot2grid(shape=(6, 3), loc=(5, 2),sharex=ax5,sharey=ax5)
# plotting bars here
# first bar plot
ax1.set_title('Inundation area')
ax1.set_xticklabels('')
ylbl0 = 'Inundation area \n' + r'$(km^2)$'
ax1.set_ylabel(ylbl0)
# repeat for ax2 & ax3
# last bar plot
ax4.set_title(r'$\Delta$ Shear Stress')
ax4.set_xticks(np.arange(len(df_bars)))
ax4.set_xticklabels(df_bars['Reach Number'])
ax4.invert_xaxis()
ax4.axhline(y=0,c='k',lw = 0.5)
ax4.set_xlabel('Reach number')
ax4.set_ylabel('% change \n (2019-2020)')
Same occurs when using sharey for the 3 scatter plots and ax.set_yticklabels('')
ax1.tick_params(labelbottom=False)
does what you want.
This example works for me:
fig = plt.figure()
fig.set_figheight(15)
fig.set_figwidth(9)
ax1 = plt.subplot2grid(shape=(2, 1), loc=(0, 0), colspan=3)
ax1.plot(np.random.rand(10))
ax2 = plt.subplot2grid(shape=(2, 1), loc=(1, 0), colspan=3,sharex=ax1)
ax2.plot(np.random.rand(10))
ax1.tick_params(labelbottom=False)
plt.show()
Is there any way to create a plot with matplotlib so when the window is maximized, the plot only occupies a strip of the screen? As an example, please consider the example below. In this case, I want to arrange the 3 subplots in an horizontal line, and I would like to keep the size small, that is why I added 2 rows with blank subplots. When I use figsize the window that pops does have the specified size, but once it's maximized, matplotlib re-fits the subplots to occupy the entire screen. I would like matplotlib to redraw the contents to fit this "strip", not the other way round.
Thus, is it possible to create the strip directly, without un-wanted resizes from matplotlib and without adding all these innecessary blank subplots to do the trick?
Thanks!
EDIT
I am running this program using Python 3.5 and Matplotlib 2.2.3. The interactive backend is TkAgg.
Matplotlib's subplot grids are positionned in units relative to the figure size. Positionning subplots in absolute coordinates hence requires some tweaking.
You could define the width and height of the grid in inches and then calculate the margins of the grid each time the figure is resized.
In the following the grid always stays 4 inch wide and 1 inch tall, no matter the figure size.
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(42)
fig, axes = plt.subplots(ncols=3, sharey=True)
for ax in axes:
ax.plot(np.arange(30), np.cumsum(np.random.randn(30)))
# set width and height in physical units (inches)
width = 4 # inch
height= 1 # inch
def resize(evt=None):
w,h = fig.get_size_inches()
l = ((w-width)/2.)/w
b = ((h-height)/2.)/h
fig.subplots_adjust(left=l, right=1.-l, bottom=b, top=1.-b)
fig.canvas.draw_idle()
resize()
fig.canvas.mpl_connect("resize_event", resize)
plt.show()
You didn't explain about your visualisation approach.
So according to me you can try subplot for it.
see how subplot works here (https://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.subplot)
from matplotlib import pyplot as PLT
fig = PLT.figure()
ax1 = fig.add_subplot(211)
ax1.plot([(1, 2), (3, 4)], [(4, 3), (2, 3)])
ax2 = fig.add_subplot(221)
ax2.plot([(7, 2), (5, 3)], [(1, 6), (9, 5)])
ax3 = fig.add_subplot(222)
ax3.plot([(7, 2), (5, 3)], [(1, 6), (9, 5)])
PLT.show()
I am new to python and having some difficulties with plotting using pyplot. My goal is to plot a grid of plots in-line (%pylab inline) in Juypter Notebook.
I programmed a function plot_CV which plots cross-validation erorr over the degree of polynomial of some x where across plots the degree of penalization (lambda) is supposed to vary. Ultimately there are 10 elements in lambda and they are controlled by the first argument in plot_CV. So
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
ax1 = plot_CV(1,CV_ve=CV_ve)
Gives
Now I think I have to use add_subplot to create a grid of plots as in
fig = plt.figure()
ax1 = fig.add_subplot(2,2,1)
ax1 = plot_CV(1,CV_ve=CV_ve)
ax2 = fig.add_subplot(2,2,2)
ax2 = plot_CV(2,CV_ve=CV_ve)
ax3 = fig.add_subplot(2,2,3)
ax3 = plot_CV(3,CV_ve=CV_ve)
ax4 = fig.add_subplot(2,2,4)
ax4 = plot_CV(4,CV_ve=CV_ve)
plt.show()
If I continue this, however, then the plots get smaller and smaller and start to overlap on the x and y labels. Here a picture with a 3 by 3 plot.
Is there a way to space the plots evenly, so that they do not overlap and make better use of the horizontal and vertical in-line space in Jupyter Notebook? To illustrate this point here a screenshot from jupyter:
Final note: I still need to add a title or annotation with the current level of lambda used in plot_CV.
Edit: Using the tight layout as suggested, gives:
Edit 2: Using the fig.set_figheight and fig.set_figwidth I could finally use the full length and heigth available.
The first suggestion to your problem would be taking a look at the "Tight Layout guide" for matplotlib.
They have an example that looks visually very similar to your situation. As well they have examples and suggestions for taking into consideration axis labels and plot titles.
Furthermore you can control the overall figure size by using Figure from the matplotlib.figure class.
Figure(figsize = (x,y))
figsize: x,y (inches)
EDIT:
Here is an example that I pulled from the matplotlib website and added in the:
fig.set_figheight(15)
fig.set_figwidth(15)
example:
import matplotlib.pyplot as plt
plt.rcParams['savefig.facecolor'] = "0.8"
def example_plot(ax, fontsize=12):
ax.plot([1, 2])
ax.locator_params(nbins=3)
ax.set_xlabel('x-label', fontsize=fontsize)
ax.set_ylabel('y-label', fontsize=fontsize)
ax.set_title('Title', fontsize=fontsize)
plt.close('all')
fig = plt.figure()
fig.set_figheight(15)
fig.set_figwidth(15)
ax1 = plt.subplot2grid((3, 3), (0, 0))
ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2)
ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2)
ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)
example_plot(ax1)
example_plot(ax2)
example_plot(ax3)
example_plot(ax4)
plt.tight_layout()
You can achieve padding of your subplots by using tight_layout this way:
plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0)
That way you can keep your subplots from crowding each other even further.
Have a good one!
I would like to have plot with an y axis that is devided into two parts. The lower part should have a normal scale while the upper one should scale with a factor of 10.
I already found some examples on how to make plots with broken x or y axes, for example:
http://matplotlib.org/examples/pylab_examples/broken_axis.html
But I do not understand how to achieve this, when I want to apply this to one single subplot inside a 2x2 grid of plots. If it is important, I set up the plots like this:
fig = plt.figure()
fig.set_size_inches(8, 6)
fig.add_subplot(221)
[...]
fig.add_subplot(222)
[...]
You could use gridspec to layout the shape and location of the axes:
import numpy as np
import matplotlib.gridspec as gridspec
import matplotlib.pyplot as plt
gs = gridspec.GridSpec(4, 2)
ax00 = plt.subplot(gs[:2, 0])
ax01 = plt.subplot(gs[:2, 1])
ax10a = plt.subplot(gs[2, 0])
ax10b = plt.subplot(gs[3, 0])
ax11 = plt.subplot(gs[2:, 1])
x = np.linspace(-1, 1, 500)
y = 100*np.cos(10*x)**2*np.exp(-x**2)
for ax in (ax00, ax01, ax10a, ax10b, ax11):
ax.plot(x, y)
ax10a.set_ylim(60, 110)
ax10b.set_ylim(0, 10)
ax10a.spines['bottom'].set_visible(False)
ax10b.spines['top'].set_visible(False)
ax10a.xaxis.tick_top()
ax10a.tick_params(labeltop='off') # don't put tick labels at the top
ax10b.xaxis.tick_bottom()
d = .015 # how big to make the diagonal lines in axes coordinates
# arguments to pass plot, just so we don't keep repeating them
kwargs = dict(transform=ax10a.transAxes, color='k', clip_on=False)
ax10a.plot((-d,+d),(-d,+d), **kwargs) # top-left diagonal
ax10a.plot((1-d,1+d),(-d,+d), **kwargs) # top-right diagonal
kwargs.update(transform=ax10b.transAxes) # switch to the bottom axes
ax10b.plot((-d,+d),(1-d,1+d), **kwargs) # bottom-left diagonal
ax10b.plot((1-d,1+d),(1-d,1+d), **kwargs) # bottom-right diagonal
plt.tight_layout()
plt.show()
Couldn't you set up a 4x4 grid of axes, and have 3 of the axes span 2x2 of that space? Then the plot you want to have broken axes on can just cover the remaining 2x2 space as parts ax4_upper and ax4_lower.
ax1 = plt.subplot2grid((4, 4), (0, 0), colspan=2, rowspan=2)
ax2 = plt.subplot2grid((4, 4), (0, 2), colspan=2, rowspan=2)
ax3 = plt.subplot2grid((4, 4), (2, 0), colspan=2, rowspan=2)
ax4_upper = plt.subplot2grid((4, 4), (2, 2), colspan=2, rowspan=1)
ax4_lower = plt.subplot2grid((4, 4), (3, 2), colspan=2, rowspan=1)
You can then set the ylim values for ax4_upper and ax4_lower, and continue as your example showed:
# hide the spines between ax4 upper and lower
ax4_upper.spines['bottom'].set_visible(False)
ax4_lower.spines['top'].set_visible(False)
ax4_upper.xaxis.tick_top()
ax4_upper.tick_params(labeltop='off') # don't put tick labels at the top
ax4_lower.xaxis.tick_bottom()
d = .015 # how big to make the diagonal lines in axes coordinates
# arguments to pass plot, just so we don't keep repeating them
kwargs = dict(transform=ax4_upper.transAxes, color='k', clip_on=False)
ax4_upper.plot((-d,+d),(-d,+d), **kwargs) # top-left diagonal
ax4_upper.plot((1-d,1+d),(-d,+d), **kwargs) # top-right diagonal
kwargs.update(transform=ax4_lower.transAxes) # switch to the bottom axes
ax4_lower.plot((-d,+d),(1-d,1+d), **kwargs) # bottom-left diagonal
ax4_lower.plot((1-d,1+d),(1-d,1+d), **kwargs) # bottom-right diagonal
plt.show()
I am currently attempting to use passed axis object created in function, e.g.:
def drawfig_1():
import matplotlib.pyplot as plt
# Create a figure with one axis (ax1)
fig, ax1 = plt.subplots(figsize=(4,2))
# Plot some data
ax1.plot(range(10))
# Return axis object
return ax1
My question is, how can I use the returned axis object, ax1, in another figure? For example, I would like to use it in this manner:
# Setup plots for analysis
fig2 = plt.figure(figsize=(12, 8))
# Set up 2 axes, one for a pixel map, the other for an image
ax_map = plt.subplot2grid((3, 3), (0, 0), rowspan=3)
ax_image = plt.subplot2grid((3, 3), (0, 1), colspan=2, rowspan=3)
# Plot the image
ax_psf.imshow(image, vmin=0.00000001, vmax=0.000001, cmap=cm.gray)
# Plot the map
???? <----- #I don't know how to display my passed axis here...
I've tried statements such as:
ax_map.axes = ax1
and although my script does not crash, my axis comes up empty. Any help would be appreciated!
You are trying to make a plot first and then put that plot as a subplot in another plot (defined by subplot2grid). Unfortunately, that is not possible. Also see this post: How do I include a matplotlib Figure object as subplot?.
You would have to make the subplot first and pass the axis of the subplot to your drawfig_1() function to plot it. Of course, drawfig_1() will need to be modified. e.g:
def drawfig_1(ax1):
ax1.plot(range(10))
return ax1
# Setup plots for analysis
fig2 = plt.figure(figsize=(12, 8))
# Set up 2 axes, one for a pixel map, the other for an image
ax_map = plt.subplot2grid((3, 3), (0, 0), rowspan=3)
ax_image = plt.subplot2grid((3, 3), (0, 1), colspan=2, rowspan=3)
# Plot the image
ax_image.imshow(image, vmin=0.00000001, vmax=0.000001, cmap=cm.gray)
# Plot the map:
drawfig_1(ax_map)