Equivalent of pcolormesh for irregular points - python-3.x

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)

Related

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

Is there a maximum amount of ticklabels in a matplotlib axes?

So I have two lists one containing a bunch of years and the other one containing some integers, each list has 17 values.
when I make a simple bar chart
plt.bar(keys,values)
plt.show()
in the X axis of the graph it only contains some of the years in the keys list eg: the graph only has 2000,2002,2005,2007,2010,2012,2015. It has missed 2001,2003,2006,2008,2009 etc.
Is it because there is a maximum amount of keys allowed in the bar chart so it randomly took some keys?
If not how do i fix this?
There is a maximum amount of ticklabels on a matplotlib axes. This limit however lies well above 1000 and you would first run into severe lags when creating the figure.
The usual automatic ticking by matplotlib is that the axes are equipped with just as many labels as needed. I.e. if you plot 50 points on a plot, you would not want to have 50 labels as well. Further if you plot a point at 0.853164 you would not want to have such odd number being displayed as ticklabel on the axes.
Now, I cannot think of any reason matplotlib would produce the labels you report about, 2000,2002,2005,2007,2010,2012,2015, because the automatic locator for the ticks chooses equidistant points on the axes. For any help with this specific problem, a MCVE would be needed.
But in general there are two concepts from which you may choose.
Numerical axes
When plotting numbers, matplotlib will by default choose a linear axes and tick it automatically as described above.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(2000, 2017)
y = np.random.randint(5,21, size=len(x))
plt.bar(x,y)
plt.show()
In this case an equidistant ticking of 2.5 units is chosen to have 7 nicely spaced ticks on the axes. If instead you would want to have every bar ticked, you could use a custom ticker.
E.g. a MultipleLocator with the interval set to 1,
import matplotlib.ticker as mticker
plt.gca().xaxis.set_major_locator(mticker.MultipleLocator(1))
plt.gca().tick_params(axis="x", rotation=90)
Or, a FixedLocator with the locations set to the x values of the bars,
import matplotlib.ticker as mticker
plt.gca().xaxis.set_major_locator(mticker.FixedLocator(x))
plt.gca().tick_params(axis="x", rotation=90)
Categorical axes
You may also decide that your xaxis shall be categorical. This means that every unique value gets its own tick and those ticks are equally spaced, independent of their value. This is easiest accomplished by converting the numbers to strings.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(2000, 2017)
y = np.random.randint(5,21, size=len(x))
cats = list(map(str, x))
plt.bar(cats,y)
plt.gca().tick_params(axis="x", rotation=90)
plt.show()
The result is visually the same as above, but this time, the number 2000 is not at location 2000, but at its index 0, 2001 is at 1 and so on.
You can show all the ticks in this way:
plt.xticks(np.arange(min(keys), max(keys)+1, 1.0), rotation=45)
Example:
keys = [2000, 2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016]
values = range(1,18)
import matplotlib.pyplot as plt
plt.bar(keys,values)
plt.xticks(np.arange(min(keys), max(keys)+1, 1.0), rotation=45)
plt.show()

How to fill area under step curve using pyplot?

I have plotted two step curves using pyplot.step(), and I would like to shade in the area beneath these curves (ideally with transparent shading). pyplot.fill_between() assumes linear interpolation, whereas I want to see step interpolation, as displayed below:
How can I shade in the region beneath these curves? Transparent coloring would be great, as this would make clear where these curves overlap.
You can use the alpha value of the fill_between to make it semi-transparent.
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0,50,35)
y = np.random.exponential(1, len(x))
y2 = np.random.exponential(1, len(x))
plt.fill_between(x,y, step="pre", alpha=0.4)
plt.fill_between(x,y2, step="pre", alpha=0.4)
plt.plot(x,y, drawstyle="steps")
plt.plot(x,y2, drawstyle="steps")
plt.show()

Matplotlib: Move the multiplier below the x-axis to the top

I am trying to find a way to move the little multiplier below the x-axis to the top. I have a plot with two x-axis and the multiplier of the top axis is placed below the bottom x-axis, which I find confusing.
Here is a small example:
import matplotlib as mpl
import matplotlib.pyplot as plt
import seaborn as sns
fig = plt.figure(num=None,figsize=(15, 2.5), dpi=300)
gs = mpl.gridspec.GridSpec(1,1)
ax2 = plt.subplot(gs[0,0])
ax1 = ax2.twiny()
ax1.grid(False)
ax1.set_xlim(0,10000000)
ax2.set_xlim(0,1000000)
ax1.set_ylim([0,100])
ax2.set_ylim([0,100])
plt.show()
Now, if you change ax2.set_xlim(0,1000000) to ax2.set_xlim(0,100000000), then both multipliers are placed below the bottom x-axis. Maybe it is also possible to prevent the multiplier from overlapping with the x-axis tick labels?
My problem with researching this is that I have no idea how this 'multiplier' is actually called.

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