In matplotlib, pyplot.text disappears when applying twinx. How can it appear? - python

plt.text(x, y, text) is working when I use single y-axis but it disappears when I apply twinx. Can it be fixed?
fig, ax = plt.figure(figsize=(8,6))
text = "E_rms(test) = {:7.3f}/nE_maxres = {:7.3f}".format(rmse,maxres)
plt.text(0,0,text)
plt.xlabel('data')
ax.set_ylable('PE(eV)')
ax.tick_params(axis='y', labelcolor='b')
if Ltwinx:
ax2 = ax.twinx()
ax2.set_ylabel("Difference(eV)")
ax2.set_tick_params(axis='y', labelcolor='g')
p1 = ax.scatter(range(y), y, c='r', label='true')
p2 = ax.scatter(range(y), h, c='b', label='hypothesis')
if Ltwinx:
p3, = ax2.plot(range(y), diff, c='g', label='difference')
plt.legend([p1,p2],['true value', 'hypothesis'],loc=(0.0, 0.1))
else:
p3, = plt.plot(range(y), diff, c='g', label='difference')
plt.legend([p1,p2,p3],['true value', 'hypothesis', 'difference'],loc=(0.0, 0.1))
plt.show()
This code is an extraction from full code and the belows are figure with two y-axes (1st figure) and single y-axis, where text disappeared in twinx (1st figure). Note y-axis scale is different due to the values of "diff" though p1, p2 figures are same in both figures.

I have misunderstood the manual for matplotlib.pyplot.text.
To use axis coordinate such as (0,0) to (1,1) regardless of y-values, I should add keyword of "transform=ax.transAxes". So
plt.text(0,0,text, transform=ax.transAxes)
is working.

Related

How to get the line's label if multiple graphs have been plotted?

plt.plot(x, y, label = name1)
plt.plot(x, y, label = name2)
plt.plot(x, y, label = name3)
plt.show()
How to get the label when I click the line or better if I can get this information directly in the graph window like I get the x and y axis values on bottom right.
The fastest way would be to add a legend to your graph with plt.legend() right before plt.show()
For more interactivity, maybe try bokeh instead of matplotlib.
Not sure exactly what you are asking for but if you want to represent each line with a name, or the series of the x-values, you could use legend() and input a string or series name as label name in the plot-line:
plt.plot(x1, y, label = "name1") # Show the string name1
plt.plot(x2, y, label = x2) # Shows the array x2
plt.legend() # Displays the legends
If you want to add title or labels for the axis you could use:
plt.xlabel('X-axis Label')
plt.ylabel('Y-axis label')
plt.title('Title')
I am not sure if this is what you are looking for? But you can easily name your graphs by using the Legend. the first graph will be the first in your Legendlist. The important code is between the slash :-)
import matplotlib.pyplot as plt
import numpy as np
# Select length of axes and the space between tick labels
xmin, xmax, ymin, ymax = -10, 10, -10, 10
ticks_frequency = 1
# Plot points
fig, ax = plt.subplots(figsize=(10, 10))
#//////////////////////////////////////////////////////////////////////////////
# x range
x = np.arange(-5, 5., 0.025)
# f1
y1 = 3*x+4
f1 = ax.plot(x, y1, lw = 3, alpha = 0.5, color="blue")
# f2
y2 = 1*x+1
f2 = ax.plot(x, y2, lw = 3, alpha = 0.5, color="orange")
# f3
y3 = -2*x+8
f3 = ax.plot(x, y3, lw = 3, alpha = 0.5, color="red")
# legend
ax.legend(["Gerade 1", "Gerade 2", "Gerade 3"])
#//////////////////////////////////////////////////////////////////////////////
# Set identical scales for both axes
ax.set(xlim=(xmin-1, xmax+1), ylim=(ymin-1, ymax+1), aspect='equal')
# Set bottom and left spines as x and y axes of coordinate system
ax.spines['bottom'].set_position('zero')
ax.spines['left'].set_position('zero')
# Remove top and right spines
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Create 'x' and 'y' labels placed at the end of the axes
ax.set_xlabel('x', size=14, labelpad=-24, x=1.03)
ax.set_ylabel('y', size=14, labelpad=-21, y=1.02, rotation=0)
# Create custom major ticks to determine position of tick labels
x_ticks = np.arange(xmin, xmax+1, ticks_frequency)
y_ticks = np.arange(ymin, ymax+1, ticks_frequency)
ax.set_xticks(x_ticks[x_ticks != 0])
ax.set_yticks(y_ticks[y_ticks != 0])
# Create minor ticks placed at each integer to enable drawing of minor grid
# lines: note that this has no effect in this example with ticks_frequency=1
ax.set_xticks(np.arange(xmin, xmax+1), minor=True)
ax.set_yticks(np.arange(ymin, ymax+1), minor=True)
# Draw major and minor grid lines
ax.grid(which='both', color='grey', linewidth=1, linestyle='-', alpha=0.2)
# Draw arrows
arrow_fmt = dict(markersize=4, color='black', clip_on=False)
ax.plot((1), (0), marker='>', transform=ax.get_yaxis_transform(), **arrow_fmt)
ax.plot((0), (1), marker='^', transform=ax.get_xaxis_transform(), **arrow_fmt)
plt.show()

