How to set up scaled axes with hvplot? - python-3.x

Question:
How to set up scaled axes with hvplot? [https://hvplot.pyviz.org/]
Code example:
I have the following code giving me the figure hereafter but the lat and long axes are not equal. How to have a 1:1 ratio between the two axes?
import os, sys
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import hvplot.pandas
pos = pd.read_csv(os.path.join('my_gps_positions.csv'))
pos.hvplot.scatter(*'lat lng'.split())
Here's the GPS file content:
And the resulting graph with unequal axes in my notebook:

You could adjust the width and the height parameter of the plot:
df.hvplot.scatter(x='lat', y='lon', width=500, height=500)
Or do you mean the range of the axes? They can be set by parameter xlim and ylim, for example:
df.hvplot.scatter(x='lat', y='lon', xlim=(6, 8), ylim=(45, 47))
Since you're plotting latitudes and longitudes you should definitely take a look at geoviews: http://geoviews.org/

longitude and latitude units should not be the same distance, except right on the equator. So normally you would plot these with hvplot as:
df.hvplot.points(x='lon', y='lat', geo=True, tiles='OSM')
but if you really want to force them to be the same, you can use aspect:
df.hvplot.scatter(x='lon', y='lat', aspect='equal')

Related

Fixing incorrect contour lines occurring around 0 longitude

I'm fairly new to plotting contour lines. When plotting ice data that crosses over longitude zero in the Arctic, the contour lines create horizontal lines that span the x axis. Ideally I'd merge the lines so they created one solid contour, but failing that just removing the horizontal lines would be enough.
https://imgur.com/VU1IlNA (I'm new and not allowed to post pictures yet, but this shows the problem clearly)
from netCDF4 import Dataset, MFDataset, num2date
import numpy as np
import cartopy.crs as ccrs
from cartopy.util import add_cyclic_point
import pandas as pd
from netCDF4 import Dataset as NetCDFFile
import matplotlib.pyplot as plt
nc = NetCDFFile('LongitudeLatitudeGrid-n3125-Svalbard- from20190129.hdf')
lats = nc.variables['Latitudes'][:]
lons = nc.variables['Longitudes'][:]
nc17 = NetCDFFile('asi-AMSR2-n3125-20190517-v5.4.hdf')
ice17 = nc17.variables['ASI Ice Concentration'][:]
fig = plt.figure(figsize=(30,20))
ax6 = plt.subplot(2,3,6,projection=ccrs.Mercator(min_latitude=77,max_latitude=81))
mm = ax6.contour(lons,lats,ice17,vmin=0,vmax=100,
transform=ccrs.PlateCarree(),cmap='BuPu',zorder=1)
plt.title('May 17th stations: δ15N vaules',size='x-large')
ax6.set_extent([-10,10,77,81])
ax6.coastlines()
Expected results are a clean contour line, with no gap, but instead a gap appears as shown.
I managed to fix this, the issue was that my longitudinal values jumped from 0 to 360 at longitude zero. By subtracting 360 from all longitude values > 180 the problem was solved, and the plot looks appropriate now.

Equivalent of pcolormesh for irregular points

I am using pcolormesh on a 2-D NumPY array of points M, so
pcolormesh(X,Y,M)
plots a grid of colors where the X-axis range labels correspond to X[i], Y-axis range labels correspond to Y[j], and the color plotted at point (i,j) corresponds to the level of M[i,j].
I would also like to plot the same thing but where I have a 1-D array M[i], and the color plotted at point (X[i], Y[i]) corresponds to the level of M[i].
I don't see any out of the box solution for this in matplotlib. Is there one? This is the closest I could come up with, taking a cue from an answer to this question:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
def intensityplot(x,y,z):
z=z/z.max()
colors = cm.rainbow(z)
for X,Y,Z in zip(x,y,colors):
plt.scatter([X],[Y], color=Z)

How to plot an image from a FITS file with real coordinates?

The astropy documentation has an example on how to plot an image from a FITS file. The axis on the resulting plot correspond to the number of pixels, or data points. I would like the axis to indicate galactic coordinates instead.
Note that the header of my FITS file indicates all of the information regarding the position of the image on the sky. How do I get the plot to show real coordinates rather that number of pixels ?
The WCS framework provided by astropy can be used for plotting with world coordinates.
from astropy.wcs import WCS
from astropy.io import fits
from astropy.utils.data import get_pkg_data_filename
import matplotlib.pyplot as plt
image_file = get_pkg_data_filename('tutorials/FITS-images/HorseHead.fits')
hdu = fits.open(image_file)[0]
wcs = WCS(hdu.header)
plt.subplot(projection=wcs)
plt.imshow(hdu.data, origin='lower')
plt.grid(color='white', ls='solid')
plt.show()

Adding pie chart at given coordinates to cartopy projection

I am a beginner in data visualization, and even more with cartopy, I know for most of people my question would be obvious. I am trying to get familiar with cartopy and I successfully plot text and point. But I couldn't achieve it for pie chart.
I just want to plot pie chart on a particular projection. But I am really confuse, despite the documentation of cartopy. I have first try this:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
ax = plt.axes(projection=ccrs.Robinson())
ax.coastlines(resolution='110m') # 110, 50, 10
ax.stock_img()
lat, long = 30, 30 # the latitude longitude
ax.pie(long, lat, [0.25, 0.75], transform=ccrs.PlateCarree())
That do not work, So I have checked and I found this Cartopy coastlines hidden by inset_axes use of Axes.pie but I do not understand what happend under the hood and furthermore it seems limited to PlateCarre(). I have try to modified it but I do not managed to get it work properly.
So my very simple question is How can I add several pie chart to a specific projection given latitude and longitude? If you can develop your answer you will be really welcome.
You can use an inset_axes to place a new axes into the plot, which will allow to host the pie chart. The position of the inset_axes is determined by the bbox_to_anchor argument. To have this argument use the coordinates of the projection of the cartopy axes (ax), you need to set the bbox_transform=ax.transData.
If you have your coordinates in a different coordinate system, you need to convert them to the one in use using the projection's .transform_point method first.
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
ax = plt.axes(projection=ccrs.Robinson())
ax.coastlines(resolution='110m')
ax.stock_img()
def plot_pie_inset(data,ilon,ilat,ax,width):
ax_sub= inset_axes(ax, width=width, height=width, loc=10,
bbox_to_anchor=(ilon, ilat),
bbox_transform=ax.transData,
borderpad=0)
wedges,texts= ax_sub.pie(data)
ax_sub.set_aspect("equal")
lon,lat = 90,30
lonr,latr = ccrs.Robinson().transform_point(lon,lat, ccrs.PlateCarree())
plot_pie_inset([0.25, 0.75],lonr,latr,ax,0.5)
plt.show()

better piechart color scheme

I am trying to create a pie chart, as follows:
import matplotlib.pyplot as plt
import pandas as pd
# make a square figure and axes
plt.figure(1, figsize=(10,10))
plt.axes([0.01, 0.1, 0.6, 0.6])
# plt.style.use('fivethirtyeight')
# The slices will be ordered and plotted counter-clockwise.
labels = 'foo1', 'foo2', 'foo3', 'foo4'
fracs = pd.Series([10,30, 50,10],index=labels)
fracs.plot(kind='pie', labels=None, autopct='%1.0f%%')
plt.legend(bbox_to_anchor=(0.95, .9), loc=2, borderaxespad=0.,labels=labels)
plt.title('pie chart demo which should be center aligned not left', bbox={'facecolor':'0.8', 'pad':5})
plt.show()
Which is yeilding a piechart as:
But, I am facing two problem:
1) I dont like the color scheme. I would like a color scheme more inline with (I need 12 colors)
2) Titel is centered at the pie chart only. The legend is somehow out. I am trying to get the title centered over the chart and the legend.
Can someone kindly help?
I think that is a ggplot colorscheme that you are trying to emulate.
And your plt.axes command is what is displacing your chart to the left.
Try this:
import matplotlib.pyplot as plt
plt.style.use('ggplot')
plt.figure(1, figsize=(10,10))
labels = 'foo1', 'foo2', 'foo3', 'foo4'
sizes = [10,30, 50,10]
plt.pie(sizes, labels=labels)
plt.show()

Resources