This question already has answers here:
How to remove gaps between subplots in matplotlib
(6 answers)
Closed 6 years ago.
I am having quite a bit of trouble understanding how to create good subplots. I want to create a figure that is similar to the one shown below. Does anyone know how I could set up a similar template as this?
Also, how would I include these points with error bars in the subplots?
This is my code for the error bars:
mass, p, errp, errl = np.loadtxt('/Users/shawn/Desktop/vika1.dat', usecols = [0, 10, 11, 12], unpack = True)
plt.errorbar(mass, np.log10(p) - 4, yerr = [np.log10(p) - np.log10(p-errl), np.log10(p + errp) - np.log10(p)], fmt = 'o', markerfacecolor = 'w', markeredgecolor = 'k', ecolor = 'k')
You could use sharex and sharey to share the axes. The following will give the layout you want. You can then plot individual subplots using your specific plot funcitons.
Updated complete code below
import numpy as np
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=2, ncols=2, sharex=True, sharey=True)
X = np.linspace(-np.pi, np.pi, 256, endpoint=True)
C, S = np.cos(X), np.sin(X)
axes[0,0].plot(X, C, color="blue", linewidth=1.0, linestyle="-")
axes[0,1].plot(X, C, color="orange", linewidth=1.0, linestyle="-")
axes[1,0].plot(X, C, color="green", linewidth=1.0, linestyle="-")
axes[1,1].plot(X, C, color="red", linewidth=1.0, linestyle="-")
plt.subplots_adjust(wspace=0,hspace=0)
plt.show()
Can't understand why someone has downvoted me for the initial answer...
The below lines would prune the min value for both x and y axes thereby avoiding label overlaps
from matplotlib.ticker import MaxNLocator
axes[1,1].yaxis.set_major_locator(MaxNLocator(prune='lower'))
axes[1,1].xaxis.set_major_locator(MaxNLocator(prune='lower'))
Related
I have a function that inputs a string (the name of the dataframe we're visualizing) and returns two histograms that visualize that data. The first plot (on the left) is the raw data, the one on the right is it after being normalized (same, just plotted using the matplotlib parameter density=True). But as you can see, this leads to transparency issues when the plots overlap. This is my code for this particular plot:
plt.rcParams["figure.figsize"] = [12, 8]
plt.rcParams["figure.autolayout"] = True
ax0_1 = plt.subplot(121)
_,bins,_ = ax0_1.hist(filtered_0,alpha=1,color='b',bins=15,label='All apples')
ax0_1.hist(filtered_1,alpha=0.9,color='gold',bins=bins,label='Less than two apples')
ax0_1.set_title('Condition 0 vs Condition 1: '+'{}'.format(apple_data),fontsize=14)
ax0_1.set_xlabel('{}'.format(apple_data),fontsize=13)
ax0_1.set_ylabel('Frequency',fontsize=13)
ax0_1.grid(axis='y',linewidth=0.4)
ax0_1.tick_params(axis='x',labelsize=13)
ax0_1.tick_params(axis='y',labelsize=13)
ax0_1_norm = plt.subplot(122)
_,bins,_ = ax0_1_norm.hist(filtered_0,alpha=1,color='b',bins=15,label='All apples',density=True)
ax0_1_norm.hist(filtered_1,alpha=0.9,color='gold',bins=bins,label='Less than two apples',density=True)
ax0_1_norm.set_title('Condition 0 vs Condition 1: '+'{} - Normalized'.format(apple_data),fontsize=14)
ax0_1_norm.set_xlabel('{}'.format(apple_data),fontsize=13)
ax0_1_norm.set_ylabel('Frequency',fontsize=13)
ax0_1_norm.legend(bbox_to_anchor=(2, 0.95))
ax0_1_norm.grid(axis='y',linewidth=0.4)
ax0_1_norm.tick_params(axis='x',labelsize=13)
ax0_1_norm.tick_params(axis='y',labelsize=13)
plt.tight_layout(pad=0.5)
plt.show()
What my current plot looks like
Any ideas on how to make the colors blend a bit better would be helpful. Alternatively, if there are any other combinations you know of that would work instead, feel free to share. I'm not picky about the color choice. Thanks!
I think it is better to emphasize such a histogram by distinguishing it by the shape of the histogram or by the difference in transparency rather than visualizing it by color. I have coded an example from the official reference with additional overlap.
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(20211021)
N_points = 100000
n_bins = 20
x = np.random.randn(N_points)
y = .4 * x + np.random.randn(100000) + 2
fig, axs = plt.subplots(2, 2, sharey=True, tight_layout=True)
# We can set the number of bins with the `bins` kwarg
axs[0,0].hist(x, color='b', alpha=0.9, bins=n_bins, ec='b', fc='None')
axs[0,0].hist(y, color='gold', alpha=0.6, bins=21)
axs[0,0].set_title('edgecolor and facecolor None')
axs[0,1].hist(x, color='b', alpha=0.9, bins=n_bins)
axs[0,1].hist(y, color='gold', alpha=0.6, bins=21, ec='b')
axs[0,1].set_title('edgecolor and facecolor')
axs[1,0].hist(x, alpha=0.9, bins=n_bins, histtype='step', facecolor='b')
axs[1,0].hist(y, color='gold', alpha=0.6, bins=21)
axs[1,0].set_title('step')
axs[1,1].hist(x, color='b', alpha=0.9, bins=n_bins, histtype='bar', rwidth=0.8)
axs[1,1].hist(y, color='gold', alpha=0.6, bins=21, ec='b')
axs[1,1].set_title('bar')
plt.show()
This question already has answers here:
increase the linewidth of the legend lines in matplotlib
(4 answers)
Closed 5 years ago.
What I want to do is a plot of generation and demand in an electricity grid with Matplotlib in Python. This is my code:
fig,ax = plt.subplots(figsize=(14,8))
generation.plot(kind="area", ax=ax, linewidth=1, alpha=0.9)
load.plot(kind="area", ax=ax, linewidth=1, alpha=0.9)
labels = ['Erzeugung', 'Last']
ax.legend(labels, ncol=4, loc="best", markerscale=10)
ax.set_ylabel("GW")
ax.set_xlabel("")
plt.tight_layout()
The result looks like this:
My question is about the markerscale: Why doesn't it work with this kind of plot? The problem is the bad visibility of the marker in the legend, it would be much better with a thicker line or even a box. And this without increasing the line width of the lines. Any ideas?
You can set the line size manually after creation as follows:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
fig, ax = plt.subplots(figsize=(14,8))
generation = pd.DataFrame(np.random.randint(10, 14, 10))
load = pd.DataFrame(np.random.randint(2, 5, 10))
generation.plot(kind="area", ax=ax, linewidth=1, alpha=0.9)
load.plot(kind="area", ax=ax, linewidth=1, alpha=0.9)
labels = ['Erzeugung', 'Last']
legend = ax.legend(labels, ncol=4, loc="best")
for handle in legend.legendHandles:
handle.set_linewidth(3.0)
ax.set_ylabel("GW")
ax.set_xlabel("")
plt.tight_layout()
plt.show()
Giving you something like:
This question already has answers here:
How do I let my matplotlib plot go beyond the axes?
(3 answers)
Closed 5 years ago.
I'm plotting data points using matplotlib.
Basically, I want to plot discrete points. Many of them are placed on the boundaries. However, as shown in the attached figure, the data points on the figure boundary only appears as a half circle rather than a full circle.
Could anyone suggest how to plot those points on the boundary as full circles?
def PlotGrid(grid_point, file_name):
plt.figure()
dims = np.shape(grid_point)
for i in range(0, dims[1]):
for j in range(0, dims[2]):
plt.plot(grid_point[0, i, j], grid_point[1, i, j], 'ro', markersize=15)
Thank you!
Set the plt.plot kwarg clip_on to False, and the points will show up outside the axes.
plt.plot(grid_point[0, i, j], grid_point[1, i, j], 'ro', markersize=15, clip_on=False)
From the docs:
Artist.set_clip_on(b)
Set whether artist uses clipping.
When False artists will be visible out side of the axes which can lead to unexpected results.
ACCEPTS: [True | False]
Here's a minimal example:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1)
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.plot(0, 0, 'ro', markersize=30, clip_on=True, label='clip_on=True')
ax.plot(1, 1, 'bo', markersize=30, clip_on=False, label='clip_on=False')
ax.legend()
plt.show()
Artists can be shown outside the axes by not allowing the axes to clip them, e.g. plt.plot(..., clip_on=False),
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams["figure.figsize"] = (5,4)
plt.figure()
X,Y = np.meshgrid(range(4),range(4))
for i in range(0, 4):
for j in range(0, 4):
plt.plot(X[i,j], Y[i,j], 'ro', markersize=30, clip_on=False)
plt.margins(0.0)
plt.show()
However, it might be better to extend the axes range, such that the artist actually lives completely inside the axes. This can be done using plt.margins().
import matplotlib.pyplot as plt
import numpy as np
plt.figure()
X,Y = np.meshgrid(range(4),range(4))
for i in range(0, 4):
for j in range(0, 4):
plt.plot(X[i,j], Y[i,j], 'ro', markersize=30)
plt.margins(0.1) ## add 10% margin on all sides
plt.show()
I'd like to make a quiver plot without the heads of the arrows. I also want to have borders so that the arrows could stand out of the background color plot. Here is the main part of my code trying to produce such a plot:
plt.quiver(phia[sl1,sl2], R0a[sl1,sl2],u,v, color='white', headlength=0, headwidth = 1, pivot = 'middle', scale = scale, width=width, linewidth = 0.5)
The plot is in polar axis if this matters. This works for most of the lines except for those that are very short. Some artificial tails from the border are produced after the lines in those cases. One of the plots I generated that suffers the most from this is the following:
Any solutions to this problem or suggestions to bypass it will be greatly appreciated! Thanks!
Specifying the headaxislength parameter for the arrows to be zero does the trick:
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(0, 2*np.pi, 16)
r = np.linspace(0, 1, 6)
x = np.cos(theta)[:,np.newaxis]*r
y = np.sin(theta)[:,np.newaxis]*r
quiveropts = dict(color='white', headlength=0, pivot='middle', scale=3,
linewidth=.5, units='xy', width=.05, headwidth=1) # common options
f, (ax1, ax2) = plt.subplots(1,2, sharex=True, sharey=True)
ax1.quiver(x,y, -y, x, headaxislength=4.5, **quiveropts) # the default
ax2.quiver(x,y, -y, x, headaxislength=0, **quiveropts)
The code above results in the following quiverplots, without arrowheads.
I am trying to set the x and y limits on a subplot but am having difficultly. I suspect that the difficultly stems from my fundamental lack of understanding of how figures and subplots work. I have read these two questions:
question 1
question 2
I tried to use that approach, but neither had any effect on the x and y limits. Here's my code:
fig = plt.figure(figsize=(9,6))
ax = plt.subplot(111)
ax.hist(sub_dict['b'], bins=30, color='r', alpha=0.3)
ax.set_ylim=([0,200])
ax.set_xlim=([0,100])
plt.xlabel('x')
plt.ylabel('y')
plt.title('title')
plt.show()
I am confused as whether to apply commands to fig or ax? For instance .xlabel and .title don't seem to be available for ax. Thanks
Why don't you do:
Ax = fig.add_subplot(111)
import matplotlib.pyplot as plt
import numpy as np
mu, sigma = 100, 15
x = mu + sigma*np.random.randn(100)
fig = plt.figure(figsize=(9,6))
ax = fig.add_subplot(111)
ax.hist(x, bins=30, color='r', alpha=0.3)
ax.set_ylim=(0, 200)
ax.set_xlim=(0, 100)
plt.xlabel('x')
plt.ylabel('y')
plt.title('title')
plt.show()
I've run your code on some sample code, and I'm attaching the screenshot. I'm not sure this is the desired result but this is what I got.
For a multiplot, where you have subplots in a single figure, you can have several xlabel and one title
fig.title("foobar")
ax.set_xlabel("x")
This is explained in great detail here on the Matplotlib website.
You in your case, use a subplot for just a single plot. This is possible, just doesn't make a lot of sense. Plots like the one below are supposed to be created with the subplot feature:
To answer your question: you can set the x- and y-limits on a per-subplot and per-axis basis by simply addressing the respective subplot directly (ax for subplot 1) and them calling the set_xlabel member function to set the label on the x-axis.
EDIT
For your updated question:
Use this code as inspiration, I had to generate some data on my own so no guarantees:
import matplotlib.pyplot as plt
plt.hist(sub_dict['b'], bins=30, color='r', alpha=0.3)
plt.ylim(0,200)
plt.xlim(0,100)
plt.xlabel('x')
plt.ylabel('y')
plt.title('title')
plt.show()
Bit more googling and I got the following that has worked:
sub_dict = subset(data_dict, 'b', 'a', greater_than, 10)
fig = plt.figure(figsize=(9,6))
ax = fig.add_subplot(111)
ax.hist(sub_dict['b'], bins=30, color='r', alpha=0.3)
plt.ylim(0,250)
plt.xlim(0,100)
plt.xlabel('x')
plt.ylabel('y')
plt.title('title')
plt.show()