I'm doing some plotting using cartopy and matplotlib, and I was recently using the PlateCarree transformation, but I changed to Mercator because Louisiana was a bit too squished for my liking. Prior to the switch, I had a logo displayed in the bottom left corner, using these two lines of code logo = matplotlib.image.imread('/Users/ian/Desktop/M.png')
plt.imshow(logo, extent =(lon-offset -1 + .25, lon - offset + .75, lat - offset + .25, lat - offset + 1 + .75), zorder=35)
Where the extent of the axis was set using these points
ax.set_extent([lon-offset-1, lon+offset+1, lat-offset, lat+offset])
this is what the plot looked like using PlateCarree:
After switching to Mercator, I've gotten everything to work well except for the logo. I've added the transformation keyword argument to the image plotting line, so now it reads:
plt.imshow(logo, extent =(lon-offset -1 +.25, lon - offset + .75, lat - offset + .25, lat - offset + 1 + .75), zorder=35, transform=ccrs.PlateCarree())
but now the the logo has lost its crispness and become skewed with the transformation, and most mysteriously, it has switched corners to the upper left corner of the plot. It now looks like this:
Does anyone know how I can change the projection of my plot without skewing this image? What I really need to do is make sure that the corner of the image is in the corner of the plot in the transformed coordinate stystem, but leave the rest of the image's placement independent of the coordinate system. I was thinking about possibly putting the image all alone in its own seperate subplot, and than trying to place that subplot directly on top of the main one. Seems like a pretty bad solution though. Thanks!
You might get better results if you plot the image logo in axes coordinates rather than data coordinates. You can use the ax.transAxes transform for this, and specify the extent in axes coordinates ([0, 0] in bottom left, [1, 1] in top right).
Related
I'm trying to set as initial camera of a 3D volume plot where the upper left corner is the origin (x, y, z = 0). I've read the documentation about the camera controls but cannot figure out how can I accomplish this.
The initial view I want it's something like this:
I tried it and this one work on me
If you want the front upper left corner as (0,0,0)
camera = dict(
eye=dict(x=0, y=-0.5, z=-2.5)
)
fig.update_layout(scene_camera=camera, title=name)
fig.show()
what I understand from this eye is basically the position of the eye(or you) look at eyepoint(0,0,0) which is I believe the center of the 3D graph (not the coordinate)
And if you need to change the axes direction to the opposite, you can try to put it on negative on the eye position, and if it is zero you can put negative small number (in this example I used -0.5, but you can use -0.01 too)
I am faced now to a new problem using GetDist library available on home page of GetDist. Examples are given in this getdist plot gallery.
This is a tool to plot joint distribution for a set of covariance matrices.
Everything works fine except one detail that disturbs me : If I zoom very deeply, I notice a slight shift between the contours filled and the lines contours. I illustrate this by the following zoomed figure (smallest contours refers to 1 sigma uncertainty and the largest 2 sigma) representing the ellipse of 2 covariance matrices.
In this figure, I zoom very deeply on a subplot. Classically, if I unzoom the figure, I get this kind of image :
The relevant section that generates the triplot is :
# Call triplot
g.triangle_plot([matrix1, matrix2],
names,
filled = True,
legend_labels = [],
contour_colors = ['darkblue','red'],
line_args = [{'lw':2, 'color':'darkblue'},
{'lw':2, 'color':'red'}],
)
I don't understand why filled area (red and darkblue) exceeds slightly the lines of the corresponding contours.
Maybe it is related to my conputation of limits of ellipse along x-coordinates and y-coordinates in order to fully fill the subplot and the rounding errors. I tried to modify these paramters without success.
I haven't looked in the code, but what I can see from the image is, that the border is half inset and half outset. I assume that the border has a transparency like the shape's fill color and thus it has the effect of a shifted dark border while this is just the part where the transparent border and the transparent background overlay.
The following example shows two circles, with a backgroundcolor rgba(0,0,0,0.5). The border on circle A has no opacity: rgb(0,0,0,1) while on circle B the border color matches the fill color (so 50% opacity: rgba(0,0,0,0.5).
I am using python 3.6 to open a shapefile of the Amazon River on to basemap. However I am confused with how coordinates work in python. I looked up coordinates of the the Amazon River and found it to be lon,lat=-55.126648,-2.163106. But to open my map I need the lat/lon values of corners, which I am not sure how to get.
Here is my code so far:
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
map= Basemap(projection='tmerc',
lon_0=180,
lat_0=0,
resolution='l')
map.drawmapboundary(fill_color='aqua')
map.fillcontinents(color='#ddaa66',lake_color='aqua')
map.drawcoastlines()
map.readshapefile('filename','Amazon')
plt.show()
Here is the error message I get when I try to run it:
ValueError: must either specify lat/lon values of corners
(llcrnrlon,llcrnrlat,ucrnrlon,urcrnrlat) in degrees or width and height in meters
When creating your map (map = Basemap(...)) , you need to specify those values. They are lower left corner longitude, lower left corner latitude, upper right corner longitude, and upper right corner latitude. These define the extents of the map. You could just plot the whole earth, then look at the region you want and pick the points off of it for your new corners.
The best method for this type of point plotting is to create your own corners by 'zooming out' from the point. this means you'll need to specify llcrnrlat (lower left corner latitude), etc. as such:
my_coords = [38.9719980,-76.9219820]
# How much to zoom from coordinates (in degrees)
zoom_scale = 1
# Setup the bounding box for the zoom and bounds of the map
bbox = [my_coords[0]-zoom_scale,my_coords[0]+zoom_scale,\
my_coords[1]-zoom_scale,my_coords[1]+zoom_scale]
plt.figure(figsize=(12,6))
# Define the projection, scale, the corners of the map, and the resolution.
m = Basemap(projection='merc',llcrnrlat=bbox[0],urcrnrlat=bbox[1],\
llcrnrlon=bbox[2],urcrnrlon=bbox[3],lat_ts=10,resolution='i')
If you want to see a full tutorial on plotting lat/lon points from a .csv file, check out my tutorial where I go through the whole process and include the full code:
Geographic Mapping from a CSV File Using Python and Basemap
You end up with a result that looks like the following:
How can I draw shapes in matplotlib using point/inch dimensions?
I've gone through the patch/transform documentation so I understand how to work in pixel, data, axes or figure coordinates but I cannot figure out how to dimension a rectangle in points/inches.
Ideally I would like to position a rectangle in data coordinates but set its size in points, much like how line markers work.
Here is an example of the plot I am trying to create. I currently position the black and red boxes in (data, axes) coordinates. This works when the graph is a known size, but fails when it gets rescaled as the boxes become smaller even through the text size is constant.
Ended up figuring it out with help from this question: How do I offset lines in matplotlib by X points
There is no built in way to specify patch dimensions in points, so you have to manually calculate a ratio of axes or data coordinates to inches/points. This ratio will of course vary depending on figure/axes size.
This is accomplished by running a (1, 1) point through the axes transform and seeing where it ends up in pixel coordinates. Pixels can then be converted to inches or points via the figure dpi.
t = axes.transAxes.transform([(0,0), (1,1)])
t = axes.get_figure().get_dpi() / (t[1,1] - t[0,1]) / 72
# Height = 18 points
height = 18 * t
I am trying to draw a tilted ellipse in image draw. However, I am not sure how to define it, since while the scheme below would move the points, I think this would just squish the ellipse, not rotate it (also I think there is something slightly wrong with the transformation in any case). I am feeding the output of this function into the ellipse command and adding it to an existing picture, so any methods that would rotate the entire image are no good. OD is just a square offset to the coordinate center I am using.
def ellipsebound(major, minor, tilt=0, offset=0, angle=0):
#creates a bound for an ellispe, defined with tilt meaning to rotate the orthogonal axis and angle corresponds to rotating the ellipse position
angle = radians(angle)
tilt = radians(tilt)
box=(
1 + int(ceil((OD+offset*cos(angle)+(major*cos(tilt)+minor*sin(tilt)))/conv)),
1 + int(ceil((OD+offset*sin(angle)+(major*sin(tilt)-minor*cos(tilt)))/conv)),
int(ceil((2*OD-(OD-offset*cos(angle)-(major*cos(tilt)+minor*sin(tilt)))/conv))),
int(ceil((2*OD-(OD-offset*sin(angle)-(major*sin(tilt)-minor*cos(tilt)))/conv)))
) #create bounding box
return box
Does anyone know how to accomplish this?
It looks like the 'box' that is being used to draw the ellipse has no rotation associated with it. It is simply defined by the (left, top, right, bottom) extents.
One possible workaround (depending on what you need to do) is to draw the ellipse (sized correctly, but without the rotation) onto an intermediary image, use the image.rotate() method, and then paste it into your target image.
I hope that helps.