Matplotlib incorrect display of data on the y-axis. Bars are displayed from coordinate 0.5 to 1.0, but this is not what I would like to see. Coordinates 1.0 are not in the data (height and bottom)
Code for example:
fig, ax = plt.subplots()
x = [0, 1, 2, 3, 4]
height = [0.5047, 0.4999, 0.4985, 0.4999, 0.4987]
bottom = [0.5002, 0.4969, 0.4956, 0.4969, 0.4967]
ax.set_ylim(0, 2)
ax.bar(x=x, height=height, width=0.2, bottom=bottom)
plt.show()
see the output here
Matplotlib Pyplot Bars use the
bottom parameter to define the y-coordinate of the bottom of the bar
height parameter to define the hight of the bar
Consequently, your bars start at bottom and end at bottom+height.
If you calculate the sum of each of coordinates, you will see that they all end roughly at about 1.0:
print([sum(x) for x in zip(height, bottom)]) results in
[1.0049000000000001, 0.9968, 0.9941, 0.9968]
If you aim at drawing bars, whose y-coordinate start at bottom and end at height, then subtract them first
fig, ax = plt.subplots()
x = [0, 1, 2, 3, 4]
height = [0.5047, 0.4999, 0.4985, 0.4999, 0.4987]
bottom = [0.5002, 0.4969, 0.4956, 0.4969, 0.4967]
tmpHeight = tuple(map(lambda i, j: i - j, height, bottom))
ax.bar(x=x, height=tmpHeight , width=0.2, bottom=bottom)
plt.show()
Related
I am plotting an animated contourf map in matplotlib with a colorbar that changes at each frame. I want to keep the colorbar centered at zero (I am using a diverging colormap) and to do so I use an odd number of levels. The problem is, when I do this, even though the central color of the colormap (cm.seismic) is white, this color does not appear in the colormap. I want to be able to replace the color of the smallest values (the light red and the light blue) by white, so that instead of having one central level whose color is white (zero), I have two (two smallest values).
Instead of providing a colormap, you can provide a list of colors. That list can be calculated from the given colormap, and the middle colors can be set explicitly to white.
Here is an example:
import matplotlib.pyplot as plt
import numpy as np
x = y = np.linspace(-3.0, 3.01, 100)
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X ** 2 - Y ** 2)
Z2 = np.exp(-(X - 1) ** 2 - (Y - 1) ** 2)
Z = (Z1 - Z2) * 2
num_levels = 9
colors = plt.cm.seismic(np.linspace(0, 1, num_levels + 1))
colors[num_levels // 2] = [1, 1, 1, 1] # set to white
colors[num_levels // 2 + 1] = [1, 1, 1, 1]
fig, ax1 = plt.subplots(figsize=(10, 5))
CS = ax1.contourf(X, Y, Z, num_levels, colors=colors, origin='lower')
cbar = fig.colorbar(CS, ax=ax1)
plt.show()
I am making a figure with several panels ("subfigures"). I want to place a label ("(a)", "(b)", ...) in the top left corner of each of the panels.
My question: How do I place a label at relative figure coordinates (0, 1) (top-left of the panel) in such a way that:
the specification is independent of aspect ratio, data, etc.;
it is the true top-left (it does not add or leaves a margin)?
Current solution
My current solution is this:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(ncols=2, constrained_layout=True)
ax = axes[0]
ax.plot([0, 1], [0, 1])
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.text(-0.2, 1, "(a)", ha="left", va="top", transform=ax.transAxes)
ax = axes[1]
ax.plot([0, 1], [0, 1])
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.text(-0.2, 1, "(b)", ha="left", va="top", transform=ax.transAxes)
plt.show()
which gives
What I'm looking to improve is that the horizontal -0.2 needs to be tuned every time something like aspect ratio changes. In addition, the vertical 1 needs to be tuned for example when a title is added.
I am using the following code to to generate this heat map:
dim = np.arange(1, 32, 1)
fig, ax = plt.subplots(figsize=(7,9))
heatmap = ax.imshow(h, aspect=1, cmap=plt.cm.get_cmap('Blues', 5), clim=[0,100])
ax.set_ylabel("Days", fontsize=15)
ax.set_xlabel("Months", fontsize=15)
ax.set_title("Percentage of records per day", fontsize=18)
ax.set_yticks(range(0,31))
ax.set_yticklabels(dim, ha='center', minor=False)
ax.set_xticks(range(0,13,1))
ax.set_xticklabels(ylabel[7:],rotation=45, ha='right')
ax.grid(which = 'minor', color = 'w')
ax.set_facecolor('gray')
ax.xaxis.set_minor_locator(MultipleLocator(.5))
ax.yaxis.set_minor_locator(MultipleLocator(.5))
cbaxes = fig.add_axes([.8, .35, .04, .3])
cbar = fig.colorbar(heatmap, ticks = [0, 20, 40, 60, 80 ,100], label = 'Percentage', cax = cbaxes)
fig.show()
I would like to highlight all of the cells with a value greater or equal to 60.
I tried adding this to my code:
highlight = (h> 60)
highlight = np.ma.masked_less(highlight, 1)
ax.pcolormesh(highlight, facecolor = 'None')
and got this:
I am almost there but the cells and the mesh are misaligned. How could I fix this?
The cells in a heatmap are centered on integers, this means for example that the cell with index 0,0 is in fact -0.5 to 0.5 on both axes. You have to subtract 0.5 to the coordinates of your highlights.
Thanks to mozway's comment I was able to fix my problem. I changed the beginning of my code to:
highlight = (h> 60)
highlight = np.ma.masked_less(highlight, 1)
x = np.arange(-0.5,12,1) # len = 10
y = np.arange(-0.5,30,1) # len = 6
X, Y = np.meshgrid(x, y)
and change the line plotting the color mesh to:
ax.pcolormesh(x,y,highlight, facecolor = 'None', edgecolors = 'w',shading='auto', zorder=2)
I also had to set the z-order of the color mesh to be greater than the grid lines (zorder=2 and zorder=1 respectively).
I have several plots and one of these showed below:
Example plot
Problem is I have many plots and I need to put the legend differently according to the position where x=0 and line of x=0 may vary in different plots.
How can I achieve this?
besides, bbox_to_anchor just allow me locate relatively to the fig, but have no idea of the inside (x,y) coordinate.
This is the part plotting:
ax.errorbar(x=x, y=y_erd, yerr=e_erd, fmt='-o',ecolor='orange',elinewidth=1,ms=5,mfc='wheat',mec='salmon',capsize=3)
ax.errorbar(x=x, y=y_ers, yerr=e_ers, fmt='-o',ecolor='blue',elinewidth=1,ms=5,mfc='wheat',mec='salmon',capsize=3)
ax.legend(['ERD', 'ERS'], loc="upper left", bbox_to_anchor=(1, 0.85),fontsize='x-small')
ax.axhline(y=0, color='r', linestyle='--')
We have created a code to calculate the zero position of the x and y axes using a simple sample as an example. First, get the tick values for each axis. Then, use the obtained value to get the index of zero. The next step is to calculate the position of the tick marks for the difference between the minimum and maximum values. From the array, we obtain the coordinates based on the zero index we obtained earlier. Set the obtained coordinates to bbox_to_anchor=[].
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-10, 10, 500)
y = np.sin(x)
fig, ax = plt.subplots()
ax.plot(x, y, label='x=0,y=0')
xticks, yticks = ax.get_xticks(), ax.get_yticks()
xpos, ypos = 0, 0
for i,(x,y) in enumerate(zip(xticks, yticks)):
if x == 0:
xpos = i
if y == 0:
ypos = i
print(xpos, ypos)
x_min, x_max = ax.get_xlim()
xticks = [(tick - x_min)/(x_max - x_min) for tick in xticks]
y_min, y_max = ax.get_ylim()
yticks = [(tick - y_min)/(y_max - y_min) for tick in yticks]
print(xticks[xpos], yticks[ypos])
ax.legend(bbox_to_anchor=[xticks[xpos], yticks[ypos]], loc='center')
plt.show()
I am struggling to remove the empty space in or between subplots. I already read a lot of answers here, but I am not getting anywhere.
I want to make horizontal bar plots with several subplots:
My example is:
import matplotlib.pyplot as plt
x1 = [5]
y1 = [-10]
x2 = [30, 35]
y2 = [-15, -20]
x3 = [15, 5, 20]
y3 = [-10, -15, -30]
xlimits = [-30, 35]
ylimits = [-0.5, 2.5]
fig = plt.figure(figsize=(12,6))
ax1 = fig.add_subplot(3,1,1)
ax1.barh(0, x1, height = 1)
ax1.barh(0, y1, height = 1)
ax2 = fig.add_subplot(3,1,2)
ax2.barh([0, 1], x2, height = 1)
ax2.barh([0, 1], y2, height = 1)
ax3 = fig.add_subplot(3,1,3)
ax3.barh([0, 1, 2], x3, height = 1)
ax3.barh([0, 1, 2], y3, height = 1)
for ax in fig.axes:
ax.set_ylim(ylimits)
ax.set_xlim(xlimits)
plt.show()
will result in:
I used ax.set_ylim(ylimits) to have an equal height of all bars and ax.set_xlim(xlimits) to have "0" in one vertical line.
Now I would like to adjust the bbox to remove the empty space in the subplots (top and middle). But I have no idea how to achieve this. I also tried ax.set_aspect(). In this case I will receive empty space between the subplots.
I would like to do it with subplots to easily add description, swap stuff and so on.
Thanks in advance for any suggestions.
If I understood you correctly, you could try adding this to your code:
fig.subplots_adjust(wspace=0, hspace=0)