matplotlib: different handletextpad values in the same legend

I have the following script:
fig = plt.figure()
fig.set_size_inches(8,7)
ax1 = fig.add_subplot(1,1,1)
### PLOT
for k in my_dict:
x, y = my_dict[k][0], my_dict[k][1]
ax1.plot(x, y, linewidth = 0, marker='o', markersize = 4)
X = np.logspace(0.3, 6.6)
ax1.plot(X, 2*X**(-2), linewidth = 2, c='k')
X = np.logspace(0.3, 7.7)
ax1.plot(X, 3*X**(-1.5), linewidth = 2, c='b')
ax1.set_xscale('log')
ax1.set_yscale('log')
## LEGEND
labels = ['$10^{-1} \, \\Delta_1^*$', '$\\Delta_1^*$',\
'$10^{5/2} \, \\Delta_1^*$', '$10^3 \, \\Delta_1^*$',
'$x^{-2}$', '$x^{-3/2}$']
curves = ax1.get_lines()
legend1 = ax1.legend([curves[0], curves[1], curves[2]],\
[labels[0], labels[1], labels[2]],\
loc=1, ncol=1, fancybox=False, shadow=False,\
framealpha=0.0, markerscale=2, fontsize=25, handletextpad=0.0)
legend2 = ax1.legend([curves[3], curves[4], curves[5]],\
[labels[3], labels[4], labels[5]],\
loc=3, ncol=1, fancybox=False, shadow=False,\
framealpha=0.0, markerscale=2, fontsize=25, handletextpad=0.0)
vp = legend1._legend_box._children[-1]._children[0]
for c in vp._children:
c._children.reverse()
vp.align="right"
ax1.add_artist(legend1)
ax1.add_artist(legend2)
fig.tight_layout()
plt.show()
The result is
The issue: I use handletextpad in the legends, and that is because I need points and text to be very close. However the last two elements in the second legend are not points, but lines. They take more space then points and the text happens to be too close.
I need to keep this distance between text and points while increasing the distance between text and lines in the same legend.
I tried with handletextpad=[0.1, 0.5, 0.5] and similar strategies, but I haven't been able to set individual values of handletextpad.
Another possibility would be to make separate legends and specifically one with only lines. This, however, would force me to manually positioning any legend very carefully and I'd rather not doing it. Also (I don't know if it can help), but I'd rather not replace
plt.plot(x, y, linewidth = 0, markersize = 4)
with
plt.scatter(x, y).
Except for these two caveats, everything is welcome.

How to decide which bars are plotted on top/last in overlay of 2 Pandas bar plots where one plot uses alpha [duplicate]

In pyplot, you can change the order of different graphs using the zorder option or by changing the order of the plot() commands. However, when you add an alternative axis via ax2 = twinx(), the new axis will always overlay the old axis (as described in the documentation).
Is it possible to change the order of the axis to move the alternative (twinned) y-axis to background?
In the example below, I would like to display the blue line on top of the histogram:
import numpy as np
import matplotlib.pyplot as plt
import random
# Data
x = np.arange(-3.0, 3.01, 0.1)
y = np.power(x,2)
y2 = 1/np.sqrt(2*np.pi) * np.exp(-y/2)
data = [random.gauss(0.0, 1.0) for i in range(1000)]
# Plot figure
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax2.hist(data, bins=40, normed=True, color='g',zorder=0)
ax2.plot(x, y2, color='r', linewidth=2, zorder=2)
ax1.plot(x, y, color='b', linewidth=2, zorder=5)
ax1.set_ylabel("Parabola")
ax2.set_ylabel("Normal distribution")
ax1.yaxis.label.set_color('b')
ax2.yaxis.label.set_color('r')
plt.show()
Edit: For some reason, I am unable to upload the image generated by this code. I will try again later.
You can set the zorder of an axes, ax.set_zorder(). One would then need to remove the background of that axes, such that the axes below is still visible.
ax2 = ax1.twinx()
ax1.set_zorder(10)
ax1.patch.set_visible(False)

