from matplotlib import pyplot as plt
plt.scatter(X,Y1,color='red')
plt.scatter(X,Y2,color='blue')
plt.show()
How can I do this with 10 sets?
I searched for this and could find any reference to what I’m asking.
Edit: clarifying (hopefully) my question
If I call scatter multiple times, I can only set the same color on each scatter. Also, I know I can set a color array manually but I’m sure there is a better way to do this.
My question is then, “How can I automatically scatter-plot my several data sets, each with a different color.
If that helps, I can easily assign a unique number to each data set.
回答 0
我不知道“手动”是什么意思。您可以选择一个颜色图并足够容易地创建颜色阵列:
import numpy as npimport matplotlib.pyplot as pltimport matplotlib.cm as cm
x = np.arange(10)
ys =[i+x+(i*x)**2for i in range(10)]
colors = cm.rainbow(np.linspace(0,1, len(ys)))for y, c in zip(ys, colors):
plt.scatter(x, y, color=c)
I don’t know what you mean by ‘manually’. You can choose a colourmap and make a colour array easily enough:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
x = np.arange(10)
ys = [i+x+(i*x)**2 for i in range(10)]
colors = cm.rainbow(np.linspace(0, 1, len(ys)))
for y, c in zip(ys, colors):
plt.scatter(x, y, color=c)
Or you can make your own colour cycler using itertools.cycle and specifying the colours you want to loop over, using next to get the one you want. For example, with 3 colours:
import itertools
colors = itertools.cycle(["r", "b", "g"])
for y in ys:
plt.scatter(x, y, color=next(colors))
Come to think of it, maybe it’s cleaner not to use zip with the first one neither:
colors = iter(cm.rainbow(np.linspace(0, 1, len(ys))))
for y in ys:
plt.scatter(x, y, color=next(colors))
import matplotlibimport numpy as np
X =[1,2,3,4]Ys= np.array([[4,8,12,16],[1,4,9,16],[17,10,13,18],[9,10,18,11],[4,15,17,6],[7,10,8,7],[9,0,10,11],[14,1,15,5],[8,15,9,14],[20,7,1,5]])
nCols = len(X)
nRows =Ys.shape[0]
colors = matplotlib.cm.rainbow(np.linspace(0,1, len(Ys)))
cs =[colors[i//len(X)]for i in range(len(Ys)*len(X))]#could be done with numpy's repmatXs=X*nRows #use list multiplication for repetition
matplotlib.pyplot.scatter(Xs,Ys.flatten(),color=cs)
When you have a list of lists and you want them colored per list.
I think the most elegant way is that suggesyted by @DSM,
just do a loop making multiple calls to scatter.
But if for some reason you wanted to do it with just one call, you can make a big list of colors, with a list comprehension and a bit of flooring division:
import matplotlib
import numpy as np
X = [1,2,3,4]
Ys = np.array([[4,8,12,16],
[1,4,9,16],
[17, 10, 13, 18],
[9, 10, 18, 11],
[4, 15, 17, 6],
[7, 10, 8, 7],
[9, 0, 10, 11],
[14, 1, 15, 5],
[8, 15, 9, 14],
[20, 7, 1, 5]])
nCols = len(X)
nRows = Ys.shape[0]
colors = matplotlib.cm.rainbow(np.linspace(0, 1, len(Ys)))
cs = [colors[i//len(X)] for i in range(len(Ys)*len(X))] #could be done with numpy's repmat
Xs=X*nRows #use list multiplication for repetition
matplotlib.pyplot.scatter(Xs,Ys.flatten(),color=cs)
import matplotlib.pyplot as pltfrom random import randintimport numpy as np#Let's generate some random X, Y data X = [ [frst group],[second group] ...]
X =[[randint(0,50)for i in range(0,5)]for i in range(0,24)]
Y =[[randint(0,50)for i in range(0,5)]for i in range(0,24)]
labels = range(1,len(X)+1)
fig = plt.figure()
ax = fig.add_subplot(111)for x,y,lab in zip(X,Y,labels):
ax.scatter(x,y,label=lab)
您唯一需要的一段代码:
#Now this is actually the code that you need, an easy fix your colors just cut and paste not you need ax.
colormap = plt.cm.gist_ncar #nipy_spectral, Set1,Paired
colorst =[colormap(i)for i in np.linspace(0,0.9,len(ax.collections))]for t,j1 in enumerate(ax.collections):
j1.set_color(colorst[t])
ax.legend(fontsize='small')
If you have only one type of collections (e.g. scatter with no error bars) you can also change the colours after that you have plotted them, this sometimes is easier to perform.
import matplotlib.pyplot as plt
from random import randint
import numpy as np
#Let's generate some random X, Y data X = [ [frst group],[second group] ...]
X = [ [randint(0,50) for i in range(0,5)] for i in range(0,24)]
Y = [ [randint(0,50) for i in range(0,5)] for i in range(0,24)]
labels = range(1,len(X)+1)
fig = plt.figure()
ax = fig.add_subplot(111)
for x,y,lab in zip(X,Y,labels):
ax.scatter(x,y,label=lab)
The only piece of code that you need:
#Now this is actually the code that you need, an easy fix your colors just cut and paste not you need ax.
colormap = plt.cm.gist_ncar #nipy_spectral, Set1,Paired
colorst = [colormap(i) for i in np.linspace(0, 0.9,len(ax.collections))]
for t,j1 in enumerate(ax.collections):
j1.set_color(colorst[t])
ax.legend(fontsize='small')
The output gives you differnent colors even when you have many different scatter plots in the same subplot.
回答 3
您可以始终plot()像这样使用该函数:
import matplotlib.pyplot as pltimport numpy as np
x = np.arange(10)
ys =[i+x+(i*x)**2for i in range(10)]
plt.figure()for y in ys:
plt.plot(x, y,'o')
plt.show()
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(10)
ys = [i+x+(i*x)**2 for i in range(10)]
plt.figure()
for y in ys:
plt.plot(x, y, 'o')
plt.show()
# rgbaArr is a N*4 array of float numbers you know what I mean# X is a N*2 array of coordinates# axx is the axes object that current draw, you get it from# axx = fig.gca()# also import these, to recreate the within env of scatter command import matplotlib.markers as mmarkers
import matplotlib.transforms as mtransforms
from matplotlib.collections importPatchCollectionimport matplotlib.markers as mmarkers
import matplotlib.patches as mpatches
# define this function# m is a string of scatter marker, it could be 'o', 's' etc..# s is the size of the point, use 1.0# dpi, get it from axx.figure.dpidef addPatch_point(m, s, dpi):
marker_obj = mmarkers.MarkerStyle(m)
path = marker_obj.get_path()
trans = mtransforms.Affine2D().scale(np.sqrt(s*5)*dpi/72.0)
ptch = mpatches.PathPatch(path, fill =True, transform = trans)return ptch
patches =[]# markerArr is an array of maker string, ['o', 's'. 'o'...]# sizeArr is an array of size float, [1.0, 1.0. 0.5...]for m, s in zip(markerArr, sizeArr):
patches.append(addPatch_point(m, s, axx.figure.dpi))
pclt =PatchCollection(
patches,
offsets = zip(X[:,0], X[:,1]),
transOffset = axx.transData)
pclt.set_transform(mtransforms.IdentityTransform())
pclt.set_edgecolors('none')# it's up to you
pclt._facecolors = rgbaArr
# in the end, when you decide to draw
axx.add_collection(pclt)# and call axx's parent to draw_idle()
This question is a bit tricky before Jan 2013 and matplotlib 1.3.1 (Aug 2013), which is the oldest stable version you can find on matpplotlib website. But after that it is quite trivial.
Because present version of matplotlib.pylab.scatter support assigning: array of colour name string, array of float number with colour map, array of RGB or RGBA.
this answer is dedicate to @Oxinabox’s endless passion for correcting the 2013 version of myself in 2015.
you have two option of using scatter command with multiple colour in a single call.
as pylab.scatter command support use RGBA array to do whatever colour you want;
back in early 2013, there is no way to do so, since the command only support single colour for the whole scatter point collection. When I was doing my 10000-line project I figure out a general solution to bypass it. so it is very tacky, but I can do it in whatever shape, colour, size and transparent. this trick also could be apply to draw path collection, line collection….
the code is also inspired by the source code of pyplot.scatter, I just duplicated what scatter does without trigger it to draw.
the command pyplot.scatter return a PatchCollection Object, in the file “matplotlib/collections.py” a private variable _facecolors in Collection class and a method set_facecolors.
so whenever you have a scatter points to draw you can do this:
# rgbaArr is a N*4 array of float numbers you know what I mean
# X is a N*2 array of coordinates
# axx is the axes object that current draw, you get it from
# axx = fig.gca()
# also import these, to recreate the within env of scatter command
import matplotlib.markers as mmarkers
import matplotlib.transforms as mtransforms
from matplotlib.collections import PatchCollection
import matplotlib.markers as mmarkers
import matplotlib.patches as mpatches
# define this function
# m is a string of scatter marker, it could be 'o', 's' etc..
# s is the size of the point, use 1.0
# dpi, get it from axx.figure.dpi
def addPatch_point(m, s, dpi):
marker_obj = mmarkers.MarkerStyle(m)
path = marker_obj.get_path()
trans = mtransforms.Affine2D().scale(np.sqrt(s*5)*dpi/72.0)
ptch = mpatches.PathPatch(path, fill = True, transform = trans)
return ptch
patches = []
# markerArr is an array of maker string, ['o', 's'. 'o'...]
# sizeArr is an array of size float, [1.0, 1.0. 0.5...]
for m, s in zip(markerArr, sizeArr):
patches.append(addPatch_point(m, s, axx.figure.dpi))
pclt = PatchCollection(
patches,
offsets = zip(X[:,0], X[:,1]),
transOffset = axx.transData)
pclt.set_transform(mtransforms.IdentityTransform())
pclt.set_edgecolors('none') # it's up to you
pclt._facecolors = rgbaArr
# in the end, when you decide to draw
axx.add_collection(pclt)
# and call axx's parent to draw_idle()
回答 5
这对我有用:
对于每个系列,请使用随机的RGB颜色生成器
c = color[np.random.random_sample(), np.random.random_sample(), np.random.random_sample()]
for each series, use a random rgb colour generator
c = color[np.random.random_sample(), np.random.random_sample(), np.random.random_sample()]
回答 6
对于大型数据集和有限数量的颜色,一种更快的解决方案是使用Pandas和groupby函数:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import time
# a generic set of data with associated colors
nsamples=1000
x=np.random.uniform(0,10,nsamples)
y=np.random.uniform(0,10,nsamples)
colors={0:'r',1:'g',2:'b',3:'k'}
c=[colors[i]for i in np.round(np.random.uniform(0,3,nsamples),0)]
plt.close('all')# "Fast" Scatter plotting
starttime=time.time()# 1) make a dataframe
df=pd.DataFrame()
df['x']=x
df['y']=y
df['c']=c
plt.figure()# 2) group the dataframe by color and loopfor g,b in df.groupby(by='c'):
plt.scatter(b['x'],b['y'],color=g)print('Fast execution time:', time.time()-starttime)# "Slow" Scatter plotting
starttime=time.time()
plt.figure()# 2) group the dataframe by color and loopfor i in range(len(x)):
plt.scatter(x[i],y[i],color=c[i])print('Slow execution time:', time.time()-starttime)
plt.show()
A MUCH faster solution for large dataset and limited number of colors is the use of Pandas and the groupby function:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import time
# a generic set of data with associated colors
nsamples=1000
x=np.random.uniform(0,10,nsamples)
y=np.random.uniform(0,10,nsamples)
colors={0:'r',1:'g',2:'b',3:'k'}
c=[colors[i] for i in np.round(np.random.uniform(0,3,nsamples),0)]
plt.close('all')
# "Fast" Scatter plotting
starttime=time.time()
# 1) make a dataframe
df=pd.DataFrame()
df['x']=x
df['y']=y
df['c']=c
plt.figure()
# 2) group the dataframe by color and loop
for g,b in df.groupby(by='c'):
plt.scatter(b['x'],b['y'],color=g)
print('Fast execution time:', time.time()-starttime)
# "Slow" Scatter plotting
starttime=time.time()
plt.figure()
# 2) group the dataframe by color and loop
for i in range(len(x)):
plt.scatter(x[i],y[i],color=c[i])
print('Slow execution time:', time.time()-starttime)
plt.show()
I cannot get the colorbar on imshow graphs like this one to be the same height as the graph, short of using Photoshop after the fact. How do I get the heights to match?
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
plt.figure()
ax = plt.gca()
im = ax.imshow(np.arange(100).reshape((10,10)))# create an axes on the right side of ax. The width of cax will be 5%# of ax and the padding between cax and ax will be fixed at 0.05 inch.
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(im, cax=cax)
You can do this easily with a matplotlib AxisDivider.
The example from the linked page also works without using subplots:
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
plt.figure()
ax = plt.gca()
im = ax.imshow(np.arange(100).reshape((10,10)))
# create an axes on the right side of ax. The width of cax will be 5%
# of ax and the padding between cax and ax will be fixed at 0.05 inch.
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(im, cax=cax)
@bogatron already gave the answer suggested by the matplotlib docs, which produces the right height, but it introduces a different problem.
Now the width of the colorbar (as well as the space between colorbar and plot) changes with the width of the plot.
In other words, the aspect ratio of the colorbar is not fixed anymore.
To get both the right height and a given aspect ratio, you have to dig a bit deeper into the mysterious axes_grid1 module.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable, axes_size
import numpy as np
aspect = 20
pad_fraction = 0.5
ax = plt.gca()
im = ax.imshow(np.arange(200).reshape((20, 10)))
divider = make_axes_locatable(ax)
width = axes_size.AxesY(ax, aspect=1./aspect)
pad = axes_size.Fraction(pad_fraction, width)
cax = divider.append_axes("right", size=width, pad=pad)
plt.colorbar(im, cax=cax)
Note that this specifies the width of the colorbar w.r.t. the height of the plot (in contrast to the width of the figure, as it was before).
The spacing between colorbar and plot can now be specified as a fraction of the width of the colorbar, which is IMHO a much more meaningful number than a fraction of the figure width.
import matplotlib.pyplot as plt
import numpy as np
fig=plt.figure()
ax = plt.axes()
im = ax.imshow(np.arange(100).reshape((10,10)))# Create an axes for colorbar. The position of the axes is calculated based on the position of ax.# You can change 0.01 to adjust the distance between the main image and the colorbar.# You can change 0.02 to adjust the width of the colorbar.# This practice is universal for both subplots and GeoAxes.
cax = fig.add_axes([ax.get_position().x1+0.01,ax.get_position().y0,0.02,ax.get_position().height])
plt.colorbar(im, cax=cax)# Similar to fig.colorbar(im, cax = cax)
I appreciate all the answers above. However, like some answers and comments pointed out, the axes_grid1 module cannot address GeoAxes, whereas adjusting fraction, pad, shrink, and other similar parameters cannot necessarily give the very precise order, which really bothers me. I believe that giving the colorbar its own axes might be a better solution to address all the issues that have been mentioned.
Code
import matplotlib.pyplot as plt
import numpy as np
fig=plt.figure()
ax = plt.axes()
im = ax.imshow(np.arange(100).reshape((10,10)))
# Create an axes for colorbar. The position of the axes is calculated based on the position of ax.
# You can change 0.01 to adjust the distance between the main image and the colorbar.
# You can change 0.02 to adjust the width of the colorbar.
# This practice is universal for both subplots and GeoAxes.
cax = fig.add_axes([ax.get_position().x1+0.01,ax.get_position().y0,0.02,ax.get_position().height])
plt.colorbar(im, cax=cax) # Similar to fig.colorbar(im, cax = cax)
Result
Later on, I find matplotlib.pyplot.colorbar official documentation also gives ax option, which are existing axes that will provide room for the colorbar. Therefore, it is useful for multiple subplots, see following.
Therefore, the only universal way of dealing colorbar size with all types of axes is:
ax.colorbar(im, fraction=0.046, pad=0.04)
Work with fraction from 0.035 to 0.046 to get your best size. However, the values for the fraction and paddig will need to be adjusted to get the best fit for your plot and will differ depending if the orientation of the colorbar is in vertical position or horizontal.
Alternatively, if you want to simply set the number of ticks while allowing matplotlib to position them (currently only with MaxNLocator), there is pyplot.locator_params,
pyplot.locator_params(nbins=4)
You can specify specific axis in this method as mentioned below, default is both:
# To specify the number of ticks on both or any single axes
pyplot.locator_params(axis='y', nbins=6)
pyplot.locator_params(axis='x', nbins=10)
回答 1
如果仍然有人在搜索结果中获得此页面:
fig, ax = plt.subplots()
plt.plot(...)
every_nth =4for n, label in enumerate(ax.xaxis.get_ticklabels()):if n % every_nth !=0:
label.set_visible(False)
If somebody still gets this page in search results:
fig, ax = plt.subplots()
plt.plot(...)
every_nth = 4
for n, label in enumerate(ax.xaxis.get_ticklabels()):
if n % every_nth != 0:
label.set_visible(False)
in case somebody still needs it, and since nothing
here really worked for me, i came up with a very
simple way that keeps the appearance of the
generated plot “as is” while fixing the number
of ticks to exactly N:
The solution @raphael gave is straightforward and quite helpful.
Still, the displayed tick labels will not be values sampled from the original distribution but from the indexes of the array returned by np.linspace(ymin, ymax, N).
To display N values evenly spaced from your original tick labels, use the set_yticklabels() method. Here is a snippet for the y axis, with integer labels:
import numpy as np
import matplotlib.pyplot as plt
ax = plt.gca()
ymin, ymax = ax.get_ylim()
custom_ticks = np.linspace(ymin, ymax, N, dtype=int)
ax.set_yticks(custom_ticks)
ax.set_yticklabels(custom_ticks)
回答 6
使用对数刻度时,可以使用以下命令固定主要刻度数
import matplotlib.pyplot as plt
....
plt.locator_params(numticks=12)
plt.show()
works perfect with pyplot.figure, but with matplotlib.Figure it only removes the gray background, the frame stays . Also, I only want the lines to show, and all the rest of figure be transparent.
with pyplot I can do what I want, I want to do it with matplotlib for some long reason I ‘d rather not mention to extend my question.
First off, if you’re using savefig, be aware that it will override the figure’s background color when saving unless you specify otherwise (e.g. fig.savefig('blah.png', transparent=True)).
However, to remove the axes’ and figure’s background on-screen, you’ll need to set both ax.patch and fig.patch to be invisible.
E.g.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(range(10))
for item in [fig, ax]:
item.patch.set_visible(False)
with open('test.png', 'w') as outfile:
fig.canvas.print_png(outfile)
(Of course, you can’t tell the difference on SO’s white background, but everything is transparent…)
If you don’t want to show anything other than the line, turn the axis off as well using ax.axis('off'):
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(range(10))
fig.patch.set_visible(False)
ax.axis('off')
with open('test.png', 'w') as outfile:
fig.canvas.print_png(outfile)
In that case, though, you may want to make the axes take up the full figure. If you manually specify the location of the axes, you can tell it to take up the full figure (alternately, you can use subplots_adjust, but this is simpler for the case of a single axes).
import matplotlib.pyplot as plt
fig = plt.figure(frameon=False)
ax = fig.add_axes([0, 0, 1, 1])
ax.axis('off')
ax.plot(range(10))
with open('test.png', 'w') as outfile:
fig.canvas.print_png(outfile)
ax.axis('off'), will as Joe Kington pointed out, remove everything except the plotted line.
For those wanting to only remove the frame (border), and keep labels, tickers etc, one can do that by accessing the spines object on the axis. Given an axis object ax, the following should remove borders on all four sides:
import matplotlib.pyplot as plt
import numpy as np
plt.figure()
xvals = list('ABCDE')
yvals = np.array(range(1,6))
position = np.arange(len(xvals))
mybars = plt.bar(position, yvals, align='center', linewidth=0)
plt.xticks(position, xvals)
plt.title('My great data')# plt.show()# get rid of the framefor spine in plt.gca().spines.values():
spine.set_visible(False)# plt.show()# remove all the ticks and directly label each bar with respective value
plt.tick_params(top='off', bottom='off', left='off', right='off', labelleft='off', labelbottom='on')# plt.show()# direct label each bar with Y axis valuesfor bari in mybars:
height = bari.get_height()
plt.gca().text(bari.get_x()+ bari.get_width()/2, bari.get_height()-0.2, str(int(height)),
ha='center', color='white', fontsize=15)
plt.show()
In this case, one can then label the bars directly; the final plot could look like this (code can be found below):
Here is the entire code that is necessary to generate the plots:
import matplotlib.pyplot as plt
import numpy as np
plt.figure()
xvals = list('ABCDE')
yvals = np.array(range(1, 6))
position = np.arange(len(xvals))
mybars = plt.bar(position, yvals, align='center', linewidth=0)
plt.xticks(position, xvals)
plt.title('My great data')
# plt.show()
# get rid of the frame
for spine in plt.gca().spines.values():
spine.set_visible(False)
# plt.show()
# remove all the ticks and directly label each bar with respective value
plt.tick_params(top='off', bottom='off', left='off', right='off', labelleft='off', labelbottom='on')
# plt.show()
# direct label each bar with Y axis values
for bari in mybars:
height = bari.get_height()
plt.gca().text(bari.get_x() + bari.get_width()/2, bari.get_height()-0.2, str(int(height)),
ha='center', color='white', fontsize=15)
plt.show()
data = range(100)import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(data)#ax.set(frameon=False) # Old
ax.set(frame_on=False)# New
plt.show()
I had a similar problem using axes. The class parameter is frameon but the kwarg is frame_on. axes_api >>> plt.gca().set(frameon=False) AttributeError: Unknown property frameon
Solution
frame_on
Example
data = range(100)
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(data)
#ax.set(frameon=False) # Old
ax.set(frame_on=False) # New
plt.show()
surprisingly I didn’t find a straight-forward description on how to draw a circle with matplotlib.pyplot (please no pylab) taking as input center (x,y) and radius r. I tried some variants of this:
import matplotlib.pyplot as plt
circle=plt.Circle((0,0),2)
# here must be something like circle.plot() or not?
plt.show()
import matplotlib.pyplot as plt
circle1 = plt.Circle((0,0),0.2, color='r')
circle2 = plt.Circle((0.5,0.5),0.2, color='blue')
circle3 = plt.Circle((1,1),0.2, color='g', clip_on=False)
fig, ax = plt.subplots()# note we must use plt.subplots, not plt.subplot# (or if you have an existing figure)# fig = plt.gcf()# ax = fig.gca()
ax.add_artist(circle1)
ax.add_artist(circle2)
ax.add_artist(circle3)
fig.savefig('plotcircles.png')
circle1 = plt.Circle((0,0),2, color='r')# now make a circle with no fill, which is good for hi-lighting key results
circle2 = plt.Circle((5,5),0.5, color='b', fill=False)
circle3 = plt.Circle((10,10),2, color='g', clip_on=False)
ax = plt.gca()
ax.cla()# clear things for fresh plot# change default range so that new circles will work
ax.set_xlim((0,10))
ax.set_ylim((0,10))# some data
ax.plot(range(11),'o', color='black')# key data point that we are encircling
ax.plot((5),(5),'o', color='y')
ax.add_artist(circle1)
ax.add_artist(circle2)
ax.add_artist(circle3)
fig.savefig('plotcircles2.png')
You need to add it to an axes. A Circle is a subclass of an Artist, and an axes has an add_artist method.
Here’s an example of doing this:
import matplotlib.pyplot as plt
circle1 = plt.Circle((0, 0), 0.2, color='r')
circle2 = plt.Circle((0.5, 0.5), 0.2, color='blue')
circle3 = plt.Circle((1, 1), 0.2, color='g', clip_on=False)
fig, ax = plt.subplots() # note we must use plt.subplots, not plt.subplot
# (or if you have an existing figure)
# fig = plt.gcf()
# ax = fig.gca()
ax.add_artist(circle1)
ax.add_artist(circle2)
ax.add_artist(circle3)
fig.savefig('plotcircles.png')
This results in the following figure:
The first circle is at the origin, but by default clip_on is True, so the circle is clipped when ever it extends beyond the axes. The third (green) circle shows what happens when you don’t clip the Artist. It extends beyond the axes (but not beyond the figure, ie the figure size is not automatically adjusted to plot all of your artists).
The units for x, y and radius correspond to data units by default. In this case, I didn’t plot anything on my axes (fig.gca() returns the current axes), and since the limits have never been set, they defaults to an x and y range from 0 to 1.
Here’s a continuation of the example, showing how units matter:
circle1 = plt.Circle((0, 0), 2, color='r')
# now make a circle with no fill, which is good for hi-lighting key results
circle2 = plt.Circle((5, 5), 0.5, color='b', fill=False)
circle3 = plt.Circle((10, 10), 2, color='g', clip_on=False)
ax = plt.gca()
ax.cla() # clear things for fresh plot
# change default range so that new circles will work
ax.set_xlim((0, 10))
ax.set_ylim((0, 10))
# some data
ax.plot(range(11), 'o', color='black')
# key data point that we are encircling
ax.plot((5), (5), 'o', color='y')
ax.add_artist(circle1)
ax.add_artist(circle2)
ax.add_artist(circle3)
fig.savefig('plotcircles2.png')
which results in:
You can see how I set the fill of the 2nd circle to False, which is useful for encircling key results (like my yellow data point).
回答 1
import matplotlib.pyplot as plt
circle1=plt.Circle((0,0),.2,color='r')
plt.gcf().gca().add_artist(circle1)
import matplotlib.pyplot as plt
circle1=plt.Circle((0,0),.2,color='r')
plt.gcf().gca().add_artist(circle1)
A quick condensed version of the accepted answer, to quickly plug a circle into an existing plot. Refer to the accepted answer and other answers to understand the details.
from pylab import*
figure(figsize=(8,8))
ax=subplot(aspect='equal')#plot one circle (the biggest one on bottom-right)
circles(1,0,0.5,'r', alpha=0.2, lw=5, edgecolor='b', transform=ax.transAxes)#plot a set of circles (circles in diagonal)
a=arange(11)
out = circles(a, a, a*0.2, c=a, alpha=0.5, edgecolor='none')
colorbar(out)
xlim(0,10)
ylim(0,10)
If you want to plot a set of circles, you might want to see this post or this gist(a bit newer). The post offered a function named circles.
The function circles works like scatter, but the sizes of plotted circles are in data unit.
Here’s an example:
from pylab import *
figure(figsize=(8,8))
ax=subplot(aspect='equal')
#plot one circle (the biggest one on bottom-right)
circles(1, 0, 0.5, 'r', alpha=0.2, lw=5, edgecolor='b', transform=ax.transAxes)
#plot a set of circles (circles in diagonal)
a=arange(11)
out = circles(a, a, a*0.2, c=a, alpha=0.5, edgecolor='none')
colorbar(out)
xlim(0,10)
ylim(0,10)
回答 3
#!/usr/bin/pythonimport matplotlib.pyplot as plt
import numpy as np
def xy(r,phi):return r*np.cos(phi), r*np.sin(phi)
fig = plt.figure()
ax = fig.add_subplot(111,aspect='equal')
phis=np.arange(0,6.28,0.01)
r =1.
ax.plot(*xy(r,phis), c='r',ls='-')
plt.show()
import matplotlib.pyplot as plt
x =[1,2,3,4,5]
y =[10,20,30,40,50]
r =[100,80,60,40,20]# in points, not data units
fig, ax = plt.subplots(1,1)
ax.scatter(x, y, s=r)
fig.show()
import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y = [10, 20, 30, 40, 50]
r = [100, 80, 60, 40, 20] # in points, not data units
fig, ax = plt.subplots(1, 1)
ax.scatter(x, y, s=r)
fig.show()
回答 5
将常见问题扩展为可接受的答案。特别是:
以自然的长宽比查看圈子。
自动扩展轴限制以包括新绘制的圆。
独立的示例:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.add_patch(plt.Circle((0,0),0.2, color='r', alpha=0.5))
ax.add_patch(plt.Circle((1,1),0.5, color='#00ffff', alpha=0.5))
ax.add_artist(plt.Circle((1,0),0.5, color='#000033', alpha=0.5))#Use adjustable='box-forced' to make the plot area square-shaped as well.
ax.set_aspect('equal', adjustable='datalim')
ax.plot()#Causes an autoscale update.
plt.show()
Extending the accepted answer for a common usecase. In particular:
View the circles at a natural aspect ratio.
Automatically extend the axes limits to include the newly plotted circles.
Self-contained example:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.add_patch(plt.Circle((0, 0), 0.2, color='r', alpha=0.5))
ax.add_patch(plt.Circle((1, 1), 0.5, color='#00ffff', alpha=0.5))
ax.add_artist(plt.Circle((1, 0), 0.5, color='#000033', alpha=0.5))
#Use adjustable='box-forced' to make the plot area square-shaped as well.
ax.set_aspect('equal', adjustable='datalim')
ax.plot() #Causes an autoscale update.
plt.show()
Note the difference between ax.add_patch(..) and ax.add_artist(..): of the two, only the former makes autoscaling machinery take the circle into account (reference: discussion), so after running the above code we get:
import matplotlib.pyplot as plt
import numpy as np
x = list(range(1,6))
y = list(range(10,20,2))print(x, y)for i, data in enumerate(zip(x,y)):
j, k = data
plt.scatter(j,k, marker ="o", s =((i+1)**4)*50, alpha =0.3)
centers = np.array([[5,18],[3,14],[7,6]])
m, n = make_blobs(n_samples=20, centers=[[5,18],[3,14],[7,6]], n_features=2,
cluster_std =0.4)
colors =['g','b','r','m']
plt.figure(num=None, figsize=(7,6), facecolor='w', edgecolor='k')
plt.scatter(m[:,0], m[:,1])for i in range(len(centers)):
plt.scatter(centers[i,0], centers[i,1], color = colors[i], marker ='o', s =13000, alpha =0.2)
plt.scatter(centers[i,0], centers[i,1], color ='k', marker ='x', s =50)
plt.savefig('plot.png')
I see plots with the use of (.circle) but based on what you might want to do you can also try this out:
import matplotlib.pyplot as plt
import numpy as np
x = list(range(1,6))
y = list(range(10, 20, 2))
print(x, y)
for i, data in enumerate(zip(x,y)):
j, k = data
plt.scatter(j,k, marker = "o", s = ((i+1)**4)*50, alpha = 0.3)
centers = np.array([[5,18], [3,14], [7,6]])
m, n = make_blobs(n_samples=20, centers=[[5,18], [3,14], [7,6]], n_features=2,
cluster_std = 0.4)
colors = ['g', 'b', 'r', 'm']
plt.figure(num=None, figsize=(7,6), facecolor='w', edgecolor='k')
plt.scatter(m[:,0], m[:,1])
for i in range(len(centers)):
plt.scatter(centers[i,0], centers[i,1], color = colors[i], marker = 'o', s = 13000, alpha = 0.2)
plt.scatter(centers[i,0], centers[i,1], color = 'k', marker = 'x', s = 50)
plt.savefig('plot.png')
I’m having issues with redrawing the figure here. I allow the user to specify the units in the time scale (x-axis) and then I recalculate and call this function plots(). I want the plot to simply update, not append another plot to the figure.
def plots():
global vlgaBuffSorted
cntr()
result = collections.defaultdict(list)
for d in vlgaBuffSorted:
result[d['event']].append(d)
result_list = result.values()
f = Figure()
graph1 = f.add_subplot(211)
graph2 = f.add_subplot(212,sharex=graph1)
for item in result_list:
tL = []
vgsL = []
vdsL = []
isubL = []
for dict in item:
tL.append(dict['time'])
vgsL.append(dict['vgs'])
vdsL.append(dict['vds'])
isubL.append(dict['isub'])
graph1.plot(tL,vdsL,'bo',label='a')
graph1.plot(tL,vgsL,'rp',label='b')
graph2.plot(tL,isubL,'b-',label='c')
plotCanvas = FigureCanvasTkAgg(f, pltFrame)
toolbar = NavigationToolbar2TkAgg(plotCanvas, pltFrame)
toolbar.pack(side=BOTTOM)
plotCanvas.get_tk_widget().pack(side=TOP)
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0,6*np.pi,100)
y = np.sin(x)# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
line1,= ax.plot(x, y,'r-')# Returns a tuple of line objects, thus the commafor phase in np.linspace(0,10*np.pi,500):
line1.set_ydata(np.sin(x + phase))
fig.canvas.draw()
fig.canvas.flush_events()
Do exactly what you’re currently doing, but call graph1.clear() and graph2.clear() before replotting the data. This is the slowest, but most simplest and most robust option.
Instead of replotting, you can just update the data of the plot objects. You’ll need to make some changes in your code, but this should be much, much faster than replotting things every time. However, the shape of the data that you’re plotting can’t change, and if the range of your data is changing, you’ll need to manually reset the x and y axis limits.
To give an example of the second option:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 6*np.pi, 100)
y = np.sin(x)
# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
line1, = ax.plot(x, y, 'r-') # Returns a tuple of line objects, thus the comma
for phase in np.linspace(0, 10*np.pi, 500):
line1.set_ydata(np.sin(x + phase))
fig.canvas.draw()
fig.canvas.flush_events()
回答 1
您还可以执行以下操作:这将在for循环的50个循环的绘图上绘制10×1随机矩阵数据。
import matplotlib.pyplot as plt
import numpy as np
plt.ion()for i in range(50):
y = np.random.random([10,1])
plt.plot(y)
plt.draw()
plt.pause(0.0001)
plt.clf()
You can also do like the following:
This will draw a 10×1 random matrix data on the plot for 50 cycles of the for loop.
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
for i in range(50):
y = np.random.random([10,1])
plt.plot(y)
plt.draw()
plt.pause(0.0001)
plt.clf()
回答 2
这对我有用。每次重复调用更新图形的函数。
import matplotlib.pyplot as plt
import matplotlib.animation as anim
def plot_cont(fun, xmax):
y =[]
fig = plt.figure()
ax = fig.add_subplot(1,1,1)def update(i):
yi = fun()
y.append(yi)
x = range(len(y))
ax.clear()
ax.plot(x, y)print i,': ', yi
a = anim.FuncAnimation(fig, update, frames=xmax, repeat=False)
plt.show()
from pylab import figure, plot, ion, linspace, arange, sin, pi
def draw_fig():# can be arbitrarily complex; just to draw a figure#figure() # don't call!
plot(t, x)#show() # don't call!
N =1e3
figure()# call here instead!
ion()# enable interactivity
t = linspace(0,2*pi, num=N)for i in arange(100):
x = sin(2* pi * i**2* t /100.0)
drawnow(draw_fig)
I have released a package called python-drawnow that provides functionality to let a figure update, typically called within a for loop, similar to Matlab’s drawnow.
An example usage:
from pylab import figure, plot, ion, linspace, arange, sin, pi
def draw_fig():
# can be arbitrarily complex; just to draw a figure
#figure() # don't call!
plot(t, x)
#show() # don't call!
N = 1e3
figure() # call here instead!
ion() # enable interactivity
t = linspace(0, 2*pi, num=N)
for i in arange(100):
x = sin(2 * pi * i**2 * t / 100.0)
drawnow(draw_fig)
This package works with any matplotlib figure and provides options to wait after each figure update or drop into the debugger.
All of the above might be true, however for me “online-updating” of figures only works with some backends, specifically wx. You just might try to change to this, e.g. by starting ipython/pylab by ipython --pylab=wx! Good luck!
回答 6
这对我有用:
from matplotlib import pyplot as plt
fromIPython.display import clear_output
import numpy as np
for i in range(50):
clear_output(wait=True)
y = np.random.random([10,1])
plt.plot(y)
plt.show()
from matplotlib import pyplot as plt
from IPython.display import clear_output
import numpy as np
for i in range(50):
clear_output(wait=True)
y = np.random.random([10,1])
plt.plot(y)
plt.show()
import matplotlib.pyplot as plt
x = range(10)
y = range(10)
fig, ax = plt.subplots(nrows=2, ncols=2)for row in ax:for col in row:
col.plot(x, y)
plt.show()
There are several ways to do it. The subplots method creates the figure along with the subplots that are then stored in the ax array. For example:
import matplotlib.pyplot as plt
x = range(10)
y = range(10)
fig, ax = plt.subplots(nrows=2, ncols=2)
for row in ax:
for col in row:
col.plot(x, y)
plt.show()
However, something like this will also work, it’s not so “clean” though since you are creating a figure with subplots and then add on top of them:
Figure class now has subplots method
The Figure class now has a subplots() method which behaves the same as pyplot.subplots() but on an existing figure.
So this produces a graph of the values ‘v’ on the axes X vs Y, using the specified colormap. The X and Y axes are perfect, but the colormap spreads between the min and max of v. I would like to force the colormap to range between 0 and 1.
I thought of using:
plt.axis(...)
To set the ranges of the axes, but this only takes arguments for the min and max of X and Y, not the colormap.
Edit:
For clarity, let’s say I have one graph whose values range (0 … 0.3), and another graph whose values (0.2 … 0.8).
In both graphs, I will want the range of the colorbar to be (0 … 1). In both graphs, I want this range of colour to be identical using the full range of cdict above (so 0.25 in both graphs will be the same colour). In the first graph, all colours between 0.3 and 1.0 won’t feature in the graph, but will in the colourbar key at the side. In the other, all colours between 0 and 0.2, and between 0.8 and 1 will not feature in the graph, but will in the colourbar at the side.
回答 0
使用vmin并vmax强制使用颜色范围。这是一个例子:
import matplotlib as m
import matplotlib.pyplot as plt
import numpy as np
cdict ={'red':((0.0,0.25,.25),(0.02,.59,.59),(1.,1.,1.)),'green':((0.0,0.0,0.0),(0.02,.45,.45),(1.,.97,.97)),'blue':((0.0,1.0,1.0),(0.02,.75,.75),(1.,0.45,0.45))}
cm = m.colors.LinearSegmentedColormap('my_colormap', cdict,1024)
x = np.arange(0,10,.1)
y = np.arange(0,10,.1)
X, Y = np.meshgrid(x,y)
data =2*( np.sin(X)+ np.sin(3*Y))def do_plot(n, f, title):#plt.clf()
plt.subplot(1,3, n)
plt.pcolor(X, Y, f(data), cmap=cm, vmin=-4, vmax=4)
plt.title(title)
plt.colorbar()
plt.figure()
do_plot(1,lambda x:x,"all")
do_plot(2,lambda x:np.clip(x,-4,0),"<0")
do_plot(3,lambda x:np.clip(x,0,4),">0")
plt.show()
Not sure if this is the most elegant solution (this is what I used), but you could scale your data to the range between 0 to 1 and then modify the colorbar:
With the two different limits you can control the range and legend of the colorbar. In this example only the range between -0.5 to 1.5 is show in the bar, while the colormap covers -2 to 2 (so this could be your data range, which you record before the scaling).
So instead of scaling the colormap you scale your data and fit the colorbar to that.
回答 3
使用图形环境和.set_clim()
如果您有多个图,可能会更容易,更安全地进行此选择:
import matplotlib as m
import matplotlib.pyplot as plt
import numpy as np
cdict ={'red':((0.0,0.25,.25),(0.02,.59,.59),(1.,1.,1.)),'green':((0.0,0.0,0.0),(0.02,.45,.45),(1.,.97,.97)),'blue':((0.0,1.0,1.0),(0.02,.75,.75),(1.,0.45,0.45))}
cm = m.colors.LinearSegmentedColormap('my_colormap', cdict,1024)
x = np.arange(0,10,.1)
y = np.arange(0,10,.1)
X, Y = np.meshgrid(x,y)
data =2*( np.sin(X)+ np.sin(3*Y))
data1 = np.clip(data,0,6)
data2 = np.clip(data,-6,0)
vmin = np.min(np.array([data,data1,data2]))
vmax = np.max(np.array([data,data1,data2]))
fig = plt.figure()
ax = fig.add_subplot(131)
mesh = ax.pcolormesh(data, cmap = cm)
mesh.set_clim(vmin,vmax)
ax1 = fig.add_subplot(132)
mesh1 = ax1.pcolormesh(data1, cmap = cm)
mesh1.set_clim(vmin,vmax)
ax2 = fig.add_subplot(133)
mesh2 = ax2.pcolormesh(data2, cmap = cm)
mesh2.set_clim(vmin,vmax)# Visualizing colorbar part -start
fig.colorbar(mesh,ax=ax)
fig.colorbar(mesh1,ax=ax1)
fig.colorbar(mesh2,ax=ax2)
fig.tight_layout()# Visualizing colorbar part -end
plt.show()
The best alternative is then to use a single color bar for the entire plot. There are different ways to do that, this tutorial is very useful for understanding the best option. I prefer this solution that you can simply copy and paste instead of the previous visualizing colorbar part of the code.
I want to make a scatterplot (using matplotlib) where the points are shaded according to a third variable. I’ve got very close with this:
plt.scatter(w, M, c=p, marker='s')
where w and M are the datapoints and p is the variable I want to shade with respect to.
However I want to do it in greyscale rather than colour. Can anyone help?
回答 0
无需手动设置颜色。相反,请指定灰度颜色图…
import numpy as np
import matplotlib.pyplot as plt
# Generate data...
x = np.random.random(10)
y = np.random.random(10)# Plot...
plt.scatter(x, y, c=y, s=500)
plt.gray()
plt.show()
import matplotlib.pyplot as plt
import numpy as np
# Generate data...
x = np.random.random(10)
y = np.random.random(10)
plt.scatter(x, y, c=y, s=500, cmap='gray')
plt.show()
There’s no need to manually set the colors. Instead, specify a grayscale colormap…
import numpy as np
import matplotlib.pyplot as plt
# Generate data...
x = np.random.random(10)
y = np.random.random(10)
# Plot...
plt.scatter(x, y, c=y, s=500)
plt.gray()
plt.show()
Or, if you’d prefer a wider range of colormaps, you can also specify the cmap kwarg to scatter. To use the reversed version of any of these, just specify the “_r” version of any of them. E.g. gray_r instead of gray. There are several different grayscale colormaps pre-made (e.g. gray, gist_yarg, binary, etc).
import matplotlib.pyplot as plt
import numpy as np
# Generate data...
x = np.random.random(10)
y = np.random.random(10)
plt.scatter(x, y, c=y, s=500, cmap='gray')
plt.show()
from matplotlib import pyplot as plt
x =[1,2,3,4,5,6,7,8,9]
y =[125,32,54,253,67,87,233,56,67]
color =[str(item/255.)for item in y]
plt.scatter(x, y, s=500, c=color)
plt.show()
In matplotlib grey colors can be given as a string of a numerical value between 0-1.
For example c = '0.1'
Then you can convert your third variable in a value inside this range and to use it to color your points.
In the following example I used the y position of the point as the value that determines the color:
from matplotlib import pyplot as plt
x = [1, 2, 3, 4, 5, 6, 7, 8, 9]
y = [125, 32, 54, 253, 67, 87, 233, 56, 67]
color = [str(item/255.) for item in y]
plt.scatter(x, y, s=500, c=color)
plt.show()
x=['A','B','B','C','A','B']
y=[15,30,25,18,22,13]# Function to map the colors as a list from the input list of x variablesdef pltcolor(lst):
cols=[]for l in lst:if l=='A':
cols.append('red')elif l=='B':
cols.append('blue')else:
cols.append('green')return cols
# Create the colors list using the function above
cols=pltcolor(x)
plt.scatter(x=x,y=y,s=500,c=cols)#Pass on the list created by the function here
plt.grid(True)
plt.show()
Sometimes you may need to plot color precisely based on the x-value case. For example, you may have a dataframe with 3 types of variables and some data points. And you want to do following,
Plot points corresponding to Physical variable ‘A’ in RED.
Plot points corresponding to Physical variable ‘B’ in BLUE.
Plot points corresponding to Physical variable ‘C’ in GREEN.
In this case, you may have to write to short function to map the x-values to corresponding color names as a list and then pass on that list to the plt.scatter command.
x=['A','B','B','C','A','B']
y=[15,30,25,18,22,13]
# Function to map the colors as a list from the input list of x variables
def pltcolor(lst):
cols=[]
for l in lst:
if l=='A':
cols.append('red')
elif l=='B':
cols.append('blue')
else:
cols.append('green')
return cols
# Create the colors list using the function above
cols=pltcolor(x)
plt.scatter(x=x,y=y,s=500,c=cols) #Pass on the list created by the function here
plt.grid(True)
plt.show()
Say I have an image of size 3841 x 7195 pixels. I would like to save the contents of the figure to disk, resulting in an image of the exact size I specify in pixels.
No axis, no titles. Just the image. I don’t personally care about DPIs, as I only want to specify the size the image takes in the screen in disk in pixels.
I have read otherthreads, and they all seem to do conversions to inches and then specify the dimensions of the figure in inches and adjust dpi’s in some way. I would like to avoid dealing with the potential loss of accuracy that could result from pixel-to-inches conversions.
with no luck (Python complains that width and height must each be below 32768 (?))
From everything I have seen, matplotlib requires the figure size to be specified in inches and dpi, but I am only interested in the pixels the figure takes in disk. How can I do this?
To clarify: I am looking for a way to do this with matplotlib, and not with other image-saving libraries.
Matplotlib doesn’t work with pixels directly, but rather physical sizes and DPI. If you want to display a figure with a certain pixel size, you need to know the DPI of your monitor. For example this link will detect that for you.
If you have an image of 3841×7195 pixels it is unlikely that you monitor will be that large, so you won’t be able to show a figure of that size (matplotlib requires the figure to fit in the screen, if you ask for a size too large it will shrink to the screen size). Let’s imagine you want an 800×800 pixel image just for an example. Here’s how to show an 800×800 pixel image in my monitor (my_dpi=96):
So you basically just divide the dimensions in inches by your DPI.
If you want to save a figure of a specific size, then it is a different matter. Screen DPIs are not so important anymore (unless you ask for a figure that won’t fit in the screen). Using the same example of the 800×800 pixel figure, we can save it in different resolutions using the dpi keyword of savefig. To save it in the same resolution as the screen just use the same dpi:
plt.savefig('my_fig.png', dpi=my_dpi)
To to save it as an 8000×8000 pixel image, use a dpi 10 times larger:
plt.savefig('my_fig.png', dpi=my_dpi * 10)
Note that the setting of the DPI is not supported by all backends. Here, the PNG backend is used, but the pdf and ps backends will implement the size differently. Also, changing the DPI and sizes will also affect things like fontsize. A larger DPI will keep the same relative sizes of fonts and elements, but if you want smaller fonts for a larger figure you need to increase the physical size instead of the DPI.
Getting back to your example, if you want to save a image with 3841 x 7195 pixels, you could do the following:
plt.figure(figsize=(3.841, 7.195), dpi=100)
( your code ...)
plt.savefig('myfig.png', dpi=1000)
Note that I used the figure dpi of 100 to fit in most screens, but saved with dpi=1000 to achieve the required resolution. In my system this produces a png with 3840×7190 pixels — it seems that the DPI saved is always 0.02 pixels/inch smaller than the selected value, which will have a (small) effect on large image sizes. Some more discussion of this here.
回答 1
根据您的代码,这对我有用,生成了一个93Mb png图像,带有彩色噪声和所需的尺寸:
import matplotlib.pyplot as plt
import numpy
w =7195
h =3841
im_np = numpy.random.rand(h, w)
fig = plt.figure(frameon=False)
fig.set_size_inches(w,h)
ax = plt.Axes(fig,[0.,0.,1.,1.])
ax.set_axis_off()
fig.add_axes(ax)
ax.imshow(im_np, aspect='normal')
fig.savefig('figure.png', dpi=1)
import matplotlib.pyplot as plt
import numpy as np
def export_figure_matplotlib(arr, f_name, dpi=200, resize_fact=1, plt_show=False):"""
Export array as figure in original resolution
:param arr: array of image to save in original resolution
:param f_name: name of file where to save figure
:param resize_fact: resize facter wrt shape of arr, in (0, np.infty)
:param dpi: dpi of your screen
:param plt_show: show plot or not
"""
fig = plt.figure(frameon=False)
fig.set_size_inches(arr.shape[1]/dpi, arr.shape[0]/dpi)
ax = plt.Axes(fig,[0.,0.,1.,1.])
ax.set_axis_off()
fig.add_axes(ax)
ax.imshow(arr)
plt.savefig(f_name, dpi=(dpi * resize_fact))if plt_show:
plt.show()else:
plt.close()
Based on the accepted response by tiago, here is a small generic function that exports a numpy array to an image having the same resolution as the array:
import matplotlib.pyplot as plt
import numpy as np
def export_figure_matplotlib(arr, f_name, dpi=200, resize_fact=1, plt_show=False):
"""
Export array as figure in original resolution
:param arr: array of image to save in original resolution
:param f_name: name of file where to save figure
:param resize_fact: resize facter wrt shape of arr, in (0, np.infty)
:param dpi: dpi of your screen
:param plt_show: show plot or not
"""
fig = plt.figure(frameon=False)
fig.set_size_inches(arr.shape[1]/dpi, arr.shape[0]/dpi)
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)
ax.imshow(arr)
plt.savefig(f_name, dpi=(dpi * resize_fact))
if plt_show:
plt.show()
else:
plt.close()
As said in the previous reply by tiago, the screen DPI needs to be found first, which can be done here for instance: http://dpi.lv
I’ve added an additional argument resize_fact in the function which which you can export the image to 50% (0.5) of the original resolution, for instance.
#file_path = directory address where the image will be stored along with file name and extension#array = variable where the image is stored. I think for the original post this variable is im_np
plt.imsave(file_path, array)
#file_path = directory address where the image will be stored along with file name and extension
#array = variable where the image is stored. I think for the original post this variable is im_np
plt.imsave(file_path, array)