Preview OSX bug (?) converting bezier curve in .eps file to .pdf - macos

I have a small .eps file which uses bezier curves with a thick linewidth to achieve a certain effect. This file displays as I expect it to in gv, but when I convert it to a .pdf (eg with ps2pdf or by opening the file with Preview on a Mac running OSX) it renders some of the curves incorrectly (or at least, not in the way I was expecting); in the middle of the curve, the normals to the curve seem to "flip over", producing a strange artifact.
Here is the .eps file in question, as code:
%!PS-Adobe-2.0 EPSF-2.0
%%BoundingBox: 0 0 750 200
gsave 50 50 scale 1 3 translate
/edge{4 dict begin
/y2 exch def
/x2 exch def
/y1 exch def
/x1 exch def
gsave
1 setgray
1 8 div setlinewidth
newpath
x1 y1 moveto x2 y2 lineto
stroke
0 setgray
1 20 div setlinewidth
newpath
x1 y1 moveto x2 y2 lineto
stroke
x1 y1 0.07 0 360 arc fill stroke
x2 y2 0.07 0 360 arc fill stroke
grestore
end}def
/cur_edge{7 dict begin
/T exch def
/angle2 exch def
/y2 exch def
/x2 exch def
/angle1 exch def
/y1 exch def
/x1 exch def
gsave
1 setgray
1 8 div setlinewidth
newpath
x1 y1 moveto
x1 angle1 cos T mul add y1 angle1 sin T mul add
x2 angle2 cos T mul add y2 angle2 sin T mul add
x2 y2 curveto
stroke
0 setgray
1 20 div setlinewidth
newpath
x1 y1 moveto
x1 angle1 cos T mul add y1 angle1 sin T mul add
x2 angle2 cos T mul add y2 angle2 sin T mul add
x2 y2 curveto
stroke
x1 y1 0.07 0 360 arc fill stroke
x2 y2 0.07 0 360 arc fill stroke
grestore
end}def
/fat_edge{7 dict begin
/T exch def
/angle2 exch def
/y2 exch def
/x2 exch def
/angle1 exch def
/y1 exch def
/x1 exch def
gsave
0 setgray
1 4 div setlinewidth
newpath
x1 y1 moveto
x1 angle1 cos T mul add y1 angle1 sin T mul add
x2 angle2 cos T mul add y2 angle2 sin T mul add
x2 y2 curveto
stroke
0.9 setgray
1 5 div setlinewidth
newpath
x1 y1 moveto
x1 angle1 cos T mul add y1 angle1 sin T mul add
x2 angle2 cos T mul add y2 angle2 sin T mul add
x2 y2 curveto
stroke
grestore
end}def
/fat_vertex{4 dict begin
/angle exch def
/y exch def
/x exch def
/T 0.14 def
gsave
0.9 setgray
1 5.5 div setlinewidth
newpath
x y moveto
x angle cos T mul add y angle sin T mul add lineto
stroke
grestore
end}def
/extra_fat_vertex{5 dict begin
/y exch def
/x exch def
/w 0.16 def
gsave
1 setgray
newpath
x w sub y w sub moveto
x w add y w sub lineto
x w add y w add lineto
x w sub y w add lineto
closepath
fill
stroke
0 setgray
/v 0.12 def
newpath
x v sub y v sub moveto
x v add y v sub lineto
x v add y v add lineto
x v sub y v add lineto
closepath
fill
0.9 setgray
/u 0.095 def
newpath
x u sub y u sub moveto
x u add y u sub lineto
x u add y u add lineto
x u sub y u add lineto
closepath
fill
grestore
end}def
/extra_fat_triangle{5 dict begin
/y exch def
/x exch def
/w 0.16 def
gsave
1 setgray
newpath
x w sub y w sub moveto
x w 1.1 mul add y lineto
x w sub y w add lineto
closepath
fill
stroke
0 setgray
/v 0.12 def
newpath
x v sub y v sub moveto
x v add y lineto
x v sub y v add lineto
closepath
fill
0.9 setgray
/u 0.095 def
newpath
x u sub y u sub moveto
x u 0.85 mul add y lineto
x u sub y u add lineto
closepath
fill
grestore
end}def
/extra_fat_triangle_left{5 dict begin
/y exch def
/x exch def
/w 0.16 def
gsave
1 setgray
newpath
x w add y w sub moveto
x w 1.1 mul sub y lineto
x w add y w add lineto
closepath
fill
stroke
0 setgray
/v 0.12 def
newpath
x v add y v sub moveto
x v sub y lineto
x v add y v add lineto
closepath
fill
0.9 setgray
/u 0.095 def
newpath
x u add y u sub moveto
x u 0.85 mul sub y lineto
x u add y u add lineto
closepath
fill
grestore
end}def
0 0 90 2 0 270 1 cur_edge
% 0 0 270 2 0 90 1 cur_edge
2 0 90 0 0 270 1 cur_edge
0 0 180 0.5 -2 180 1 cur_edge
0.5 -2 90 1.5 -1.3 180 0.5 cur_edge
1.5 -1.3 270 2.5 -2 270 0.7 cur_edge
2.5 -2 90 0.5 -2 270 1 cur_edge %
2.5 -2 0 3 -0.75 0 1 cur_edge
3 -0.75 270 1.5 -1.3 0 0.7 cur_edge
3 -0.75 180 1.5 -1.3 90 0.7 cur_edge
3 -0.75 90 2 0 0 0.5 cur_edge
5 0 translate
0 0 90 2 0 270 1 fat_edge
% 0 0 270 2 0 90 1 fat_edge
2 0 90 0 0 270 1 fat_edge
0 0 180 0.5 -2 180 1 fat_edge
0.5 -2 90 1.5 -1.3 180 0.5 fat_edge
1.5 -1.3 270 2.5 -2 270 0.7 fat_edge
2.5 -2 90 0.5 -2 270 1 fat_edge
2.5 -2 0 3 -0.75 0 1 fat_edge
3 -0.75 270 1.5 -1.3 0 0.7 fat_edge
3 -0.75 180 1.5 -1.3 90 0.7 fat_edge
3 -0.75 90 2 0 0 0.5 fat_edge
0 0 90 fat_vertex
0 0 180 fat_vertex
0 0 270 fat_vertex
2 0 0 fat_vertex
2 0 90 fat_vertex
2 0 270 fat_vertex
0.5 -2 180 fat_vertex
0.5 -2 90 fat_vertex
2.5 -2 90 fat_vertex
2.5 -2 270 fat_vertex
1.5 -1.3 0 fat_vertex
1.5 -1.3 90 fat_vertex
1.5 -1.3 180 fat_vertex
1.5 -1.3 270 fat_vertex
3 -0.75 0 fat_vertex
3 -0.75 90 fat_vertex
3 -0.75 180 fat_vertex
3 -0.75 270 fat_vertex
5 0 translate
0 0 90 2 0 270 1 fat_edge
% 0 0 270 2 0 90 1 fat_edge
2 0 90 0 0 270 1 fat_edge
0 0 180 0.5 -2 180 1 fat_edge
0.5 -2 90 1.5 -1.3 180 0.5 fat_edge
1.5 -1.3 270 2.5 -2 270 0.7 fat_edge
2.5 -2 90 0.5 -2 270 1 fat_edge
2.5 -2 0 3 -0.75 0 1 fat_edge
3 -0.75 270 1.5 -1.3 0 0.7 fat_edge
3 -0.75 180 1.5 -1.3 90 0.7 fat_edge
3 -0.75 90 2 0 0 0.5 fat_edge
0 0 90 fat_vertex
0 0 180 fat_vertex
0 0 270 fat_vertex
2 0 0 fat_vertex
2 0 90 fat_vertex
2 0 270 fat_vertex
0.5 -2 180 fat_vertex
0.5 -2 90 fat_vertex
2.5 -2 90 fat_vertex
2.5 -2 270 fat_vertex
1.5 -1.3 0 fat_vertex
1.5 -1.3 90 fat_vertex
1.5 -1.3 180 fat_vertex
1.5 -1.3 270 fat_vertex
3 -0.75 0 fat_vertex
3 -0.75 90 fat_vertex
3 -0.75 180 fat_vertex
3 -0.75 270 fat_vertex
0 0 extra_fat_triangle
2 0 extra_fat_triangle_left
0.5 -2 extra_fat_triangle
1.5 -1.3 extra_fat_vertex
2.5 -2 extra_fat_triangle_left
3 -0.75 extra_fat_vertex
grestore
%eof
What is curious is that the .pdf only displays incorrectly when it is resized to certain specific sizes (or: it displays correctly at certain sizes). I don't seem to be able to predict when it will work.
Here is how it displays (part of the image) correctly:
And here it is resized and displaying incorrectly:
(source: dannyc at math.uchicago.edu)
Note that these images are .jpgs obtained from the .pdf. If you save the code above as an .eps file and open it with Preview on a Mac, I assume it will exhibit the same pathology it did on my computer.
Any advice would be very welcome. I don't know enough (or: anything) about how bezier curves are displayed in .pdf to know what might be the problem here.

