Adding pie chart at given coordinates to cartopy projection - python-3.x

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()

Related

problem on filing up the colour between two index values

I have a timeseries data timeseries.txt. First I select a index value (here 50) and put a red line mark on that selected index value. And I want to highlight portion before(idx-20) and after(idx+20) the red line index value on the timeseries.
I wrote this code however i am able to put the red line mark on the timeseries but while using fill_betweenx it doesnot work. I hope experts may help me overcoming this problem.Thanks.
import matplotlib.pyplot as plt
import numpy as np
input_data=np.loadtxt("timeseries.txt")
time=np.arange(len(input_data))
plt.plot(time,input_data)
idx = [50]
mark = [time[i] for i in idx]
plt.plot(idx,[input_data[i] for i in mark], marker="|",color='red',markerfacecolor='none',mew=0.4,ms=30,alpha=2.0)
plt.fill_betweenx(idx-20,idx+20 alpha=0.25,color='lightsteelblue')
plt.show()
If you are looking for just a semi-transparent rectangle, you can use patches.Rectangle to draw one. Refer here. I have updated your code to add a rectangle. See if this meets your requirement. I have used a sine wave as I didn't have your data.
import matplotlib.pyplot as plt
import numpy as np
## Create sine wave
x = np.arange(100)
input_data=np.sin(2*np.pi*3*x/100)
time=np.arange(len(input_data))
plt.plot(time,input_data)
idx = [50]
mark = [time[i] for i in idx]
plt.plot(idx,[input_data[i] for i in mark], marker="|", color='red', markerfacecolor='none', mew=0.4,ms=30,alpha=2.0)
#plt.fill_betweenx(mark,idx-20,0, alpha=0.25,color='lightsteelblue')
# Create a Rectangle patch
import matplotlib.patches as patches
from matplotlib.patches import Rectangle
plt.gca().add_patch(Rectangle((idx[0]-20, -0.15), 40, .3, facecolor = 'lightsteelblue',fill=True,alpha=0.25, lw=0))
plt.show()
EDIT
Please refer to the Rectangle documentation provided earlier in the response. You will need to adjust the start coordinates (x,y) and the height and width to see how big/small you need the Rectangle. For eg: changing the rectangle code like this...
plt.gca().add_patch(Rectangle((idx[0]-10, -0.40), 20, 0.8, facecolor = 'lightsteelblue',fill=True,alpha=0.25, lw=0))
will give you this plot.

How to set up scaled axes with hvplot?

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')

3D plotting of points

I want to use python to plot some specific points in 3D given their coordinates. I want to use the matplotlib library but I'm not sure if there's an easy way of doing this.
Let's say I want to plot the following points:
(1,0,0)
(2,2,2)
(-1,2,0)
(1,2,1)
Since some of the examples around are overly complicated, a minimal example for a 3D scatter plot in matplotlib would look like this:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
fig, ax = plt.subplots(subplot_kw=dict(projection='3d') )
points = [(1,0,0), (2,2,2), (-1,2,0), (1,2,1)]
x,y,z = zip(*points)
ax.scatter(x,y,z, s=100)
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()

Matplotlib: personalize imshow axis

I have the results of a (H,ranges) = numpy.histogram2d() computation and I'm trying to plot it.
Given H I can easily put it into plt.imshow(H) to get the corresponding image. (see http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.imshow )
My problem is that the axis of the produced image are the "cell counting" of H and are completely unrelated to the values of ranges.
I know I can use the keyword extent (as pointed in: Change values on matplotlib imshow() graph axis ). But this solution does not work for me: my values on range are not growing linearly (actually they are going exponentially)
My question is: How can I put the value of range in plt.imshow()? Or at least, or can I manually set the label values of the plt.imshow resulting object?
Editing the extent is not a good solution.
You can just change the tick labels to something more appropriate for your data.
For example, here we'll set every 5th pixel to an exponential function:
import numpy as np
import matplotlib.pyplot as plt
im = np.random.rand(21,21)
fig,(ax1,ax2) = plt.subplots(1,2)
ax1.imshow(im)
ax2.imshow(im)
# Where we want the ticks, in pixel locations
ticks = np.linspace(0,20,5)
# What those pixel locations correspond to in data coordinates.
# Also set the float format here
ticklabels = ["{:6.2f}".format(i) for i in np.exp(ticks/5)]
ax2.set_xticks(ticks)
ax2.set_xticklabels(ticklabels)
ax2.set_yticks(ticks)
ax2.set_yticklabels(ticklabels)
plt.show()
Expanding a bit on #thomas answer
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mi
im = np.random.rand(20, 20)
ticks = np.exp(np.linspace(0, 10, 20))
fig, ax = plt.subplots()
ax.pcolor(ticks, ticks, im, cmap='viridis')
ax.set_yscale('log')
ax.set_xscale('log')
ax.set_xlim([1, np.exp(10)])
ax.set_ylim([1, np.exp(10)])
By letting mpl take care of the non-linear mapping you can now accurately over-plot other artists. There is a performance hit for this (as pcolor is more expensive to draw than AxesImage), but getting accurate ticks is worth it.
imshow is for displaying images, so it does not support x and y bins.
You could either use pcolor instead,
H,xedges,yedges = np.histogram2d()
plt.pcolor(xedges,yedges,H)
or use plt.hist2d which directly plots your histogram.

Resources