I am trying to add hatching (like dots, hashes, .. ) over contour map. Such hatching could represent the only the statistically significant contours, or contours with certain criteria. Like the following image on nature article (second and third plot) http://www.nature.com/articles/srep16853/figures/3.
The following code show plot of precipitation from NOAA data available for download at.
import numpy as np
import sys
import netCDF4 as nc
import matplotlib.pyplot as plt
import matplotlib.mlab as m
import mpl_toolkits.basemap as bm
import os
sys.path.insert(0, '../');import py4met as sm;reload(sm)
#- Reading data for a timeslice, latitude, and longitude:
diri_output="./"
diri="./"
tmp_file = nc.Dataset(diri+"precip.mon.mean.nc","r")
print(tmp_file.variables)
p_pre = tmp_file.variables['precip']
lat = tmp_file.variables['lat'][:]
lon = tmp_file.variables['lon'][:]
time = tmp_file.variables['time']
tmp_file.close
lat1=np.min(lat)
lat2=np.max(lat)
lon1=np.min(lon)
lon2=np.max(lon)
[lonall, latall] = np.meshgrid(lon[:], lat[:])
plt.figure(num=None, figsize=(8+4, 6+4), dpi=80, facecolor='w', edgecolor='k')
mapproj = bm.Basemap(projection='cyl',llcrnrlat=lat1, llcrnrlon=lon1,urcrnrlat=lat2, urcrnrlon=lon2,resolution='l')
mapproj.drawcoastlines()
mapproj.drawmapboundary(fill_color='white')
mapproj.drawcountries()
x, y = mapproj(lonall, latall)
plt.contourf(x,y,p_pre[240,:,:],cmap=plt.cm.GnBu)
plt.colorbar(orientation='horizontal',pad=0.05,shrink=0.6)
plt.title("title")
xx,yy=np.where(p_pre[240,:,:] >= 20)
sig=np.copy(p_pre[0,:,:])
sig[:,:]=1
sig[xx,yy]=0
#plt.contourf(x,y,sig,hatches=['.'])
plt.show()
I want to hatch all contours above 20 mm, so I used the above command
plt.contourf(x,y,sig,hatches=['.'])
but it didn’t work (it make dotes everywhere on the map and not only contours with specific criteria), thus I commented it.
Any ideas.
See this matplotlib example page for a demo of how hatches can be used with contourf. Of particular relevance to your problem is that (1) there is a keyword level that contourf takes in order to establish the bounds of what values get colored and/or hatched and (2) an empty string "" can be used for the absence of a hatch.
So, instead of the plt.contourf line you have commented out try
levels = [p_pre[240,:,:].min(), 20, p_pre[240,:,:].max()]
plt.contourf(x, y, p_pre[240,:,:], levels=levels, hatches=["", "."], alpha=0)
I had trouble recreating your plot from the data you linked to, so I generated some random data to make the image below using the same principles I describe above.
Related
First time user so apologies for any mistakes.
I have some code (pasted below) which is used to analyse and gain values/graphs from a simulation I have run.
This results in the following image:
I would therefore now like to plot a line graph on top of this according to the values of the colour map corresponding to r = 0 on the y-axis at every point on the x - axis with each respective value on the colour map. However, I'm completely lost on where to even begin with this. I've tried looking into KDE and other similar things, but I realise I'm not sure how to take numerical values which were used to generate the colour map.
from openpmd_viewer import OpenPMDTimeSeries
from openpmd_viewer.addons import LpaDiagnostics
import numpy as np
from scipy.constants import c, e, m_e
import matplotlib.pyplot as plt
from matplotlib import gridspec
# Replace the string below, to point to your data
ts = OpenPMDTimeSeries(r"/Users/bentorrance/diags/hdf5/")
ts_2d = LpaDiagnostics(r"/Users/bentorrance/diags/hdf5/")
plt.figure(1)
Ez = ts.get_field(iteration=5750, field='E', coord='z', plot=True, cmap='inferno')
plt.title(r'Electric Field Density $E_{z}$')
plt.show()
I am new in Python. The answer to my question might be available in the StackOverflow, but honestly speaking, I tried almost all the codes and suggestions available in the StackOverflow.
My problem: Almost the same as it is described here. I have coordinate points (x and y) and the corresponding value (p) as a .csv file. I am reading that file using pandas.
df = pd.read_csv("example.csv")
The example.csv file can be download from here. Let an image of size 2000 x 2000.
Task:
Based on the x and y coordinate points in the excel sheet, I have to locate the point in that image.
Lets, A is an image and A(x,y) is any point within A. Now I have to generate a heat map in such a way so that 50 pixels from x and 50 pixels fromy i.e., A(x,y), A(x+50, y), A(x, y+50) and A(x+50, y+50) contains p corresponding to that coordinate points.
I found this link which is very helpful and serves my issue, but the problem is some more modifications are necessary for my datasets.
The code which is available in the above link:
#!/usr/bin/python3
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from skimage import io
from skimage.color import rgb2gray
import matplotlib as mpl
# Read original image
img = io.imread('img.jpg')
# Get the dimensions of the original image
x_dim, y_dim, z_dim = np.shape(img)
# Create heatmap
heatmap = np.zeros((x_dim, y_dim), dtype=float)
# Read CSV with a Pandas DataFrame
df = pd.read_csv("data.csv")
# Set probabilities values to specific indexes in the heatmap
for index, row in df.iterrows():
x = np.int(row["x"])
y = np.int(row["y"])
x1 = np.int(row["x1"])
y1 = np.int(row["y1"])
p = row["Probability value"]
heatmap[x:x1,y:y1] = p
# Plot images
fig, axes = plt.subplots(1, 2, figsize=(8, 4))
ax = axes.ravel()
ax[0].imshow(img)
ax[0].set_title("Original")
fig.colorbar(ax[0].imshow(img), ax=ax[0])
ax[1].imshow(img, vmin=0, vmax=1)
ax[1].imshow(heatmap, alpha=.5, cmap='jet')
ax[1].set_title("Original + heatmap")
# Specific colorbar
norm = mpl.colors.Normalize(vmin=0,vmax=2)
N = 11
cmap = plt.get_cmap('jet',N)
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
plt.colorbar(sm, ticks=np.linspace(0,1,N),
boundaries=np.arange(0,1.1,0.1))
fig.tight_layout()
plt.show()
Issues which I am facing when using this code:
This code is generating a heat map of square edges, but I am expecting a smooth edge. I know Gaussian distribution might solve this problem. But I am new in python and I don't know how to implement the Gaussian Distribution in my dataset.
The regions which don't belong to the coordinate points also generating a layer of color. As a result in an overlayed image those layer covering the background of original images. In one sentence I want the background of the heat map will be transparent so that overlays will not create any problem in showing the regions which are not covered by the coordinate points.
Any leads will be highly appreciated.
Your code is perfect. Just change only one line, then your both issues will be solved.
Before changes:
ax[1].imshow(heatmap, alpha=.5, cmap='jet')
After changes:
ax[1].imshow(heatmap, alpha=.5, cmap='coolwarm', interpolation='gaussian')
Though above changes will solve your issue, but if you want then for additional transparency, you can use below function
def transparent_cmap(cmap, N=255):
"Copy colormap and set alpha values"
mycmap = cmap
mycmap._init()
mycmap._lut[:,-1] = np.linspace(0, 0.8, N+4)
return mycmap
mycmap = transparent_cmap(plt.cm.coolwarm)
In that case, your previous code line will change like below:
ax[1].imshow(heatmap, alpha=.5, cmap=mycmap, vmin=0, vmax=1)
The question you linked uses plotly. If you don't want to use that and want to simply smooth the way your data looks, I suggest just using a gaussian filter using scipy.
At the top, import:
import seaborn as sns
from scipy.ndimage.filters import gaussian_filter
Then use it like this:
df_smooth = gaussian_filter(df, sigma=1)
sns.heatmap(df_smooth, vmin=-40, vmax=150, cmap ="coolwarm" , cbar=True , cbar_kws={"ticks":[-40,150,-20,0,25,50,75,100,125]})
You can change the amount of smoothing, using e.g. sigma=3, or any other number that gives you the amount of smoothing you want.
Keep in mind that that will also "smooth out" any maximum data peaks you have, so your minimum and maximum data will not be the same that you specified in your normalization anymore. To still get good looking heatmaps I would suggest not using fixed values for your vmin and vmax, but:
sns.heatmap(df_smooth, vmin=np.min(df_smooth), vmax=np.max(df_smooth), cmap ="coolwarm" , cbar=True , cbar_kws={"ticks":[-40,150,-20,0,25,50,75,100,125]})
In case that you Gaussian filter fulfill your expectations you mentioned you can even implement Gaussian normalization on your data directly.
I'm currently trying to plot with matplotlib a 2d map recorded with an instrument. The instrument is moving 2 motors (it makes a raster) and records the associated intensity value.
I'm currently able to plot the data and to associate the values I want to the axes, but I would like to digitize (make discrete) these values in order to obtain at each pixel of the image the corresponding values for the motors.
I'm currently using the following code (in the example I'll use x and y to define the motor positions):
import pylab as pl
pl.imshow(intensity, extent=(x_min, x_max, y_min, y_max),
interpolation='none')
The code works quite well but if I select one of the pixel on my plot with the cursor, it returns continuous values with many digits (like in figure).
Would it be possible to obtain directly the values of the motors (which I have stored for each point/pixel) by positioning the cursor on them?
Thanks for the help,
Fabio
You can do it by modifying the coordinate formatter like in this example on the matplotlib documentation. A simple adaptation to your request is:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
X = 10*np.random.rand(5, 3)
fig, ax = plt.subplots()
ax.imshow(X, cmap=cm.jet, interpolation='nearest')
def format_coord(x, y):
return 'x=%i, y=%i' % (x+1, y+1)
ax.format_coord = format_coord
plt.show()
, which will result in this:
Also you might want to check out mpldatacursor for something more pretty. For this option take a look at this question here in SO.
I have bubble plot like this, and I am willing to put labels next to each bubble (their name). Does any body know how to do that?
#Falko refered to another post that indicates you should be looking for the text method of the axes. However, your problem is quite a bit more involved than that, because you'll need to implement an offset that scales dynamically with the size of the "bubble" (the marker). That means you'll be looking into the transformation methods of matplotlib.
As you didn't provide a simple example dataset to experiment with, I've used one that is freely available: earthquakes of 1974. In this example, I'm plotting the depth of the quake vs the date on which it occurred, using the magnitude of the earthquake as the size of the bubbles/markers. I'm appending the locations of where these earthquakes happened next to the markers, not inside (which is far more easy: ignore the offset and set ha='center' in the call to ax.text).
Note that the bulk of this code example is merely about getting some dataset to toy with. What you really needed was just the ax.text method with the offset.
from __future__ import division # use real division in Python2.x
from matplotlib.dates import date2num
import matplotlib.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# Get a dataset
data_url = 'http://datasets.flowingdata.com/earthquakes1974.csv'
df = pd.read_csv(data_url, parse_dates=['time'])
# Select a random subset of that dataframe to generate some variance in dates, magnitudes, ...
data = np.random.choice(df.shape[0], 10)
records = df.loc[data]
# Taint the dataset to add some bigger variance in the magnitude of the
# quake to show that the offset varies with the size of the marker
records.mag.values[:] = np.arange(10)
records.mag.values[0] = 50
records.mag.values[-1] = 100
dates = [date2num(dt) for dt in records.time]
f, ax = plt.subplots(1,1)
ax.scatter(dates, records.depth, s=records.mag*100, alpha=.4) # markersize is given in points**2 in recentt versions of mpl
for _, record in records.iterrows():
# Specify an offset for the text annotation:
# it is approx the radius of the disc + 10 points to the right
dx, dy = np.sqrt(record.mag*100)/f.dpi/2 + 10/f.dpi, 0.
offset = transforms.ScaledTranslation(dx, dy, f.dpi_scale_trans)
ax.text(date2num(record.time), record.depth, s=record.place,
va='center', ha='left',
transform=ax.transData + offset)
ax.set_xticks(dates)
ax.set_xticklabels([el.strftime("%Y-%M") for el in records.time], rotation=-60)
ax.set_ylabel('depth of earthquake')
plt.show()
For one such run, I got:
Definitely not pretty because of the overlapping labels, but it was just an example to show how to use the transforms in matplotlib to dynamically add an offset to the labels.
I am working on project to find similarity between two sentences/documents using tf-idf measure.
Now my question is how can I show the similarity in a graphical/Visualization format. Something like a Venn diagram where intersection value becomes the similarity measure or any other plots available in matplotlib or any python libraries.
I tried the following code:
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
documents = (
"The sky is blue",
"The sun is bright"
)
tfidf_vectorizer = TfidfVectorizer()
tfidf_matrix = tfidf_vectorizer.fit_transform(documents)
print tfidf_matrix
cosine = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix)
print cosine
import matplotlib.pyplot as plt
r=25
d1 = 2 * r * (1 - cosine[0][0])
circle1=plt.Circle((0,0),d1/2,color='r')
d2 = 2 * r * (1 - cosine[0][1])
circle2=plt.Circle((r,0),d2/2,color="b")
fig = plt.gcf()
fig.gca().add_artist(circle1)
fig.gca().add_artist(circle2)
fig.savefig('plotcircles.png')
plt.show()
But the plot I got was empty. Can some one explain what might be the error.
plotting circle source:plot a circle
Just to explain what's going on, here's a stand-alone example of your problem (if the circle is entirely outside the boundaries, nothing would be shown):
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
fig, ax = plt.subplots()
circ = Circle((1, 1), 0.5)
ax.add_artist(circ)
plt.show()
When you manually add an artist through add_artist, add_patch, etc, autoscaling isn't applied unless you explicitly do so. You're accessing a lower-level interface of matplotlib that's what the higher-level functions (e.g. plot) are built on top of. However, this is also the easiest way to add a single circle in data coordinates, so the lower-level interface is what you want in this case.
Furthermore, add_artist is too general for this. You actually want add_patch (plt.Circle is matplotlib.patches.Circle). The difference between add_artist and add_patch may seem arbitrary, but add_patch has extra logic to calculate the extent of a patch for autoscaling, whereas add_artist is the "bare" lower-level function that can take any artist, but doesn't do anything special. Autoscaling won't work correctly for a patch if you add it with add_artist.
To autoscale the plot based on the artists that you've added, call ax.autoscale():
As a quick example of autoscaling a manually added patch:
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
fig, ax = plt.subplots()
circ = Circle((1, 1), 0.5)
ax.add_patch(circ)
ax.autoscale()
plt.show()
Your next question might be "why isn't the circle round?". It is, in data coordinates. However, the x and y scales of the plot (this is the aspect ratio, in matplotlib terminology) are currently different. To force them to be the same, call ax.axis('equal') or ax.axis('scaled'). (We can actually leave out the call to autoscale in this case, as ax.axis('scaled'/'equal') will effectively call it for us.):
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
fig, ax = plt.subplots()
circ = Circle((1, 1), 0.5)
ax.add_patch(circ)
ax.axis('scaled')
plt.show()
The Plots are not empty, but I guess, your circles are to big!
I don't have sklearn installed, so I start at the point where you print cosine:
## set constants
r = 1
d = 2 * r * (1 - cosine[0][1])
## draw circles
circle1=plt.Circle((0, 0), r, alpha=.5)
circle2=plt.Circle((d, 0), r, alpha=.5)
## set axis limits
plt.ylim([-1.1, 1.1])
plt.xlim([-1.1, 1.1 + d])
fig = plt.gcf()
fig.gca().add_artist(circle1)
fig.gca().add_artist(circle2)
## hide axes if you like
# fig.gca().get_xaxis().set_visible(False)
# fig.gca().get_yaxis().set_visible(False)
fig.savefig('venn_diagramm.png')
That also answers your other question, where I also added this piece of code!