import matplotlib.pyplot as plt
import seaborn as sb
from matplotlib import style
style.use("dark_background")
tips = sb.load_dataset("tips")
plt.figure(figsize=(8,4))
sb.set_context('paper', font_scale=1.2)
sb.lmplot(x="total_bill", y="tip", hue="sex", data=tips,markers=['o', '^'],
scatter_kws={'s':50, "linewidth" : 0.2, "edgecolor" : 'w'}, aspect=1.5)
I am using dataset tips(seaborn dataset). When am plotting the graph some data points are not fully shown like one at (0,1) the triangle data point is not fully shown and other at (51,10) the circle data point is half visible.
Graph : Graph Image
Where am I doing wrong?
In addition to the correct answer by #r-beginners, you can pass clip_on=False to the plotting function to prevent artists to being clipped at the edge of the axes.
sb.lmplot(x="total_bill", y="tip", hue="sex", data=tips,markers=['o', '^'],
scatter_kws={'s':50, "linewidth" : 0.2, "edgecolor" : 'w', 'clip_on':False}, aspect=1.5)
You can use ax.set_xlim() in such a case. You can use ax.set_xlim() to expand the area over which the image is displayed. Also, seaborn gives priority to height and aspect ratio over figsize.
import matplotlib.pyplot as plt
import seaborn as sb
from matplotlib import style
style.use("dark_background")
tips = sb.load_dataset("tips")
# plt.figure(figsize=(8,4))
sb.set_context('paper', font_scale=1.2)
sb.lmplot(x="total_bill", y="tip", hue="sex", data=tips,markers=['o', '^'],
scatter_kws={'s':50, "linewidth" : 0.2, "edgecolor" : 'w'}, aspect=2, legend_out=False, height=4)
ax = plt.gca()
ax.set_xlim((0,55))
Related
How to display an image with imshow on all the width of an axe (viewport) but keeping the ratio 'equal' ?
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(nrows=2, figsize=(8,8))
img = ax[0].imshow(np.random.random((10,10)), aspect='equal')
line = ax[1].plot([12,34],[45,78])
I would like that the image width be aligned on the line plot keeping an equal ratio even if that implies having blank around. My application has a zooming feature coded on the image in fact so I would to offer all the width possible for its display.
So in few words, I would like the same width as with aspect='auto' but with square pixels.
Is it possible ? Thanks.
Found with a reading of Axes class - set explicitly size (width/height) of axes in given units
and the use of
set_adjustable('datalim')
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(nrows=2, figsize=(8,8))
img = ax[0].imshow(np.random.random((10,10)), aspect='equal')
ax[0].set_adjustable('datalim')
line = ax[1].plot([12,34],[45,78])
Tried the midnorm and listed colormap, but do not know how to turn the front 0-20 into uniform multi-color (the picture shows the abbreviation, please do not mind), do not know how to draw the effect of the picture! ! Help
In this case it makes sense to use a BoundaryNorm and a ListedColormap. Define the N+1 bounaries for the N colors of the colormap and use spacing="proportional" in the colorbar call.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import BoundaryNorm, ListedColormap
cmap = ListedColormap(["black", "darkred", "crimson", "salmon", "navy", "violet", "yellow"])
bounds = [0,1,2,3,4,10,20,30]
norm = BoundaryNorm(bounds, cmap.N)
fig, ax = plt.subplots()
sc = ax.scatter(*np.random.rand(2,100), c=np.random.rand(100)*30, cmap=cmap, norm=norm)
fig.colorbar(sc, orientation="horizontal", spacing="proportional")
plt.show()
I think you should use
MyCmap=colors.LinearSegmentedColormap.from_list("", list(zip(lvals,cvals)))
as in this solution (even if it is for a logarithmic scale there). Look at the end of the accepted answer.
I'm trying to write a function to display astronomical images with a colorbar on the top (automaticly with the same length of the x-axis).
I'm having problem because when I try to put the tick on the top it doesn't do anything...it keeps the tick on the bottom of the colorbar (and also the tick on the y-axis of the colobar).
I think that could be a problem with the WCS coordinate of the x-axis, because when i try to do it without the projection it work well!
import numpy as np
import matplotlib.pyplot as plt
from astropy import wcs
from matplotlib.colors import PowerNorm
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib import cm
#WCS coordinate system
w = wcs.WCS(naxis=2)
w.wcs.crpix = [23.5, 23.5]
w.wcs.cdelt = np.array([-0.0035, 0.0035])
w.wcs.crval = [266.8451, -28.151658]
w.wcs.ctype = ["RA---TAN", "DEC--TAN"]
w.wcs.set_pv([(2, 1, 45.0)])
#generate an array as image test
data = (np.arange(10000).reshape((100,100)))
#display image
fig = plt.figure()
ax = plt.gca(projection=w)
graf = ax.imshow(data, origin='lower', cmap=cm.viridis, norm=PowerNorm(1))
#colorbar
divider = make_axes_locatable(ax)
cax = divider.append_axes("top", size="5%")
cbar = fig.colorbar(graf, cax=cax, orientation='horizontal')
cax.xaxis.set_ticks_position('top')
fig.show()
Thanks!
You can fix this issue using matplotlib's axes class.
...
import matplotlib.axes as maxes
cax = divider.append_axes("top", size="5%", axes_class=maxes.Axes)
...
You need to use the internal machinery of the WCSAxes to handle the ticks in the WCS projection. It looks like WCSAxes handles the colorbar ticks through a coordinate map container (you can find it in cbar.ax.coords) instead of the xaxis/yaxis attributes (that don't seem to be used much).
So, after running your code, the following trick worked for me and the xticks moved up:
c_x = cbar.ax.coords['x']
c_x.set_ticklabel_position('t')
cbar.update_normal(cax)
To get something like this to work, I needed a few additional parameters:
from mpl_toolkits.axes_grid1 import make_axes_locatable
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
cax.coords[0].grid(False)
cax.coords[1].grid(False)
cax.tick_params(direction='in')
cax.coords[0].set_ticks(alpha=0, color='w', size=0, values=[]*u.dimensionless_unscaled)
cax.coords[1].set_ticklabel_position('r')
cax.coords[1].set_axislabel_position('r')
because the default axis gad the grid on, the labels to the left, and x-axis labels enabled. I'm not sure why the original post didn't have issues with this.
import matplotlib.pyplot as plt
import pandas as pd
df = pd.DataFrame({'y':['a','b','c','d','e','f','g','h','i']\
,'x':[10,9,9,8,7,6,10,6,7]})
df.sort_values(by='x',inplace=True,ascending = True)
plt.barh(bottom=list(range(1,10)), width=df.x, height = 0.15, align='center',color = 'blue')
plt.xlim([0,11])
plt.yticks(list(range(1,10)),skills.y)
plt.show()
This code gives me a horizontal bar graph.
I want to add a circular dot at the edge of each bars.
Can someone please help me with that.
Tableau graph
I did this in tableau, I want to replicate the same in python.
Also, please let me know if there a better way of coding the same.
I am using Anaconda Python 3.5, Matplotlib library, Windows 10, Idlex IDE
You could just add a scatterplot on top of your bars, using matplotlib scatter function.
Also, note that you could use the numpy.arange function to generate your x values, instead of your current list(range(1,10)).
See example below
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
df = pd.DataFrame({'y':['a','b','c','d','e','f','g','h','i'],
'x':[10,9,9,8,7,6,10,6,7]})
df.sort_values(by='x',inplace=True,ascending = True)
plt.barh(bottom=np.arange(len(df)), width=df.x, height = 0.15, align='center',color = 'blue')
plt.scatter(df.x.values, y=np.arange(df.shape[0]), color='b', s=40)
plt.xlim([0,11])
plt.yticks(np.arange(len(df)),df.y)
plt.show()
I am quite used to working with matlab and now trying to make the shift matplotlib and numpy. Is there a way in matplotlib that an image you are plotting occupies the whole figure window.
import numpy as np
import matplotlib.pyplot as plt
# get image im as nparray
# ........
plt.figure()
plt.imshow(im)
plt.set_cmap('hot')
plt.savefig("frame.png")
I want the image to maintain its aspect ratio and scale to the size of the figure ... so when I do savefig it exactly the same size as the input figure, and it is completely covered by the image.
Thanks.
I did this using the following snippet.
#!/usr/bin/env python
import numpy as np
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
from pylab import *
delta = 0.025
x = y = np.arange(-3.0, 3.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = Z2-Z1 # difference of Gaussians
ax = Axes(plt.gcf(),[0,0,1,1],yticks=[],xticks=[],frame_on=False)
plt.gcf().delaxes(plt.gca())
plt.gcf().add_axes(ax)
im = plt.imshow(Z, cmap=cm.gray)
plt.show()
Note the grey border on the sides is related to the aspect rario of the Axes which is altered by setting aspect='equal', or aspect='auto' or your ratio.
Also as mentioned by Zhenya in the comments Similar StackOverflow Question
mentions the parameters to savefig of bbox_inches='tight' and pad_inches=-1 or pad_inches=0
You can use a function like the one below.
It calculates the needed size for the figure (in inches) according to the resolution in dpi you want.
import numpy as np
import matplotlib.pyplot as plt
def plot_im(image, dpi=80):
px,py = im.shape # depending of your matplotlib.rc you may
have to use py,px instead
#px,py = im[:,:,0].shape # if image has a (x,y,z) shape
size = (py/np.float(dpi), px/np.float(dpi)) # note the np.float()
fig = plt.figure(figsize=size, dpi=dpi)
ax = fig.add_axes([0, 0, 1, 1])
# Customize the axis
# remove top and right spines
ax.spines['right'].set_color('none')
ax.spines['left'].set_color('none')
ax.spines['top'].set_color('none')
ax.spines['bottom'].set_color('none')
# turn off ticks
ax.xaxis.set_ticks_position('none')
ax.yaxis.set_ticks_position('none')
ax.xaxis.set_ticklabels([])
ax.yaxis.set_ticklabels([])
ax.imshow(im)
plt.show()
Here's a minimal object-oriented solution:
fig = plt.figure(figsize=(8, 8))
ax = fig.add_axes([0, 0, 1, 1], frameon=False, xticks=[], yticks=[])
Testing it out with
ax.imshow([[0]])
fig.savefig('test.png')
saves out a uniform purple block.
edit: As #duhaime points out below, this requires the figure to have the same aspect as the axes.
If you'd like the axes to resize to the figure, add aspect='auto' to imshow.
If you'd like the figure to resize to be resized to the axes, add
from matplotlib import tight_bbox
bbox = fig.get_tightbbox(fig.canvas.get_renderer())
tight_bbox.adjust_bbox(fig, bbox, fig.canvas.fixed_dpi)
after the imshow call. This is the important bit of matplotlib's tight_layout functionality which is implicitly called by things like Jupyter's renderer.