Here's a cut down case that displays the same rendering problem:
%!PS-Adobe-2.0 EPSF-2.0
%%BoundingBox: 0 0 400 200
gsave 50 50 scale 1 3 translate
0 setgray
0.05 setlinewidth
newpath
0 0 moveto
0 1 2 -1 2 0 curveto
stroke
grestore
%eof
Can't get much simpler than that: a Bezier path with just two points, all with integer values.
It looks like Apple's renderer has some numeric instability around the center of the curve. If you tweak one of the curve control points by a tiny amount, the bug doesn't happen:
0 1.00001 2 -1 2 0 curveto
So there's a workaround: In your original file, add a small fudge factor (a fraction of a degree) to one of the angles in each curve.
I changed each /angle1 exch def to 0.01 add /angle1 exch def, and it worked for me. Here's the EPS file and the resulting PDF file.
(Of course this shouldn't be necessary, but until you file a bug and Apple releases a fix, it may be the most expedient solution.)

Related

Netlogo: How can send agents from "area x" to "area y" using an O/D matrix?

I have a O/D matrix that might be useful to move people from one place to another. With the matrix extension, I attempt to build a simple model before I progress to the actual model, but ended up coding verbosely.
extensions [matrix]
globals [mat]
patches-own [location]
turtles-own [residency]
to setup
ca
reset-ticks
ask patches [
if pxcor >= 0 and pycor >= 0 [set pcolor black + 0 set location "ne" ]
if pxcor < 0 and pycor >= 0 [set pcolor black + 1 set location "nw" ]
if pxcor < 0 and pycor < 0 [set pcolor black + 2 set location "sw" ]
if pxcor >= 0 and pycor < 0 [set pcolor black + 3 set location "se" ]
]
ask n-of 40 patches [
sprout 1 [
set shape "person student"
set heading random 360
set residency [location] of patch-here
if residency = "nw" [set color yellow + 2]
]
]
set-matrix
end
to set-matrix
set mat matrix:from-row-list [[0.5 0.3 0.1 0.1][0.3 0.5 0.1 0.1][0.1 0.1 0.5 0.2][0.1 0.1 0.2 0.5]]
print matrix:pretty-print-text mat
;pretty text print looks something like this
; nw ne sw se
;nw 0.5 0.3 0.1 0.1
;ne 0.3 0.5 0.1 0.1
;sw 0.1 0.1 0.5 0.2
;se 0.1 0.1 0.2 0.5
end
to go
ifelse(ticks mod 240 <= 120)[move-out][come-home]
tick
end
to move-out
;; North West Residents
let n-of-nw count turtles with [residency = "nw"]
let %nw-nw matrix:get mat 0 0
let %nw-ne matrix:get mat 0 1
let %nw-sw matrix:get mat 0 2
let %nw-se matrix:get mat 0 3
ask n-of (%nw-nw * n-of-nw) turtles with [residency = "nw"]
[rt 45 lt 45 set heading random 360 fd 2
face min-one-of patches with [location = "nw"][distance myself]]
ask n-of (%nw-ne * n-of-nw) turtles with [residency = "nw"]
[ifelse location = "ne"[face min-one-of patches with [location != "nw" and location = "ne"][distance myself]
rt 45 lt 45 set heading random 360 fd 2]
[rt 45 lt 45 set heading random 360 fd 2]]
ask n-of (%nw-sw * n-of-nw) turtles with [residency = "nw"]
[ifelse location = "sw"[face min-one-of patches with [location != "nw" and location = "sw"][distance myself]
rt 45 lt 45 set heading random 360 fd 2]
[rt 45 lt 45 set heading random 360 fd 2]]
ask n-of (%nw-se * n-of-nw) turtles with [residency = "nw"]
[ifelse location = "se"[face min-one-of patches with [location != "nw" and location = "se"][distance myself]
rt 45 lt 45 set heading random 360 fd 2]
[rt 45 lt 45 set heading random 360 fd 2]]
ask turtles with [residency != "nw"][rt 45 lt 45 set heading random 360 fd 1]
end
to come-home
ask turtles with [residency = "nw"]
[ifelse location != "nw" [face min-one-of patches with [location = "nw"][distance myself] fd 1]
[move-to one-of neighbors with [location = "nw"]]]
ask turtles with [residency != "nw"][rt 45 lt 45 set heading random 360 fd 1]
end
Inside the Netlogo world, four regions splitted up at each corner as northwest(nw), northeast(ne), southwest(sw), southeast(se). I created agents in a random space and assigned their residency according to their location. Then, I wrote a origin-destination matrix as below,
nw ne sw se
nw 0.5 0.3 0.1 0.1
ne 0.3 0.5 0.1 0.1
sw 0.1 0.1 0.5 0.2
se 0.1 0.1 0.2 0.5
where, for example, 30% of nw residents should move to ne. I only coded one region, but can anyone give comments to improve my code more sound? Many thanks in advance.
Okay, if you have separated identifying where to go from moving toward the destination, this is a cleaner version. It is not tested. I have scrapped the matrix since that was making you triple-handle choosing where to go. NetLogo doesn't have a 'choose case' type structure so nested ifelse is the way to go.
I also added some randomness to the direction since I think that was what you were trying to do with all the heading code.
patches-own [location] turtles-own [residency destination]
to setup
clear-all
ask patches [
if pxcor >= 0 and pycor >= 0 [set pcolor black + 0 set location "ne" ]
if pxcor < 0 and pycor >= 0 [set pcolor black + 1 set location "nw" ]
if pxcor < 0 and pycor < 0 [set pcolor black + 2 set location "sw" ]
if pxcor >= 0 and pycor < 0 [set pcolor black + 3 set location "se" ]
]
ask n-of 40 patches
[ sprout 1
[ set shape "person student"
set heading random 360
set residency [location] of patch-here
if residency = "nw" [set color yellow + 2]
choose-destination
]
]
reset-ticks
end
to go
ifelse(ticks mod 240 <= 120)[move-out][come-home]
tick
end
to choose-destination
ask turtles with [residency = "nw"]
[ let myrandom random-float 1
ifelse myrandom <= 0.5 [ set destination "nw" ] [
ifelse myrandom <= 0.8 [ set destination "ne" ] [
ifelse myrandom <= 0.9 [ set destination "sw" ] [
set destination "se" ]]]
; similar code for each residency
end
to move-out
ask turtles with [destination != location]
[ face min-one-of patches with [location = destination][distance myself]
set heading heading + 10 - random 20
forward 1 ]
end
to come-home
; code more like revised move-out
end

Calculating a location on a circle given an angle of rotation

Okay algebra and trig are not my strong suit by any means so here is what I need to do.
I have a circle which is measured in degrees from +180 to -180 (360 total)
Given the center point of the circle stays the same, Cx , Cy.
The angle varies from -180 to +180
I need to locate a point that regardless the given angle is + 3 units away that is at the 90 degree position and the 270 degree position (from the given degrees)
So like...
Angle = 0
Point 1 -> x = 0, y -3
Point 2 -> x = 0, y + 3
And if the angle was say 90 (provided its measured Clockwise)
Point 1 -> x = -3, y = 0
Point 2 -> x = 3, y = 0
What I need is a forumla that will accept Angle, then tell me what my x/y should be 3 units away from the origin.
I have tried: EDIT Updated to double precision using Java.
`double x = Cx + 3 * Math.cos((d + 90) * Math.PI / 180);'
'double y = Cy + 3 * Math.sin((d + 90) * Math.PI / 180);`
this gives me mixed results, I mean sometimes it's where I think it should be and other times its quite wrong.
Assuming Cx = 0.500, Cy = 0.500
Sample Data: Result:
Deg = 0 x = 2 / y = 5
Deg = 90 x = -1 / y = 2
Deg = 125 x = -0.457 / y = 0.297
Deg = 159 x = 0.924 / y = -0.800
I realize I am only calculating one point at this point but do you have any suggestions on how to get the first point working? at say 90 degrees from whatever degree I start with?
x = Cx + r * Math.cos( (d+90) * Math.PI / 180 );
y = Cy + r * Math.sin( (d+90) * Math.PI / 180 );
Seems that this is the correct formula for what I was trying to accomplish. This will take any value for Cx/Cy's origin add the Radius r, then calculate the degrees + 90 and convert to radians.. Once all that magic takes place, you're left with an x/y coord that is 90 degrees of where you started.

Display label on gnuplot value in heatmap

Base on gnuplot example about "Heat map with non-zero pixel values written as labels" in here:
http://gnuplot.sourceforge.net/demo_cvs/heatmaps.html
I have data:
6 5 4 3 1 0
3 2 2 0 0 1
0 0 0 0 1 0
0 0 0 0 2 3
0 0 1 2 4 4
0 1 2 3 4 6
and my gnuplot:
set terminal pngcairo enhanced font "arial,10" fontscale 1.0 size 500, 350
set output 'heatmaps.png'
unset key
set view map
set xtics border in scale 0,0 mirror norotate offset character 0, 0, 0 autojustify
set ytics border in scale 0,0 mirror norotate offset character 0, 0, 0 autojustify
set ztics border in scale 0,0 nomirror norotate offset character 0, 0, 0 autojustify
set nocbtics
set rtics axis in scale 0,0 nomirror norotate offset character 0, 0, 0 autojustify
set xrange [ -0.500000 : 4.50000 ] noreverse nowriteback
set yrange [ -0.500000 : 4.50000 ] noreverse nowriteback
set cbrange [ 0.00000 : 5.00000 ] noreverse nowriteback
set palette rgbformulae -7, 2, -7
splot 'heatmap.txt' matrix using 1:2:3 with image, \
'heatmap.txt' matrix using 1:2:($3 == 0 ? " " : sprintf("$3") ) with labels
this script just printout "3" in every labels. Could you help me? thanks
and also label for Xtics and Ytics
Tipe1 Tipe2 Tipe3 Tipe4 Tipe5
Failure1 6 2 0 0 1
Failure2 0 0 0 1 0
Failure3 0 0 0 2 3
Failure4 0 1 2 4 4
Failure5 1 2 3 4 6
Thanks again
I think the problem is the wrong call to the sprintf function.
sprintf(format,values)
You should call sprintf with a decimal number in format (%d) and the label value you want to display (third column $3) :
sprintf("%d",$3)
I copied your data into a file (named data) and this example works well :
plot 'data' matrix using 1:2:3 with image, '' matrix using 1:2:($3==0 ? " " : sprintf("%d",$3)) with labels
Hope it helps!

Animating With Gloss in Haskell

Here's my code for a little pattern that looks something like this. (Not the most efficient code I know). Now, I want to make stars rotate using animate. but I'm not sure how to use display and animate together in one program. Any help would be appreciated. Thanks.
import Graphics.Gloss
main = display (InWindow "Gloss" (700,700) (0,0))
black (picture 100)
picture :: Float -> Picture
picture 0 = text "Value cannot be 0"
picture number = scale 6.5 6.5 (color rose $ drawpicture number)
orangered, orangered2, orangered3 :: Color
orangered = makeColor 1.0 0.251 0.0 0.7
orangered2 = makeColor 1.0 0.251 0.0 0.5
orangered3 = makeColor 1.0 0.251 0.0 0.3
intervalsmall = [0,11.25,22.5,33.75,45,56.25,67.5,78.75]
intervalbig = [0,22.5,45,67.5,90,112.5,135,157.5,180,202.5,225,247.5,270,292.5,315,337.5]
xlist = [2,4..50]
ylist = [0,2..48]
squares = pictures[rotate x (line [(-50,0),(0,50),(50,0),(0,-50),(-50,0)]) | x <- intervalsmall]
stars = pictures[rotate x ((pictures [line [(-8.5,0),(0,50),(8.5,0)],line[(0,50),(0,0)]])) | x <- intervalbig]
grid = pictures[line [(0,y),(x,50)] | x <- xlist, y <- ylist, x-y==2]
insidegrid = pictures[
translate 0 (-50) grid,
rotate 90 (translate 0 (-50) grid),
rotate 180 (translate 0 (-50) grid),
rotate 270 (translate 0 (-50) grid)]
drawpicture :: Float -> Picture
drawpicture number = pictures [
color red (pictures [circle 50,circle 8.5]),
line [(-50,-50),(-50,50),(50,50),(50,-50),(-50,-50)],
squares,
scale 0.7 0.7 squares,
scale 0.49 0.49 squares,
scale 0.347 0.347 squares,
scale 0.242 0.242 squares,
color orange stars,
color orange (scale 0.178 0.178 stars),
rotate 11.25 (scale 0.178 0.178 stars),
translate (-50) 0 grid,
rotate 90 (Translate (-50) 0 grid),
rotate 180 (Translate (-50) 0 grid),
rotate 270 (Translate (-50) 0 grid),
color orangered insidegrid,
color orangered2 (rotate 45 insidegrid),
color orangered3 (rotate 22.5 insidegrid),
color orangered3 (rotate 67.5 insidegrid)
]
It's easier if you have separate draw functions for each visual element, but the basic answer is: to animate it just use the animate function and rotate the image components you desire to "move":
import Graphics.Gloss
main = animate (InWindow "Gloss" (700,700) (0,0))
black picture
picture :: Float -> Picture
picture 0 = text "Value cannot be 0"
picture number = scale 6.5 6.5 (color rose $ drawpicture number)
orangered, orangered2, orangered3 :: Color
orangered = makeColor 1.0 0.251 0.0 0.7
orangered2 = makeColor 1.0 0.251 0.0 0.5
orangered3 = makeColor 1.0 0.251 0.0 0.3
intervalsmall = [0,11.25,22.5,33.75,45,56.25,67.5,78.75]
intervalbig = [0,22.5,45,67.5,90,112.5,135,157.5,180,202.5,225,247.5,270,292.5,315,337.5]
xlist = [2,4..50]
ylist = [0,2..48]
squares = pictures[rotate x (line [(-50,0),(0,50),(50,0),(0,-50),(-50,0)]) | x <- intervalsmall]
stars = pictures[rotate x ((pictures [line [(-8.5,0),(0,50),(8.5,0)],line[(0,50),(0,0)]])) | x <- intervalbig]
grid = pictures[line [(0,y),(x,50)] | x <- xlist, y <- ylist, x-y==2]
insidegrid = pictures[
translate 0 (-50) grid,
rotate 90 (translate 0 (-50) grid),
rotate 180 (translate 0 (-50) grid),
rotate 270 (translate 0 (-50) grid)]
rotVal :: Float -> Float
rotVal x = x - (x / (2*pi))
drawpicture :: Float -> Picture
drawpicture number = pictures [
rot $ color red (pictures [circle 50,circle 8.5]),
line [(-50,-50),(-50,50),(50,50),(50,-50),(-50,-50)],
rot $ squares,
rot $ scale 0.7 0.7 squares,
rot $ scale 0.49 0.49 squares,
rot $ scale 0.347 0.347 squares,
rot $ scale 0.242 0.242 squares,
rot $ color orange stars,
rot (color orange (scale 0.178 0.178 stars)),
rot (rotate 11.25 (scale 0.178 0.178 stars)),
translate (-50) 0 grid,
rotate 90 (Translate (-50) 0 grid),
rotate 180 (Translate (-50) 0 grid),
rotate 270 (Translate (-50) 0 grid),
rot $ color orangered insidegrid,
rot $ color orangered2 (rotate 45 insidegrid),
rot $ color orangered3 (rotate 22.5 insidegrid),
rot $ color orangered3 (rotate 67.5 insidegrid)
]
where rot = rotate (rotVal number)
It is too much to write out all for you but you just have to add another argument to your picture function that is a Float and represents time. So display would be replaced by animate. So.
main = animate (InWindow "Gloss" (700,700) (0,0))
black (picture 100)
picture :: Float -> Float -> Picture
picture number time = -- whatever you have to do
You'll have to change your helping drawing functions to take this time param. Let's say you want to rotate the whole think once ever 5 seconds you can just multiply this time coming in and get an angle angle = time*(pi*2/5) then you can use this angle for trig functions to calculate new x and y positions from the center.

How to speed up matplotlib scatter ploting?

I need to draw a batch of scatter charts in matplotlib, and found the speed of matplotlib is slow, then I lineprofile the function, and found the hotspot is fig, ax = plt.subplots(), It costs 56.1% of time to creat a blank figure and axes !!
How to speed it up ? I mean, how can I reuse fig and ax to avoid creating them each time ?
Attach the profile report here (I cut some of the line to make it simple)
Total time: 0.733771 s
Line # Hits Time Per Hit % Time Line Contents
==============================================================
517 #profile
518 def df_scatter(df):
519 ''' draw the scatter plot for Pandas dataframe 'df'
533 '''
536
537 1 75 75.0 0.0 biggest_area = 1000
538 1 117 117.0 0.0 mycm = matplotlib.cm.get_cmap('jet') # 'spectral'
539
541 1 78 78.0 0.0 col_qty = len(df.columns)
543
544 1 1859 1859.0 0.1 x = list(df.ix[:,0].values)
545 1 1258 1258.0 0.0 y = list(df.ix[:,1].values)
551
552 1 1472345 1472345.0 56.1 fig, ax = plt.subplots()
556
557 1 7007 7007.0 0.3 plt.subplots_adjust(left=0.07, right=0.92, bottom=0.1, top=0.95)
558 1 179 179.0 0.0 x_margin, y_margin = (max(x)-min(x))/20, (max(y)-min(y))/20
563
564 1 71 71.0 0.0 if col_qty > 2:
565 1 1602 1602.0 0.1 r = list(df.ix[:,2].values)
566 1 309 309.0 0.0 size_r = np.array(biggest_area)*r/max(r)
585
586 1 34712 34712.0 1.3 sc = plt.scatter(x, y, marker='o', s=size_r, cmap=mycm, alpha=0.65)
587
588 # adding colorbar
589 1 542417 542417.0 20.7 cbaxes = fig.add_axes([0.94, 0.25, 0.02, 0.70])
590 1 165719 165719.0 6.3 cbar = plt.colorbar(sc, cax=cbaxes)
591 1 122 122.0 0.0 cbar.solids.set_edgecolor('face')
595
602 1 1061 1061.0 0.0 plt.figtext(0.94,0.10,"%0.1f"%(max(r)), fontproperties=TEXT_FONT_MEDIUM)
639 1 66 66.0 0.0 return fig
I think that the best way to do it is calling
fig = plt.figure()
ax=fig.add_subplot(111)
from outside of df_scatter. Then, pass it to df_scatter as arguments:
df_scatter(df,fig,ax):
or simply do inside df_scatter:
def df_scatter(df):
fig = plt.gcf()
ax = plt.gca()
after the creation of fig & axis was done.

Resources