PyPlot move alternative y axis to background

In pyplot, you can change the order of different graphs using the zorder option or by changing the order of the plot() commands. However, when you add an alternative axis via ax2 = twinx(), the new axis will always overlay the old axis (as described in the documentation).
Is it possible to change the order of the axis to move the alternative (twinned) y-axis to background?
In the example below, I would like to display the blue line on top of the histogram:
import numpy as np
import matplotlib.pyplot as plt
import random
# Data
x = np.arange(-3.0, 3.01, 0.1)
y = np.power(x,2)
y2 = 1/np.sqrt(2*np.pi) * np.exp(-y/2)
data = [random.gauss(0.0, 1.0) for i in range(1000)]
# Plot figure
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax2.hist(data, bins=40, normed=True, color='g',zorder=0)
ax2.plot(x, y2, color='r', linewidth=2, zorder=2)
ax1.plot(x, y, color='b', linewidth=2, zorder=5)
ax1.set_ylabel("Parabola")
ax2.set_ylabel("Normal distribution")
ax1.yaxis.label.set_color('b')
ax2.yaxis.label.set_color('r')
plt.show()
Edit: For some reason, I am unable to upload the image generated by this code. I will try again later.
You can set the zorder of an axes, ax.set_zorder(). One would then need to remove the background of that axes, such that the axes below is still visible.
ax2 = ax1.twinx()
ax1.set_zorder(10)
ax1.patch.set_visible(False)

Matplotlib Bar Graph Overlapping of Bars

So I have created a bar graph but I am having trouble with overlapping bars. I thought that the problem was with the edges overlapping, but when I changed edges='none'the bars were just really slim.
I do believe my math is correct in assuming that 3 bars with a width of of .3 should be moving along the x axis by .3 and leaving a .1 gap between each set of bars. (Note x is increasing by 1)
I don't see why the bars end up overlapping and the overlap seems to get worse near the end of the graph.
ax = plt.subplot(111)
ax2 = ax.twinx()
ax.bar(x,EWtot,width=.3, color='b', align='center',label='Eyewall',edgecolor='b')
ax.bar(x + 0.3,ICtot,width=.3, color='g', align='center',label='Inner Core',edgecolor='g')
ax.bar(x + 0.6,RBtot,width=.3, color='r', align='center',label='RainBand',edgecolor='r')
I think its a combination of two factors. First you could increase the precision of your width and x-position a little by supplying some extra digits, or specifying them as a fraction.
Secondly the use of the edge (linewidth > 0) makes the bars overlap a little by default, the edge is centered, so half the edge is inside the bar, the other half outside. Disabling the edge entirely prevents any overlap.
Increasing the linewidth and setting an alpha might help you to identify whats going on exactly.
The example below illustrates this:
n = 10
x = np.arange(n)
a = np.random.rand(n)
b = np.random.rand(n)
c = np.random.rand(n)
fig, axs = plt.subplots(2,1,figsize=(10,8))
axs[0].bar(x, a, width=0.3, facecolor='b', edgecolor='b', linewidth=3, alpha=.5)
axs[0].bar(x+0.3, b, width=0.3, facecolor='r', edgecolor='r', linewidth=3, alpha=.5)
axs[0].bar(x+0.6, c, width=0.3, facecolor='g', edgecolor='g', linewidth=3, alpha=.5)
axs[1].bar(x, a, width=1/3, facecolor='b', alpha=.5, linewidth=0)
axs[1].bar(x+1/3, b, width=1/3, facecolor='r', alpha=.5, linewidth=0)
axs[1].bar(x+2/3, c, width=1/3, facecolor='g', alpha=.5, linewidth=0)

Categories

Resources