repeat y axis scale along grid line of graph ( matplotlib) - python

I am new to matplotlib and I am trying to figure out if I can repeat the y axis scale
values along the grid lines of the line graph.
The graph has 2 axis,
x-axis has hourly values and y-axis has temperature values.
I need to show the graph for 48 hours, so it results in a long horizontal graph. when user scrolls through the graph horizontally he has x-axis scale available for reference but
y axis scale is way towards left and is not visible.
I need a way to repeat the y-axis scale(temperature values) along all the graph. Is there any way to achieve this?
Is there any better solution to this problem, apart from repeating the values?

You might take a look at the colorbar from this example:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.collections import EllipseCollection
x = np.arange(10)
y = np.arange(15)
X, Y = np.meshgrid(x, y)
XY = np.hstack((X.ravel()[:,np.newaxis], Y.ravel()[:,np.newaxis]))
ww = X/10.0
hh = Y/15.0
aa = X*9
ax = plt.subplot(1,1,1)
ec = EllipseCollection(
ww,
hh,
aa,
units='x',
offsets=XY,
transOffset=ax.transData)
ec.set_array((X+Y).ravel())
ax.add_collection(ec)
ax.autoscale_view()
ax.set_xlabel('X')
ax.set_ylabel('y')
cbar = plt.colorbar(ec)
cbar.set_label('X+Y')
plt.show()
A quick experiment shows me that you can pan/zoom the main window and the colorbar will stay constant.

Related

Artificial tick labels for seaborn heatmaps

