I'm attempting to make use of twinx() to create a bar/line combo graph with the line visible on top of the bar. Currently this is how it appears:
I also need the line chart to be plotted on the left vertical axis (ax) and the bar on the right (ax2) as it currently is. If I plot the line on the second axis it does appear on top, but obviously it appears on the wrong axis (right)
Here's my code:
self.ax2=ax.twinx()
df[['Opportunities']].plot(kind='bar', stacked=False, title=get_title, color='grey', ax=self.ax2, grid=False)
ax.plot(ax.get_xticks(),df[['Percentage']].values, linestyle='-', marker='o', color='k', linewidth=1.0)
lines, labels = ax.get_legend_handles_labels()
lines2, labels2 = self.ax2.get_legend_handles_labels()
ax.legend(lines + lines2, labels + labels2, loc='lower right')
Also having trouble with the labels, but one thing at a time.
It appears, by default, that the artists are drawn on ax first, then the
artists on the twin axes ax2 on top. So since in your code the line plot was drawn on ax and the bar plot on ax2, the bar plot sits on top of (and obscures) the line.
(I thought I could change this by specifying zorder, but that attempt did not
work... )
So one way to solve the problem is to use ax to draw the bar plot and ax2 to draw the line. That will place the line on top of the bars. It will also, by default, place the ytick labels for ax (the bar plot) on the left, and the ytick labels for ax2 (the line) on the right. However, you can use
ax.yaxis.set_ticks_position("right")
ax2.yaxis.set_ticks_position("left")
to swap the location of the left and right ytick labels.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
np.random.seed(2015)
N = 16
df = pd.DataFrame({'Opportunities': np.random.randint(0, 30, size=N),
'Percentage': np.random.randint(0, 100, size=N)},
index=pd.date_range('2015-3-15', periods=N, freq='B').date)
fig, ax = plt.subplots()
df[['Opportunities']].plot(kind='bar', stacked=False, title='get_title',
color='grey', ax=ax, grid=False)
ax2 = ax.twinx()
ax2.plot(ax.get_xticks(), df[['Percentage']].values, linestyle='-', marker='o',
color='k', linewidth=1.0, label='percentage')
lines, labels = ax.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax.legend(lines + lines2, labels + labels2, loc='best')
ax.yaxis.set_ticks_position("right")
ax2.yaxis.set_ticks_position("left")
fig.autofmt_xdate()
plt.show()
yields
Alternatively, the zorder of the axes can be set so as to draw ax above ax2. Paul Ivanov shows how:
ax.set_zorder(ax2.get_zorder()+1) # put ax in front of ax2
ax.patch.set_visible(False) # hide the 'canvas'
ax2.patch.set_visible(True) # show the 'canvas'
Thus,
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
np.random.seed(2015)
N = 16
df = pd.DataFrame({'Opportunities': np.random.randint(0, 30, size=N),
'Percentage': np.random.randint(0, 100, size=N)},
index=pd.date_range('2015-3-15', periods=N, freq='B').date)
fig, ax = plt.subplots()
ax2 = ax.twinx()
df[['Opportunities']].plot(kind='bar', stacked=False, title='get_title',
color='grey', ax=ax2, grid=False)
ax.plot(ax.get_xticks(), df[['Percentage']].values, linestyle='-', marker='o',
color='k', linewidth=1.0, label='percentage')
lines, labels = ax.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax.legend(lines + lines2, labels + labels2, loc='best')
ax.set_zorder(ax2.get_zorder()+1) # put ax in front of ax2
ax.patch.set_visible(False) # hide the 'canvas'
ax2.patch.set_visible(True) # show the 'canvas'
fig.autofmt_xdate()
plt.show()
yields the same result without having to swap the roles played by ax and ax2.
Related
I have been looking around and have got to nowhere with this. I am trying to animate the poles on a stereonet diagram. However, the poles do not appear at the location that they should be in.
Figure 1 is the animated pole plot while Figure 2 is how the plot should be. I was wondering if anyone had an idea on how to proceed with this?
import matplotlib as mpl
mpl.use("TkAgg")
from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np
import mplstereonet
fig, ax = mplstereonet.subplots()
fig2, ax1 = mplstereonet.subplots()
ax.grid(True)
ax1.grid(True)
# Assume a strike and dip with a random variance.
# Current values should plot the poles at either 0, 180
strike, dip = 90, 80
num = 10
strikes = strike + 10 * np.random.randn(num)
dips = dip + 10 * np.random.randn(num)
poles, = ax.pole([], [], 'o')
def init():
poles.set_data([], [])
return poles,
def animate(i):
poles.set_data(strikes[:i], dips[:i])
return poles,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames = len(strikes), interval = 100, blit=True, repeat=False)
poles1 = ax1.pole(strikes, dips, 'o') # This is how the final image should look like
plt.show()
I would like to add a separate colorbar to each subplot in a 2x2 plot.
fig , ( (ax1,ax2) , (ax3,ax4)) = plt.subplots(2, 2,sharex = True,sharey=True)
z1_plot = ax1.scatter(x,y,c = z1,vmin=0.0,vmax=0.4)
plt.colorbar(z1_plot,cax=ax1)
z2_plot = ax2.scatter(x,y,c = z2,vmin=0.0,vmax=40)
plt.colorbar(z1_plot,cax=ax2)
z3_plot = ax3.scatter(x,y,c = z3,vmin=0.0,vmax=894)
plt.colorbar(z1_plot,cax=ax3)
z4_plot = ax4.scatter(x,y,c = z4,vmin=0.0,vmax=234324)
plt.colorbar(z1_plot,cax=ax4)
plt.show()
I thought that this is how you do it, but the resulting plot is really messed up; it just has an all grey background and ignores the set_xlim , set_ylim commands I have (not shown here for simplicity). + it shows no color bars. Is this the right way to do it?
I also tried getting rid of the "cax = ...", but then the colorbar all goes on the bottom right plot and not to each separate plot!
This can be easily solved with the the utility make_axes_locatable. I provide a minimal example that shows how this works and should be readily adaptable:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
m1 = np.random.rand(3, 3)
m2 = np.arange(0, 3*3, 1).reshape((3, 3))
fig = plt.figure(figsize=(16, 12))
ax1 = fig.add_subplot(121)
im1 = ax1.imshow(m1, interpolation='None')
divider = make_axes_locatable(ax1)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(im1, cax=cax, orientation='vertical')
ax2 = fig.add_subplot(122)
im2 = ax2.imshow(m2, interpolation='None')
divider = make_axes_locatable(ax2)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(im2, cax=cax, orientation='vertical');
In plt.colorbar(z1_plot,cax=ax1), use ax= instead of cax=, i.e. plt.colorbar(z1_plot,ax=ax1)
Specify the ax argument to matplotlib.pyplot.colorbar(), e.g.
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2, 2)
for i in range(2):
for j in range(2):
data = np.array([[i, j], [i+0.5, j+0.5]])
im = ax[i, j].imshow(data)
plt.colorbar(im, ax=ax[i, j])
plt.show()
Please have a look at this matplotlib example page. There it is shown how to get the following plot with four individual colorbars for each subplot:
I hope this helps.
You can further have a look here, where you can find a lot of what you can do with matplotlib.
Try to use the func below to add colorbar:
def add_colorbar(mappable):
from mpl_toolkits.axes_grid1 import make_axes_locatable
import matplotlib.pyplot as plt
last_axes = plt.gca()
ax = mappable.axes
fig = ax.figure
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
cbar = fig.colorbar(mappable, cax=cax)
plt.sca(last_axes)
return cbar
Then you codes need to be modified as:
fig , ( (ax1,ax2) , (ax3,ax4)) = plt.subplots(2, 2,sharex = True,sharey=True)
z1_plot = ax1.scatter(x,y,c = z1,vmin=0.0,vmax=0.4)
add_colorbar(z1_plot)
After grouping etc. I get a Series like in the example below. I would like to show the average numbers for each bar. The code below shows only one entry (of course, as I have only one "legend"). Could anyone one suggest a smart way of showing these numbers?
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib
matplotlib.style.use('ggplot')
import pandas
# create Series
dict_ = {"Business" : 104.04,"Economy":67.04, "Markets":58.56, "Companies":38.48}
s = pandas.Series(data=dict_)
# plot it
ax = s.plot(kind='bar', color='#43C6DB', stacked=True, figsize=(20, 10), legend=False)
plt.tick_params(axis='both', which='major', labelsize=14)
plt.xticks(rotation=30) #rotate labels
# Shrink current axis by 20%
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
#create new legend
legend = ['%s (%.1f a day)' %(i, row/7) for i, row in s.iteritems()]
# Put the legend to the right of the current axis
L = ax.legend(legend, loc='center left', bbox_to_anchor=(1, 0.5), fontsize=18)
plt.show()
The legend only has a single entry. This is a handle of a blue bar. Therefore even if you set the labels to a longer list, only the first element of that list is used as label for the existing handle.
The idea can be to duplicate the legend handle to have the same size as the labels
legend = ['%s (%.1f a day)' %(i, row/7) for i, row in s.iteritems()]
h,l = ax.get_legend_handles_labels()
L = ax.legend(handles = h*len(legend), labels=legend, loc='center left',
bbox_to_anchor=(1, 0.5), fontsize=18)
I am new to Matplotlib. Based on my code in following, I wanted to update the data,title,xlabel,ylabel at same time. However, the title and labels did not been updated, but data did.Someone can give me a solution? That will help me a lot.Thank you.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def updata(frame_number):
current_index = frame_number % 3
a = [[1,2,3],[4,5,6],[7,8,9]]
idata['position'][:,0] = np.asarray(a[current_index])
idata['position'][:,1] = np.asarray(a[current_index])
scat.set_offsets(idata['position'])
ax.set_xlabel('The Intensity of Image1')
ax.set_ylabel('The Intensity of Image2')
ax.set_title("For Dataset %d" % current_index)
fig = plt.figure(figsize=(5,5))
ax = fig.add_axes([0,0,1,1])
idata = np.zeros(3,dtype=[('position',float,2)])
ax.set_title(label='lets begin',fontdict = {'fontsize':12},loc='center')
scat = ax.scatter(idata['position'][:,0],idata['position'][:,1],s=10,alpha=0.3,edgecolors='none')
animation = FuncAnimation(fig,updata,interval=2000)
plt.show()
Running the code, I see an empty window. The reason is that the axes span the complete figure (fig.add_axes([0,0,1,1])). In order to see the title and labels, you would need to make the axes smaller than the figure, e.g. by
ax = fig.add_subplot(111)
Also, the scale of the axes is not defined, so the animation will happen outside the axes limits. You can use ax.set_xlim and ax.set_ylim to prevent that.
Here is a complete running code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def updata(frame_number):
current_index = frame_number % 3
a = [[1,2,3],[4,5,6],[7,8,9]]
idata['position'][:,0] = np.asarray(a[current_index])
idata['position'][:,1] = np.asarray(a[current_index])
scat.set_offsets(idata['position'])
ax.set_xlabel('The Intensity of Image1')
ax.set_ylabel('The Intensity of Image2')
ax.set_title("For Dataset %d" % current_index)
fig = plt.figure(figsize=(5,5))
ax = fig.add_subplot(111)
idata = np.zeros(3,dtype=[('position',float,2)])
ax.set_title(label='lets begin',fontdict = {'fontsize':12},loc='center')
scat = ax.scatter(idata['position'][:,0],idata['position'][:,1],
s=25,alpha=0.9,edgecolors='none')
ax.set_xlim(0,10)
ax.set_ylim(0,10)
animation = FuncAnimation(fig,updata,frames=50,interval=600)
plt.show()
i've computed an Otsu's thresholding for a kinect depth image and now i want point out the optimal thresholding value on the histogram, using for example axvline with pyplot in opencv2.
I'm a beginner with python and programming too, this is the specific part of my code:
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(8, 2.5))
ax1.imshow(img)
ax1.set_title('Original')
ax1.axis('off')
ax2.hist(img)
ax2.set_title('Histogram')
plt.axvline(x=thresh, color='r', linestyle='dashed', linewidth=2)
ax3.imshow(binary, cmap=plt.cm.gray)
ax3.set_title('Thresholded')
ax3.axis('off')
plt.show()
but i don't know why, i obtain the vertical line on the thresholded plot
what am i doing wrong??
thanks
works for me:
from scipy.misc import imread, imresize
import matplotlib.pyplot as plt
f = r"C:\Users\Public\Pictures\Sample Pictures\Lighthouse.jpg"
img = imread(f)[:, :, 0]
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(8, 2.5))
ax1.imshow(img)
ax1.set_title('Original')
ax1.axis('off')
thresh = 100
ax2.hist(img)
ax2.set_title('Histogram')
ax2.axvline(x=thresh, color='r', linestyle='dashed', linewidth=2)
ax3.imshow(img, cmap=plt.cm.gray)
ax3.set_title('Thresholded')
ax3.axis('off')
plt.show()