[matplotlib-devel] imshow with PS backend
Hi, I've just moved from MATLAB to matplotlib, and I'm really impressed with the quality of the PS figures it generates with usetex and the xpdf distiller. I've hit a couple of problems though, one I've manged to solve (patch against 0.87.4 attached) and the other I'd be greatful if you could help me with please. I've been using imshow to basically put a set of axes round an image produced my simulation code. Here's a minimal version of my script: -- from pylab import * rc('text', usetex=True) rc('ps', usedistiller="xpdf") figure(1,figsize=(6, 4)) im=imread('image.png') # a 301x318 image imshow(im,interpolation='nearest',extent=[0.98, 20, 0.01, 0.5]) axis('normal'); savefig('image.eps') The first problem I noticed is that the distilling process was causing some of my images to have (lossy) compression applied and others not. It turns out that it is a feature of ps2pdf that it tries to detect the content of the image and apply appropriate compression. You can over ride this distiller options. My patch adds a new rc option ps.image_compression that can be set to auto (preserves the current behaviour), DCTEncode (applies lossy JPEG compression), and FlateEncode (lossless compression). The distiller commands are embedded in the ps file. I looked at making it a flag on each image, but couldn't get it to work. Another way to do it is to pass extra command line options to ps2pdf (-dAutoFilterColorImages=false -sColorImageFilter=FlateEncode should do it for colour images). I thought embedding it in the PS file would be more flexible. My second problem involved the resolutions of the image. I'd like to preserve the resolution of my image in the PS output, but I can't figure out how to stop the image being resized and interpolated. Obviously you need to do this for the bitmap backends, but for vector ones surely you can just scale the original image in the vector output. Thanks in advance for you help and some great software! JIM --- --- matplotlib-0.87.4/lib/matplotlib/backends/backend_ps.py 2006-07-10 18:55:59.0 +0100 +++ matplotlib-0.87.4.new/lib/matplotlib/backends/backend_ps.py 2006-07-27 13:00:42.0 +0100 @@ -367,9 +367,11 @@ class RendererPS(RendererBase): if im.is_grayscale: h, w, bits = self._gray(im) imagecmd = "image" +imagetype="Gray" else: h, w, bits = self._rgb(im) imagecmd = "false 3 colorimage" +imagetype="Color" hexlines = '\n'.join(self._hex_lines(bits)) xscale, yscale = w, h @@ -381,7 +383,21 @@ class RendererPS(RendererBase): clipx,clipy,clipw,cliph = bbox.get_bounds() clip = '%s clipbox' % _nums_to_str(clipw, cliph, clipx, clipy) #y = figh-(y+h) -ps = """gsave + +distilleroptions_pre = '' +distilleroptions_post = '' +compressiontype=rcParams['ps.image_compression'] +if compressiontype != 'auto': +distilleroptions_pre=""" +/setdistillerparams where {pop} {userdict /setdistillerparams {pop} put} ifelse +<< /AutoFilter%(imagetype)sImages false +/%(imagetype)sImageFilter /%(compressiontype)s +>> setdistillerparams +""" % locals() +distilleroptions_post="""<< /AutoFilter%(imagetype)sImages true >> setdistillerparams +""" % locals() + +ps = """gsave%(distilleroptions_pre)s %(clip)s %(x)s %(y)s translate %(xscale)s %(yscale)s scale @@ -391,7 +407,7 @@ class RendererPS(RendererBase): currentfile DataString readhexstring pop } bind %(imagecmd)s %(hexlines)s -grestore +%(distilleroptions_post)sgrestore """ % locals() self._pswriter.write(ps) --- matplotlib-0.87.4/lib/matplotlib/__init__.py2006-07-12 03:23:59.0 +0100 +++ matplotlib-0.87.4.new/lib/matplotlib/__init__.py2006-07-27 12:08:40.0 +0100 @@ -646,6 +646,13 @@ xpdf unless xpdf-%s or later is installe raise ValueError('matplotlibrc ps.usedistiller must either be none, \ ghostscript or xpdf') +def validate_ps_image_compression(s): +if s in ('auto', 'FlateEncode', 'DCTEncode'): +return s +else: +raise ValueError('not a valid Image compression type for PS backend \ +must be one of auto, DCTEncode FlateEncode') + def validate_usetex(s): bl = validate_bool(s) if bl: @@ -860,6 +867,7 @@ defaultParams = { 'ps.papersize' : [ 'letter', validate_ps_papersize], # Set the papersize/type 'ps.useafm' : [ False, validate_bool], # Set PYTHONINSPECT 'ps.usedistiller' : [ False, validate_ps_distiller], # use ghostscript or xpdf to distill ps output +'ps.image_compression' : [ 'auto', validate_ps_image_compression], # type of image compression for the distiller to use. 'ps.distiller.res' : [6000, validate_int], # dpi 'pdf.compression' : [6, validate_int],# compression level from
Re: [matplotlib-devel] imshow with PS backend
> I'll look into this soon. I'm hesitant to add another rc option, maybe we can > consider using these settings as the defaults. I'll post again after I have > had a chance to play with it. Defaulting to lossless FlateEncode compression seems like a good idea, if the file is too big you can always run another distill cycle after wards manually. Another possibility would be to set the option based on the format of the image loaded (I'm sure I read somewhere that it is planned to support formats other than PNG). ie FlateEncode for GIF's and PNG's and DCTEncode for JPEG's. > The resolution for Postscript is 72 dpi, and I'm not sure this can be changed. > Would you send me an example postscript file along with the original png? Sure, http://jimmacdonald.co.uk/matplotlib/image.png http://jimmacdonald.co.uk/matplotlib/image.eps http://jimmacdonald.co.uk/matplotlib/image.py image.py generates image.eps from image.png. image.png is simple enough for ps2pdf not to use DCT encoding. Looking at the postscript shows that the image has resolution of 335x230 compared to the original of 318x301. JIM --- - Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys -- and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV ___ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
Re: [matplotlib-devel] imshow with PS backend
> Would you post an example where the ps2pdf flags make a big difference on the > output? I just tried with the above png, but I cant tell the difference > between the results with/without the new flags. http://jimmacdonald.co.uk/matplotlib/MPD_SinPulse_g0.500.png JIM --- - Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys -- and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV ___ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
Re: [matplotlib-devel] imshow with PS backend
> I don't think this is a problem with the postscript backend. You're rescaling > the image in your script. Try something like this: > > from pylab import * > > rc('text', usetex=True) > rc('ps', usedistiller="xpdf") > > figure(1,figsize=(6, 4)) > im=imread('image.png') > imshow(im,interpolation='nearest')#,extent=[0.98, 20, 0.01, 0.5]) > #axis('normal'); > savefig('image.eps') I just tried that and it still rescales the image, this time to 243x230. I've found I can use the figsize kwarg to control the resolution of the embedded image, but of course this means I can't have the figure the size I want it. JIM --- - Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys -- and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV ___ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
Re: [matplotlib-devel] imshow with PS backend
> There are two kinds of images in matplotlib -- AxesImage and > FigureImage. By definition, the AxesImage is interpolated to fit into > the Axes box. You can control the aspect ratio of the interpolation, > but it will be interpolated. FigureImage, on the other hand, performs > a pixel dump to the postscript canvas at the location you tell it to > -- see examples/figimage_demo.py. It should like you are more > interested in the latter. I've had a play with FigureImage and I can't see how to make it draw the image inside the axes, it seems to only draw it in the background. > If the figure image doesn't work for you, describe your use-case in > some detail and why neither work and we'll see if we can accommodate > it. OK, so imshow does exactly what I want. The only problem is the resampling. Each pixel represents a value calculated at a point on a 318x301 grid, so in resampling I loose or distort some of the fine detail. I do not understand why the image need to be resampled when using a vector based backend. I understand this is necessary for a raster backend, but surely with a vector backend you can just scale the image keeping the 318x301 resolution. I know this is possible in Postscript at least as I've produced the desired output by amalgamating two files. See http://jimmacdonald.co.uk/matplotlib/image_CORRECT_ps_hacked.eps I looked at using pcolor instead, but the postscript files where too big (~20MB) due to the large number of tiles (this is how I used to do it in matlab). JIM - Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys -- and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV ___ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
[matplotlib-devel] pcolor & colorbar with log normalised colour scale
Hi, I'm trying to do a pcolor plot with a log normalised colour scale. Following advice from past posts to this list I specialised the matplotlib.colors.normalize class, and passed an instance of that to pcolor using the norm kwarg. This works fine :-) But when I add a colorbar it goes wrong. The colorbar is labelled with the log of the values, rather than values, and the colour only fills the top third of the colorbar. Am I doing something wrong, or is this a problem with the colorbar? Any help would be much appreciated. I realise that as a work around I could do a pcolor of the log of my data and manually relabel the colorbar, but it would be nice to do it properly. I've attached an png of the output and the code. Just in case the attachments get stripped they are also available to download from: http://jimmacdonald.co.uk/pcolor_log.png http://jimmacdonald.co.uk/pcolor_log.py I'm running the svn version (r2898--- lastest as of yesterday) with numpy-1.0_rc1 on gentoo. Keep up the good work! Cheers, JIM --- pcolor_log.py Description: application/python pcolor_log.png Description: PNG image - Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV___ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
Re: [matplotlib-devel] pcolor & colorbar with log normalised colour scale
Hi Eric, Thanks for your reply. It made me realise a few things > But when I add a colorbar it goes wrong. The colorbar is labelled with > the log of the values, rather > than values, and the colour only fills the top third of the colorbar. In the absence of additional kwargs, colorbar uses norm.vmin and norm.vmax to determine the limits of the colorbar, and it uses a default formatter. It has no way of knowing that you have taken the log of your original values. Yes of course there is in inconsistency in my LogNorm class. norm.vmax will return the log of the maximum, when logically it should return the max of the actual maximum. I've modified my example to take this into account. see attached (and updated version online). Colorbar will need some kwargs, at the very least. The "format" kwarg, for example, can be used to pass in a Formatter instance so that a label is 10^-3 instead of -3. Ah I'd not discovered Formatters yet. But this does give a good solution. If I instead do a pcolor of the log of my data, and then use a FormatStrFormatter as you surgested: pcolor(X,Y,log10(Z1),shading='flat') colorbar(format=FormatStrFormatter('$10^{%d}$')) I get exactly what I want :-) Its not the most intuitive way to do it, but it works and I can't see any major drawbacks. I am not sure why only the top is colored in your example--it might be a bug or it might be an indication that additional kwargs are needed. I am reasonably sure there is a simple solution, but I can't look at it any more right now--maybe I can get back to it this evening. I'm pretty sure the reason only the top was coloured is to do in the inconsistency I described above. Once I fixed that the colorbar is fine except that it is not on a log scale. But of course it can't know that it is suppost to be on a log scale! I tried to do: gca().axes[1].set_ylim((1e-5,1)) gca().axes[1].set_yscale('log') but that doesn't work. I get a load of errors : exceptions.ValueErrorTraceback (most recent call last) /usr/lib/python2.4/site-packages/matplotlib/backends/backend_gtk.py in expose_event(self, widget, event) 282 x, y, w, h = self.allocation 283 self._pixmap_prepare (w, h) --> 284 self._render_figure(self._pixmap, w, h) 285 self._need_redraw = False 286 /usr/lib/python2.4/site-packages/matplotlib/backends/backend_gtkagg.py in _render_figure(self, pixmap, width, height) 71 def _render_figure(self, pixmap, width, height): 72 if DEBUG: print 'FigureCanvasGTKAgg.render_figure' ---> 73 FigureCanvasAgg.draw(self) 74 if DEBUG: print 'FigureCanvasGTKAgg.render_figure pixmap', pixmap 75 #agg_to_gtk_drawable(pixmap, self.renderer._renderer, None) /usr/lib/python2.4/site-packages/matplotlib/backends/backend_agg.py in draw(self) 390 391 renderer = self.get_renderer() --> 392 self.figure.draw(renderer) 393 394 def get_renderer(self): /usr/lib/python2.4/site-packages/matplotlib/figure.py in draw(self, renderer) 542 543 # render the axes --> 544 for a in self.axes: a.draw(renderer) 545 546 # render the figure text /usr/lib/python2.4/site-packages/matplotlib/axes.py in draw(self, renderer, inframe) 1061 1062 for zorder, i, a in dsu: -> 1063 a.draw(renderer) 1064 1065 self.transData.thaw() # release the lazy objects /usr/lib/python2.4/site-packages/matplotlib/patches.py in draw(self, renderer) 163 164 verts = self.get_verts() --> 165 tverts = self._transform.seq_xy_tups(verts) 166 167 renderer.draw_polygon(gc, rgbFace, tverts) ValueError: Domain error on nonlinear Transformation::seq_xy_tups operator()(thisx, thisy) As for how to solve the problem properly. Matlab allows one to set to caxis scale to log. Maybe colorbar could detect that the norm instance was an instance of LogNorm and scale the yaxis logarithmicly. Or would it be better to put a scale={'log','linear'} kwarg into colorbar()? Thanks again for your help. cheers JIM --- pcolor_log.py Description: application/python - Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV___ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
Re: [matplotlib-devel] pcolor & colorbar with log normalised colour scale
Hi Eric, > I have modified your LogNorm, added it to colors.py, made some changes > to colorbar.py, and added a stripped-down version of your pcolor_log.py > to the examples directory. If you update your mpl from svn, then I > think you will find that pcolor_log now works the way you expected it to > originally, with the colorbar automatically supporting the log color scale. I just upgraded and it works great! Thanks very much. JIM --- - Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV ___ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel