I am plotting some geometry using bokeh and came across this. I am plotting a rectangle with equal sides (i.e. a square), and in that square, plotting a circle with diameter = width of the square. The circle should tangent to the square at edges, but it is not.
here is the code:
from bokeh.plotting import output_notebook, figure, show
output_notebook()
p = figure(width=500, height=500)
p.rect(0, 0, 300, 300, line_color='black')
p.circle(x=0, y=0, radius=150, line_color='black',
fill_color='grey', radius_units='data')
p.axis.minor_tick_out = 0
show(p)
Which results in this:
Is there anything I am doing wrong or could change to make the circle fit exactly in the square?
Thanks in advance,
Randall
Here's another case - just drawing a circle:
p = figure(width=500, height=500, x_range=(-150, 150), y_range=(-150, 150))
p.circle(x=0, y=0, radius=150, line_color='black',
fill_color='grey', radius_units='data')
show(p)
radius of the circle is 150 in the x direction, but not the y-direction.
I would like to report that as of Bokeh 0.12.7, this issue can now be fixed in a simpler manner.
As described in other posts, the main issue is not that the circle is not a circle, but that the square is not a square. This is due to the fact that actual area on which Bokeh draws the figure (the canvas) is usually not a square by default or even when the width and height are set to the same value. Bokeh by default will attempt to draw a figure by using up all the space on the canvas. This creates a mismatch between the data distance and the pixel distance of the plot.
As of 0.12.7, figures can now accept a match_aspect property which when set to True will will match the aspect of the data space to the pixel space of the plot.
In your example, simply adding the match_aspect = True in your figure
p = figure(width=500, height=500, match_aspect=True,
title="Circle touches all 4 sides of square")
p.rect(0, 0, 300, 300, line_color='black')
p.circle(x=0, y=0, radius=150, line_color='black',
fill_color='grey', radius_units='data')
will now produce
UPDATE: Please note new answer by #DuCorey below. As of Bokeh 0.12.7, aspect control is now available, for situations like this.
The issue is actually that the square is not square, and that is because the pixel aspect ratio and the "data" aspect ratio do not match. i.e., the distance per pixel is different in the x direction than it is in the y direction.
There are a few options:
You can use various properties to control the dimensions of the central plot area (e.g. plot border width and axis tick label orientation) You can also control you data ranges explicitly. In other words, you can make the aspect ratios match, and then the circle and rect will match
You can use absolute pixel units (e.g. size for a circle, and use a large square marker instead of rect) instead of "data" units.
Alternatively, if you want a circle that "deforms" when the aspects do not match, then your best bet is to use an ellipse with an identical width and height, which will work because in this case bokeh has two dimensions to use to measure (instead of the single radius) and can match each to the scale along each dimension independently.
(This is actually the fundamental difference that explains the behaviour: rect has two dimensions to measure independently. circle does not, it only has one, and has to arbitrarily use the x or y dimension to measure distance per pixel)
ok, based on the suggestions, I tried a few things.
Changed the orientation of the y-axis tick labels - still
had issue.
Changed various stand-offs, even moving in the tick
labels inside the plot (with a negative offset). Did not work either.
Changed the x_range and r_range in figure() to be equal tuples. Did not work either
Changes the plot_height (decreased it), and I could eventually, through rial and error, get the circle to fit in the square with a plot_height that was < plot width.
Lots of great practice controlling attributes of the plot. Time will invested.
However, the last change I tried worked the best. It was one of the first suggestions - change the plot border.
Weirdly, setting p.min_border=40, which on 0.12.6 is the default value, and voila, it appears the chart aspect ratio for a chart where plot_width=plot_height is truly 1 on the screen as well.
p = figure(plot_width=500, plot_height=500)
p.rect(0, 0, 300, 300, line_color=None)
p.circle(x=0, y=0, radius=150, line_color=None,
fill_color='lightgrey', radius_units='data')
p.min_border=40
show(p)
Before and after images showing the effect of adding p.min_border=40. Any value over ~33 appeared to be enough force the plot area to have the same screen x and y dimension - so the square was really a square (and the circle fit inside).
The reason for this is that you're creating a circular marker (or circle glyphs) and placing it at position (0, 0), while it seems like you want to create a circle centered at 0.
I think the rect here "happens" to work because it can scale correctly in both dimensions and remain a "rectangle".
Keyword Args:
radius (UnitsSpecPropertyDescriptor) : The radius values for circle markers (in "data space" units, by default). (default None)
radius_dimension (BasicPropertyDescriptor) : What dimension to measure circle radii along. (default 'x')
radius_units (Enum('screen', 'data')) : (default 'data')
I guess my point is here you've taken a shortcut by trying to use a "glyph" as your plot and specifying the units to be the data units.
If you want to create an actual circle you could do the following:
th = np.linspace(0, 2*np.pi)
r = 150
p = figure(width=500, height=500)
p.rect(0, 0, 300, 300, line_color='black')
p.line(r * np.cos(th), r * np.sin(th), line_color='black')
# p.circle(x=0, y=0, radius=150, line_color='black',
# fill_color='grey', radius_units='data')
p.axis.minor_tick_out = 0
show(p)
Notice the above is harder to fill (I didn't bother) because I'm guessing you need to define some closed polygon function while I only defined a line that happens to be a closed polygon, in this case a circle.
Not sure, but the bleu rectangle is not your rectangle.
Replace:
p.rect(0, 0, 300, 300, line_color='black')
By:
p.rect(-150, -150, 150, 150, line_color='black')
Related
I need to create small multiples (like the one shown in the picture) using ggplot2 where each circle occupies 70% of the total size of it's own small multiple and the remaining 30% is empty space.
I know the center and the radius of the circle.
Question: Is it possible to do this, and if so, how?
Area of a circle = C = π * r²
Area of your square = S = width * length = side²
So just calculate C, so you can calculate how big S must be to fullfill your criteria. When you know S you know the side, which translates to how you have to set the axis limits for x and y.
I have the following 'data.dat' file:
# x y z radius
-1.64905083 -1.14142799 -2657.88232 177.358566
-449.735321 416.586914 -2865.25366 10.0000000
178.955292 -256.291138 -2856.96069 89.9588394
-336.942322 184.932343 -2839.22876 90.6131058
-443.635315 -80.0183029 -2863.29077 70.7404404
236.385406 349.893188 -2901.33984 10.0000000
485.313416 -366.513947 -2868.35083 10.0000000
with the positions of the spheres and their radii.
My file.p reads:
set terminal png size 500,500
set output 'file.png'
set multiplot
set xrange [-1000:1000]
set yrange [-1000:1000]
set zrange [-3000:-2500]
splot "data.dat" using 1:2:3:4 ps variable pt 7
splot -(3000**2-x**2-y**2)**(0.5)
but the dots that gnuplot provides me are much bigger.
I understand that it is because ps yields points that are radius times bigger than the normal size.
Meaning that ps does not allow to set the radius of the dots, but rather how many times bigger it is than the normal points.
How can I set the radius of the points please ?
Use "with circles" rather than "with points pt 7".
From the manual:
gnuplot> help with circles
The `circles` style plots a circle with an explicit radius at each data point.
The radius is always interpreted in the units of the plot's horizontal axis
(x or x2). The scale on y and the aspect ratio of the plot are both ignored.
If the radius is not given in a separate column for each point it is taken from
`set style circle`. In this case the radius may use graph or screen coordinates.
Many combinations of per-point and previously set properties are possible.
For 2D plots these include
using x:y
using x:y:radius
using x:y:color
using x:y:radius:color
using x:y:radius:arc_begin:arc_end
using x:y:radius:arc_begin:arc_end:color
By default a full circle will be drawn. It is possible to instead plot arc
segments by specifying a start and end angle (in degrees) in columns 4 and 5.
A per-circle color may be provided in the last column of the using specifier.
In this case the plot command must include a corresponding variable color
term such as `lc variable` or `fillcolor rgb variable`.
I have some triangles in 3D space, which originate from 0,0,0 and extend towards two points p1= -x0, 0, z0 and p2= +x0, 0, z0. This is in Unity, such that +z is the forward axis (i.e. they lie flat). Each triangle is its own mesh, pivot is at 0,0,0.
Now, I would like to rotate these (using Quaternion.LookRotation) such that their ends form a continuous polygon, in case of three triangles a triangle, in case of four triangles a square, etc.
My approach is to calculate the incircle radius of the resulting polygon based on the length of each triangle (which is 2*x0). If I now calculate n points on this circle (where n is the number of triangles I have), I get x/y coordinates which I can directly use to set the "up" axis of each triangle correctly, i.e. Quaternion.LookRotation(Vector3.forward, new Vector3(x,y,0)). This orients the triangle correctly around the z axis, i.e. the center is still on 0,0,1.
However, and this has me stumped, I still need to change the forward axis of the triangles such that they tilt to form the final polygon. I tried using new Vector3(x,y,z0) which gives an almost correct result, but leads to an overlap at the edges. I suspect this is somehow due to the fact that rotation of the triangles effectively changes z0, but I am not sure how to proceed.
My question is, how to calculate the new forward axis such that the triangles align properly?
The problem is setting the forward axis to (x,y,z0), which is wrong since the length of the vector (x,y,z0) does not equal the original length (which is just z0). The z value thus needs to be adjusted such that new Vector(x,y,z1).magnitude == z0. This can be done by calculating
Mathf.Sqrt(Mathf.Pow(z0, 2) - Mathf.Pow(x, 2) - Mathf.Pow(y, 2))
Problem solved.
I've been trying to figure out how to make the little circles that represent mutation steps on a haplotype network bigger. For whatever reason, all the normal ways I'd think don't seem to be working. It seems like no matter what I do, the symbols remain tiny. What am I missing?
Here's a base bit of sample code:
data(woodmouse)
h <- haplotype(woodmouse)
net <- haploNet(h)
plot(net, size=attr(net,"freq")*3,bg=pal,labels=F, fast=F, legend=F,
show.mutation=T,threshold=0)
# using scale.ratio = 1, the mutations are visisble
plot(net, size=attr(net,"freq")*3,bg=pal,labels=F, fast=F, legend=F,
show.mutation=T,threshold=0,scale.ratio=3)
# but using scale.ratio=3, they get tiny / disappear
You can see the mutations here, but if I set scale.ratio to something bigger (a requirement with my own data), they essentially disappear.
I've tried passing a larger cex to plot (doesn't work) as well as setting cex globally with par (makes the whole plot smaller for some reason).
It seems like the circles are scaled with the lines, but I don't know how to control that. Is it even possible? Am I missing something really obvious?
cex controls the font size and will not help with graphics size. From the help page for the haploNet and plot.haploNet functions:
?haploNet
size: a numeric vector giving the diameter of the circles representing the haplotypes: this is in the same unit than the links and eventually recycled.
scale.ratio: the ratio of the scale of the links representing the number of steps on the scale of the circles representing the haplotypes. It may be needed to give a value greater than one to avoid overlapping circles.
This means that size of the links (circles representing mutations between haplotypes) is relative to the size of the haplotypes. To relatively enlarge the link size, you need to find a suitable combination of the two arguments.
set.seed(123)
net <- haploNet(haplotype(woodmouse[sample(15, size = 50, replace = TRUE), ]))
par(mfrow=c(1,2))
plot(net, size=attr(net,"freq"), labels=F, fast=F, legend=F,
show.mutation=T, threshold=0, scale.ratio=1)
plot(net, size=attr(net,"freq")*.2, labels=F, fast=F, legend=F,
show.mutation=T, threshold=0, scale.ratio=.2)
Enlarging circle size with haploNet runs into a risk that circles will overlap and the visible number of mutations will be incorrect. Use discretion with visualization and in case of problems, consider haplotype network calculation in TCS software where unsampled mutations are displayed with vertical bars or Network from Fluxus with proportional link lengths.
I want to draw circles with semitransparent colour on top of a map (showing prevalence), the colour at overlap areas is too heavy to show the background image, the code am using is too long to put here, but for circles am using:
symbols(data[,c(9, 10)],
circles = 5/(pi * a.rad * cos(atan(b.rad / a.rad * tan((data[,10])*pi/180)))/180000),
fg = NULL,
bg = rgb(0, 1, 0, 0.18),
inches = F,
add = T)
I want to joint circles to plot them with the same "transparent" colour, is there some way to do this using R? Or is there any other alternative using R*?
*Please note: The maps am using are develped using R, and I can't use other program to develop them.
There's no simple way, since you're plotting a series of circles. If you don't demand the fill color be consistent, you could set the alpha value to a very small level. To get a consistent fill color, you'll have to calculate the intersection areas of the circles and plot those areas as well as the nonintersection areas (instead of plotting circles). If you have multiple overlapping circles, you can see that will become a computational nightmare.
My personal recommendation is to plot with the smallest visible alpha value so that the worst-case overlap area doesn't obscure the map. This has the side-effect of clearly indicating the density of overlap areas.