I have a seaborn heatmap that looks like this:
...generated from a pandas dataframe of randomly generated values a piece of which looks like this:
The values along the y axis are all in the range [0,1], and the ones on the x axis in the range [0,2*pi], and I just want some short floats at regular intervals for my tick labels, but I can only seem to get values that are in my dataframe. When I try specifying the values I want, it doesn't put them in the right place, as seen in the plot above. He's my code right now. How can I get the axis labels that I tried specifying with xticks and yticks in this code in the correct places (which would be evenly spaced along the axes)?
import pandas as pd
import numpy as np
import matplotlib as plt
from matplotlib.mlab import griddata
sns.set_style("darkgrid")
PHI, COSTH = np.meshgrid(phis, cos_thetas)
THICK = griddata(phis, cos_thetas, thicknesses, PHI, COSTH, interp='linear')
thick_df = pd.DataFrame(THICK, columns=phis, index=cos_thetas)
thick_df = thick_df.sort_index(axis=0, ascending=False)
thick_df = thick_df.sort_index(axis=1)
cmap = sns.cubehelix_palette(start=1.6, light=0.8, as_cmap=True, reverse=True)
yticks = np.array([0,0.2,0.4,0.6,0.8,1.0])
xticks = np.array([0,1,2,3,4,5,6])
g = sns.heatmap(thick_df, linewidth=0, xticklabels=xticks, yticklabels=yticks, square=True, cmap=cmap)
plt.show(g)
Here's something that should do what you want:
cmap = sns.cubehelix_palette(start=1.6, light=0.8, as_cmap=True, reverse=True)
yticks = np.linspace(0,1,6)
x_end = 6
xticks = np.arange(x_end+1)
ax = sns.heatmap(thick_df, linewidth=0, xticklabels=xticks, yticklabels=yticks[::-1], square=True, cmap=cmap)
ax.set_xticks(xticks*ax.get_xlim()[1]/(2*math.pi))
ax.set_yticks(yticks*ax.get_ylim()[1])
plt.show()
You could pass ['{:,.2f}'.format(x) for x in xticks] instead of xticks to get a float with 2 decimals.
Note that I'm reversing the yticklabels because that's what seaborn does: see matrix.py#L138.
Seaborn calculates the tick positions around the same place (e.g.: #L148), for you that amounts to:
# thick_df.T.shape[0] = thick_df.shape[1]
xticks: np.arange(0, thick_df.T.shape[0], 1) + .5
yticks: np.arange(0, thick_df.T.shape[1], 1) + .5

Contour plotting complex numbers and conjugates

I am trying to make a contour plot in python with complex numbers (i am using matplotlib, pylab).
I am working with sharp bounds on harmonic polynomials, but specifically right now I am trying to plot:
Re(z(bar) - e^(z))= 0
Im(z(bar) - e^z) = 0
and plot them over each other in a contour in order to find their zeros to determine how many solutions there are to the equation z(bar) = e^(z).
Does anyone have experience in contour plotting, specifically with complex numbers?
import numpy as np
from matplotlib import pyplot as plt
x = np.r_[0:10:30j]
y = np.r_[0:10:20j]
X, Y = np.meshgrid(x, y)
Z = X*np.exp(1j*Y) # some arbitrary complex data
def plotit(z, title):
plt.figure()
cs = plt.contour(X,Y,z) # contour() accepts complex values
plt.clabel(cs, inline=1, fontsize=10) # add labels to contours
plt.title(title)
plt.savefig(title+'.png')
plotit(Z, 'real')
plotit(Z.real, 'explicit real')
plotit(Z.imag, 'imaginary')
plt.show()
EDIT: Above is my code, and note that for Z, I need to plot both real and imaginary parts of (x- iy) - e^(x+iy)=0. The current Z that is there is simply arbitrary. It is giving me an error for not having a 2D array when I try to plug mine in.
I don't know how you are plotting since you didn't post any code, but in general I advise moving away from using pylab or the pyplot interface to matplotlib, using the direct object methods is much more robust and just as simple. Here is an example of plotting contours of two sets of data on the same plot.
import numpy as np
import matplotlib.pyplot as plt
# making fake data
x = np.linspace(0, 2)
y = np.linspace(0, 2)
c = x[:,np.newaxis] * y
c2 = np.flipud(c)
# plot
fig, ax = plt.subplots(1, 1)
cont1 = ax.contour(x, y, c, colors='b')
cont2 = ax.contour(x, y, c2, colors='r')
cont1.clabel()
cont2.clabel()
plt.show()
For tom10, here is the plot this code produces. Note that setting colors to a single color makes distinguishing the two plots much easier.

Heatmap with 3D data in matplotlib

I want to generate a heat map with my 3D data.
I have been able to plot trisurf using this data.
Can some one help me generate a heat map? I saw the online tutorials but they all seem quite complex for 3D. I found one on this website 'generating heatmap with scatter point in matplotlib but that is having only 2D data.
My code to generate trisurf is
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
n_angles = 36
n_radii = 8
# An array of radii
# Does not include radius r=0, this is to eliminate duplicate points
radii = np.linspace(0.125, 1.0, n_radii)
# An array of angles
angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)
# Repeat all angles for each radius
angles = np.repeat(angles[...,np.newaxis], n_radii, axis=1)
# Convert polar (radii, angles) coords to cartesian (x, y) coords
# (0, 0) is added here. There are no duplicate points in the (x, y) plane
x,y,z =np.loadtxt('output/flash_KR_endowment_duration_3D.dat',delimiter='\t',usecols=(0,1,2),unpack=True)
#x,y,z =np.loadtxt('output/disk_KR_endowment_duration_3D.dat',delimiter='\t',usecols=(0,1,2),unpack=True)
fig = plt.figure()
ax = fig.gca(projection='3d')
#fig.suptitle(suptitle, fontsize=12, fontweight='bold')
#ax.set_title("Disk Kryder's Rate-Endowment-Duration Plot",fontsize=12)
ax.set_title("Flash Kryder's Rate-Endowment-Duration Plot",fontsize=12)
ax.set_xlabel("Kryder's rate")
ax.set_ylabel("Duration")
ax.set_zlabel("Endowment")
surf = ax.plot_trisurf(x, y, z, cmap=cm.jet, linewidth=0.2)
fig.colorbar(surf, shrink=.7, aspect=20)
plt.show()
Data is 3 column. say X,Y,Z. I have tried 3D scatter plot with color. But I am looking for heatmap.
If you only "want to use 3rd dimension for coloring", you can do it like this:
import pandas as pd
import numpy as np
import plotly.plotly as plotly
from plotly.graph_objs import Data, Heatmap
plotly.sign_in("username", "api_key") # this is annoying but you can get one after registering - free
# generate tridimentional data
pp = pd.Panel(np.random.rand(20, 20, 20))
# crunch (sum, average...) data along one axis
crunch = pp.sum(axis=0)
# now plot with plot.ly or matplotlib as you wish
data = Data([Heatmap(z=np.array(crunch))])
plotly.image.save_as(data, "filename.pdf")
Result - heatmap with 3rd variable of 3D data as colour:
Additionally, you can plot for each combination of axis with a loop:
## Plot
# for each axis, sum data along axis, plot heatmap
# dict is axis:[x,y,z], where z is a count of that variable
desc = {0 : ["ax1", "ax2", "ax3"], 1 : ["ax1", "ax2", "ax3"], 2 : ["ax1", "ax2", "ax3"]}
for axis in xrange(3):
# crunch (sum) data along one axis
crunch = pp.sum(axis=axis)
# now let's plot
data = Data([Heatmap(
z=np.array(crunch),
x=crunch.columns,
y=crunch.index)]
)
plotly.image.save_as(data,
"heatmap_{0}_vs_{1}_count_of_{2}".format(desc[axis][0], desc[axis][1], desc[axis][2])
)

Add margin in a 2D scatter plot

How would you add a margin between the axis lines and the actual origin? In 3D scatter, like this one, the origin of x = 6 and y = -10 are not on the same point. How to do the same thing but in a 2D scatter (something similar to the graphic of p. 122 (132 of pdf) in this matplotlib doc, where the origin x = 0 and y = 0 are not located at the same place).
A margin can be easily added to any plot by supplying the plt.set_xmargin(m) with a float between 0 and 1 indicating the relative size of the margin:
import matplotlib.pyplot as plt
import numpy as np
fig =plt.figure()
ax = plt.subplot(111)
x = np.linspace(0, 10, 100)
y = np.cos(x)
ax.set_xmargin(0.2)
ax.set_ymargin(0.2)
ax.plot(x, y)
Note in practise this needs to be called before ax.plot(.. as this is when the autoscaling is done. For more information see here

How to plot one line in different colors

I have two list as below:
latt=[42.0,41.978567980875397,41.96622693388357,41.963791391892457,...,41.972407378075879]
lont=[-66.706920989908909,-66.703116557977069,-66.707351643324543,...-66.718218142021925]
now I want to plot this as a line, separate each 10 of those 'latt' and 'lont' records as a period and give it a unique color.
what should I do?
There are several different ways to do this. The "best" approach will depend mostly on how many line segments you want to plot.
If you're just going to be plotting a handful (e.g. 10) line segments, then just do something like:
import numpy as np
import matplotlib.pyplot as plt
def uniqueish_color():
"""There're better ways to generate unique colors, but this isn't awful."""
return plt.cm.gist_ncar(np.random.random())
xy = (np.random.random((10, 2)) - 0.5).cumsum(axis=0)
fig, ax = plt.subplots()
for start, stop in zip(xy[:-1], xy[1:]):
x, y = zip(start, stop)
ax.plot(x, y, color=uniqueish_color())
plt.show()
If you're plotting something with a million line segments, though, this will be terribly slow to draw. In that case, use a LineCollection. E.g.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
xy = (np.random.random((1000, 2)) - 0.5).cumsum(axis=0)
# Reshape things so that we have a sequence of:
# [[(x0,y0),(x1,y1)],[(x0,y0),(x1,y1)],...]
xy = xy.reshape(-1, 1, 2)
segments = np.hstack([xy[:-1], xy[1:]])
fig, ax = plt.subplots()
coll = LineCollection(segments, cmap=plt.cm.gist_ncar)
coll.set_array(np.random.random(xy.shape[0]))
ax.add_collection(coll)
ax.autoscale_view()
plt.show()
For both of these cases, we're just drawing random colors from the "gist_ncar" coloramp. Have a look at the colormaps here (gist_ncar is about 2/3 of the way down): http://matplotlib.org/examples/color/colormaps_reference.html
Copied from this example:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap, BoundaryNorm
x = np.linspace(0, 3 * np.pi, 500)
y = np.sin(x)
z = np.cos(0.5 * (x[:-1] + x[1:])) # first derivative
# Create a colormap for red, green and blue and a norm to color
# f' < -0.5 red, f' > 0.5 blue, and the rest green
cmap = ListedColormap(['r', 'g', 'b'])
norm = BoundaryNorm([-1, -0.5, 0.5, 1], cmap.N)
# Create a set of line segments so that we can color them individually
# This creates the points as a N x 1 x 2 array so that we can stack points
# together easily to get the segments. The segments array for line collection
# needs to be numlines x points per line x 2 (x and y)
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
# Create the line collection object, setting the colormapping parameters.
# Have to set the actual values used for colormapping separately.
lc = LineCollection(segments, cmap=cmap, norm=norm)
lc.set_array(z)
lc.set_linewidth(3)
fig1 = plt.figure()
plt.gca().add_collection(lc)
plt.xlim(x.min(), x.max())
plt.ylim(-1.1, 1.1)
plt.show()
See the answer here to generate the "periods" and then use the matplotlib scatter function as #tcaswell mentioned. Using the plot.hold function you can plot each period, colors will increment automatically.
Cribbing the color choice off of #JoeKington,
import numpy as np
import matplotlib.pyplot as plt
def uniqueish_color(n):
"""There're better ways to generate unique colors, but this isn't awful."""
return plt.cm.gist_ncar(np.random.random(n))
plt.scatter(latt, lont, c=uniqueish_color(len(latt)))
You can do this with scatter.
I have been searching for a short solution how to use pyplots line plot to show a time series coloured by a label feature without using scatter due to the amount of data points.
I came up with the following workaround:
plt.plot(np.where(df["label"]==1, df["myvalue"], None), color="red", label="1")
plt.plot(np.where(df["label"]==0, df["myvalue"], None), color="blue", label="0")
plt.legend()
The drawback is you are creating two different line plots so the connection between the different classes is not shown. For my purposes it is not a big deal. It may help someone.

Categories

Resources