How to plot the free energy landscape of protein structure? - python

I understand the question is not appropriate for this platform, but I can try if I can get some hints,
I've been trying to plot the free energy landscape of a protein structure ("Chignolin"). I'm completely run out of ideas how to do that!! I've MD simulation trajectory file Trajectory file and using pyemma to plot the energy landscape. But I'm getting the error
""
TypeError: plot_free_energy() takes from 2 to 20 positional arguments but 28 were given
""
Could someone figure out where the problem lies?
Here is my code
import numpy as np
import matplotlib.pyplot as plt
import mdtraj as md
from itertools import combinations
from simtk.openmm.app.topology import Topology
from simtk.openmm.app.simulation import Simulation
from simtk.openmm.app.dcdreporter import DCDReporter
from simtk.openmm.app.statedatareporter import StateDataReporter
import simtk.unit as u
import simtk.openmm as mm
import simtk.openmm.openmm as openmm
import pyemma.coordinates as coor
import pyemma
pdb = md.load('1uao_Calpha.pdb')
feat = pyemma.coordinates.data.MDFeaturizer(pdb)
feat.add_distances_ca(periodic=False)
files = pyemma.coordinates.load('traj/DESRES/CLN025-0-c-alpha/CLN025-0-c-alpha-005.dcd', features = feat)
pyemma.plots.plot_free_energy(*files.T)
plt.show()
Here is the another pdb file.

I recommend you start reading the documentation, especially the "learn PyEMMA" section containing Jupyter notebooks teaching you the work-flow to extract properly weighted "pseudo" free-energy surfaces. Usually these surfaces are drawn into the dimensions of the first two slowest dynamical processes, but you can think of any other combination as well. These dimensions are defined by a TICA or VAMP projection, which are basically methods to extract the slow modes from your data, in case of proteins this contains folding and rare events.
As a primer I suggest reading this tutorial first, as it gives you a brief overview how to load and process your data to extract the slow modes. Note that this not yet contain Markov state modelling, so read further in the other examples to learn about that.

Related

Interactive Xarray dataset raster visualisation app using Panel and hvplot

I am trying to replicate the Glaciers Demo using an Xarray of geospatial data. I am able to create pretty much exactly what I want but I am trying to create a Panel app that allows the user to select the data_vars, each of which has different dimensions that I want make interactable, and visualize on an interactive map with at least the continents contour. Here is what my Xarray Dataset looks like :
def plot(field):
return xds[field].hvplot.image().opts(cmap='jet',height=650,width=1300,data_aspect=1)
interact(plot, field = list(xds.data_vars))
and here is what the code above produces in a notebook :
I would like to integrate the selector for the data_vars and then depending on its dimensions have interactive maps with controls for all its dimensions (ES has (time, pres1, lat, lon) while P0 has only (time, lat, lon)) and I would like to have the controls in the sidebar and the plots in the main of the following template :
from turtle import width
from matplotlib.pyplot import title
import panel as pn
import numpy as np
import holoviews as hv
from panel.template import DefaultTheme
from pathlib import Path
import fstd2nc
import hvplot.xarray
import xarray as xr
from unicodedata import name
import hvplot
import param
from panel.interact import interact
pn.extension(sizing_mode='stretch_width')
bootstrap = pn.template.MaterialTemplate(title='Material Template', theme=DefaultTheme, )
glob_path = Path(r"C:\Users\spart\Documents\Anaconda-Work-Dir")
file_list = [str(pp).split('\\')[-1] for pp in glob_path.glob("2022*")]
phase = pn.widgets.FloatSlider(name="Phase", start=0, end=np.pi)
fileSel = pn.widgets.Select(name='Select File', options=file_list)
#pn.depends(fileSel=fileSel)
def selectedFile(fileSel):
base_path = r"C:\Users\spart\Documents\Anaconda-Work-Dir\{}".format(fileSel)
return pn.widgets.StaticText(name='Selected', value=base_path)
#pn.depends(fileSel=fileSel)
def dataXArray(fileSel):
base_path = r"C:\Users\spart\Documents\Anaconda-Work-Dir\{}".format(fileSel)
xds = fstd2nc.Buffer(base_path).to_xarray()
return xds.ES.hvplot( width=500)
bootstrap.sidebar.append(fileSel)
bootstrap.sidebar.append(selectedFile)
bootstrap.main.append(
pn.Row(
pn.Card(hv.DynamicMap(dataXArray), title='Plot'),
)
)
bootstrap.show()
EDIT : Here is a link to an example dataset which can be loaded with the following code
xds = fstd2nc.Buffer(PATH_TO_FILE).to_xarray()
Without the data file I can't easily run the code, but some observations:
If using bare functions like this rather than classes, I'd recommend using pn.bind rather than pn.depends; it really helps get the code organized better.
For a simple application like this, I'd use hvPlot .interactive: https://hvplot.holoviz.org/user_guide/Interactive.html
I can't seem to find this in the docs, but you can pull out the widgets from the result of dataXArray (or any other hvplot or holoviews object) using .widgets(), and you can then put that in the sidebar. You can then pull out just the plot using .panel(), and put that in the main area.
If that helps you get it done, then great; if not please post a sample data file or two so that it's runnable, and I can look into it further. And please submit a PR to the docs once you get it working so that future users have less trouble!

Python mapping: plotting an electoral boundary over a street map?

I would have thought this would be so simple it would be almost example 1 in any mapping documentation. But it seems not... I want to map the boundary of an electorate over a street map, using cartopy. I can download the GIS data of the electorates in either MapInfo or ShapeFile form. When I tried to do this a year ago, the only way I could find to do it was to extract the lat/long coordinates of the MapInfo polygon, and plot them with matplotlib.
I'm trying to be a bit more elegant this year. With the MapInfo file, I can isolate my particular electorate with
import geopandas as gpd
v = gpd.read_file('VicMaps/vic-july-2018-mid-mif/E_VIC18.MIF')
cg = v.loc[7].geometry
My efforts to extract a particular single boundary from a shapefile are given below.
The other issue is that when I try to run this in jupyter, attempts at plotting a map causes the kernel (python 3.4) to crash.
There must be examples of this somewhere, but so far I haven't found an example which works with my data. This is what I have so far, cobbled together from various helpful answers to other people's questions:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from cartopy.io.shapereader import Reader
from cartopy.io.img_tiles import OSM
shp = Reader('VicMaps/E_AUGFN3_region.shp')
fig = plt.figure(figsize=(16,16))
tiler = OSM()
ax = plt.axes(projection=tiler.crs)
ax.set_extent([144.956158, 145.085398, -37.813662, -37.690999])
for r, g in zip(shp.records(), shp.geometries()):
if r.attributes['Elect_div'] == 'Cooper':
ax.add_geometries(g, ccrs.Geodetic())
plt.show()
But what happens is that the kernel just dies "unexpectedly".
If anybody could point me in the direction of a solution, I'd be delighted! Also: I'm not wedded to cartopy; if there's a better package I'll use it.
Thanks!

Matplotlib plotting slow [duplicate]

I have got a problem (with my RAM) here: it's not able to hold the data I want to plot. I do have sufficient HD space. Is there any solution to avoid that "shadowing" of my data-set?
Concretely I deal with Digital Signal Processing and I have to use a high sample-rate. My framework (GNU Radio) saves the values (to avoid using too much disk space) in binary. I unpack it. Afterwards I need to plot. I need the plot zoomable, and interactive. And that is an issue.
Is there any optimization potential to this, or another software/programming language (like R or so) which can handle larger data-sets? Actually I want much more data in my plots. But I have no experience with other software. GNUplot fails, with a similar approach to the following. I don't know R (jet).
import matplotlib.pyplot as plt
import matplotlib.cbook as cbook
import struct
"""
plots a cfile
cfile - IEEE single-precision (4-byte) floats, IQ pairs, binary
txt - index,in-phase,quadrature in plaintext
note: directly plotting with numpy results into shadowed functions
"""
# unpacking the cfile dataset
def unpack_set(input_filename, output_filename):
index = 0 # index of the samples
output_filename = open(output_filename, 'wb')
with open(input_filename, "rb") as f:
byte = f.read(4) # read 1. column of the vector
while byte != "":
# stored Bit Values
floati = struct.unpack('f', byte) # write value of 1. column to a variable
byte = f.read(4) # read 2. column of the vector
floatq = struct.unpack('f', byte) # write value of 2. column to a variable
byte = f.read(4) # next row of the vector and read 1. column
# delimeter format for matplotlib
lines = ["%d," % index, format(floati), ",", format(floatq), "\n"]
output_filename.writelines(lines)
index = index + 1
output_filename.close
return output_filename.name
# reformats output (precision configuration here)
def format(value):
return "%.8f" % value
# start
def main():
# specify path
unpacked_file = unpack_set("test01.cfile", "test01.txt")
# pass file reference to matplotlib
fname = str(unpacked_file)
plt.plotfile(fname, cols=(0,1)) # index vs. in-phase
# optional
# plt.axes([0, 0.5, 0, 100000]) # for 100k samples
plt.grid(True)
plt.title("Signal-Diagram")
plt.xlabel("Sample")
plt.ylabel("In-Phase")
plt.show();
if __name__ == "__main__":
main()
Something like plt.swap_on_disk() could cache the stuff on my SSD ;)
So your data isn't that big, and the fact that you're having trouble plotting it points to issues with the tools. Matplotlib has lots of options and the output is fine, but it's a huge memory hog and it fundamentally assumes your data is small. But there are other options out there.
So as an example, I generated a 20M data-point file 'bigdata.bin' using the following:
#!/usr/bin/env python
import numpy
import scipy.io.numpyio
npts=20000000
filename='bigdata.bin'
def main():
data = (numpy.random.uniform(0,1,(npts,3))).astype(numpy.float32)
data[:,2] = 0.1*data[:,2]+numpy.exp(-((data[:,1]-0.5)**2.)/(0.25**2))
fd = open(filename,'wb')
scipy.io.numpyio.fwrite(fd,data.size,data)
fd.close()
if __name__ == "__main__":
main()
This generates a file of size ~229MB, which isn't all that big; but you've expressed that you'd like to go to even larger files, so you'll hit memory limits eventually.
Let's concentrate on non-interactive plots first. The first thing to realize is that vector plots with glyphs at each point are going to be a disaster -- for each of the 20 M points, most of which are going to overlap anyway, trying to render little crosses or circles or something is going to be a diaster, generating huge files and taking tonnes of time. This, I think is what is sinking matplotlib by default.
Gnuplot has no trouble dealing with this:
gnuplot> set term png
gnuplot> set output 'foo.png'
gnuplot> plot 'bigdata.bin' binary format="%3float32" using 2:3 with dots
And even Matplotlib can be made to behave with some caution (choosing a raster back end, and using pixels to mark points):
#!/usr/bin/env python
import numpy
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
datatype=[('index',numpy.float32), ('floati',numpy.float32),
('floatq',numpy.float32)]
filename='bigdata.bin'
def main():
data = numpy.memmap(filename, datatype, 'r')
plt.plot(data['floati'],data['floatq'],'r,')
plt.grid(True)
plt.title("Signal-Diagram")
plt.xlabel("Sample")
plt.ylabel("In-Phase")
plt.savefig('foo2.png')
if __name__ == "__main__":
main()
Now, if you want interactive, you're going to have to bin the data to plot, and zoom in on the fly. I don't know of any python tools that will help you do this offhand.
On the other hand, plotting-big-data is a pretty common task, and there are tools that are up for the job. Paraview is my personal favourite, and VisIt is another one. They both are mainly for 3D data, but Paraview in particular does 2d as well, and is very interactive (and even has a Python scripting interface). The only trick will be to write the data into a file format that Paraview can easily read.
A survey of open source interactive plotting software with a 10 million point scatter plot benchmark on Ubuntu
Inspired by the use case described at: https://stats.stackexchange.com/questions/376361/how-to-find-the-sample-points-that-have-statistically-meaningful-large-outlier-r I have benchmarked a few plotting programs with the exact same input files.
Basically, I wanted to:
do an XY scatter plot of multidimensional data, hopefully with Z as the point color
interactively select some interesting looking points from the plot with my mouse
view all dimensions of the selected points (including at least X, Y and Z) to try and understand why they are outliers in the XY scatter
That problem can be represented by the following simplified test data:
i=0;
while [ "$i" -lt 10000000 ]; do
echo "$i,$((2 * i)),$((4 * i))"; i=$((i + 1));
done > 10m1.csv
echo 5000000,20000000,-1 >> 10m1.csv
The first few lines of 10m1.csv look like this:
10m1.csv
0,0,0
1,2,4
2,4,8
3,6,12
4,8,16
and the very last one, the 10 million-first, is the outlier, and looks like:
5000000,20000000,-1
so we basically have:
a line with inclination 2 and 10 million points on it
plus a single outlier point outside of the line, on the top center of the plot
something like:
Y
^
|
|
| + +
|
| +
|
| +
|
| +
|
| +
|
| +
|
| +
|
| +
|
+-------------------> X
And the goal of this benchmark to find the point (5000000,20000000) on the graphical plot, and then determine the value of the third column from it, which is -1 in our test.
When I first wrote this answer, I had used 10.csv generated with:
i=0;
while [ "$i" -lt 10000000 ]; do
echo "$i,$((2 * i)),$((4 * i))"; i=$((i + 1));
done > 10m.csv
without the outlier. While this tests performance, it does not test selection capabilities, so the goal is to migrate each test to 10m1.csv when I find motivation to do it.
I also made a 10 point + outlier example in case I wanted to evaluate usability for some tool that could not handle the 10m point count:
i=0;
while [ "$i" -lt 10 ]; do
echo "$i,$((2 * i)),$((4 * i))"; i=$((i + 1));
done > 11.csv
echo 5,20,-1 >> 11.csv
To have extra fun, I also prepared an even larger 1 billion point dataset in case any of the programs could handle the 10 million points! CSV files were getting a bit wonky, so I moved to HDF5:
#!/usr/bin/env python3
import h5py
import numpy
size = 1000000000
with h5py.File('1b.hdf5', 'w') as f:
x = numpy.arange(size + 1)
x[size] = size / 2
f.create_dataset('x', data=x, dtype='int64')
y = numpy.arange(size + 1) * 2
y[size] = 3 * size / 2
f.create_dataset('y', data=y, dtype='int64')
z = numpy.arange(size + 1) * 4
z[size] = -1
f.create_dataset('z', data=z, dtype='int64')
This produces a ~23GiB file analogous to 10m1.csv containing:
1 billion points in a straight line much like 10m.csv
one outlier point at the center top of the graph
The tests were carried out in Ubuntu 18.10 unless mentioned otherwise in the a subsection, in a ThinkPad P51 laptop with Intel Core i7-7820HQ CPU (4 cores / 8 threads), 2x Samsung M471A2K43BB1-CRC RAM (2x 16GiB), NVIDIA Quadro M1200 4GB GDDR5 GPU.
Summary of results
This is what I observed, considering my very specific test use case and that I'm a first time user of many of the reviewed software:
Does it handle 10 million points:
Vaex Yes, tested up to 1 Billion!
VisIt Yes, but not 100m
Paraview No
Mayavi Yes
gnuplot Barely on non-interactive mode.
matplotlib No
Bokeh No, up to 1m
PyViz ?
seaborn ?
Does it have a lot of features:
Vaex Yes.
VisIt Yes, 2D and 3D, focus on interactive.
Paraview Same as above, a bit less 2D features maybe.
Mayavi 3D only, good interactive and scripting support, but more limited features.
gnuplot Lots of features, but limited in interactive mode.
matplotlib Same as above.
Bokeh Yes, easy to script.
PyViz ?
seaborn ?
Does the GUI feel good (not considering good performance):
Vaex Yes, Jupyter widget
VisIt No
Paraview Very
Mayavi OK
gnuplot OK
matplotlib OK
Bokeh Very, Jupyter widget
PyViz ?
seaborn ?
Vaex 2.0.2
https://github.com/vaexio/vaex
Install and get a hello world working as shown at: How to do interactive 2D scatter plot zoom / point selection in Vaex?
I tested vaex with up to 1 billion points and it worked, it is awesome!
It is "Python-scripted-first" which is great for reproducibility, and allows me to easily interface with other Python things.
The Jupyter setup has a few moving parts, but once I got it running with virtualenv, it was amazing.
To load our CSV run in Jupyter:
import vaex
df = vaex.from_csv('10m.csv', names=['x', 'y', 'z'],)
df.plot_widget(df.x, df.y, backend='bqplot')
and we can see instantly:
Now, we can zoom, pan and select points with the mouse, and updates are really fast, all in under 10 seconds. Here I have zoomed in to see some individual points and have selected a few of them (faint lighter rectangle on image):
After the selection is made with the mouse, this has the exact same effect as using the df.select() method. So we can extract the selected points by running in Jupyter:
df.to_pandas_df(selection=True)
which outputs data with format:
x y z index
0 4525460 9050920 18101840 4525460
1 4525461 9050922 18101844 4525461
2 4525462 9050924 18101848 4525462
3 4525463 9050926 18101852 4525463
4 4525464 9050928 18101856 4525464
5 4525465 9050930 18101860 4525465
6 4525466 9050932 18101864 4525466
Since 10M points worked fine, I decided to try 1B points... and it also worked fine!
import vaex
df = vaex.open('1b.hdf5')
df.plot_widget(df.x, df.y, backend='bqplot')
To observe the outlier, which was invisible on the original plot, we can follow How change the point style in a vaex interactive Jupyter bqplot plot_widget to make individual points larger and visible? and use:
df.plot_widget(df.x, df.y, f='log', shape=128, backend='bqplot')
which produces:
and after selecting the point:
we obtain the outlier's full data:
x y z
0 500000000 1500000000 -1
Here is a demo by the creators with a more interesting dataset and more features: https://www.youtube.com/watch?v=2Tt0i823-ec&t=770
Tested in Ubuntu 19.04.
VisIt 2.13.3
Website: https://wci.llnl.gov/simulation/computer-codes/visit
License: BSD
Developed by Lawrence Livermore National Laboratory, which is a National Nuclear Security Administration laboratory, so you can imagine that 10m points will be nothing for it if I could get it working. (The book The Supermen: The Story of Seymour Cray by Charles J. Murray (1997) does a good job a showing how computational power hungry labs such as these were when building the first H bombs, because you can't just run experiments at will with nukes, and even if you do, you can't really measure what you would like because it blows up too fast and too hot: a computer model is a must. And they decided that a bunch of physicist's wives with calculators wasn't going to cut it like as for the earlier Los Alamos fission bomb. When Israel bought one of their computers, everyone immediately assumed it was to make nukes.)
Installation: there is no Debian package, just download Linux binaries from website. Runs without installing. See also: https://askubuntu.com/questions/966901/installing-visit
Based on VTK which is the backend library that many of the high perfomance graphing software use. Written in C.
After 3 hours of playing with the UI, I did get it working, and it did solve my use case as detailed at: https://stats.stackexchange.com/questions/376361/how-to-find-the-sample-points-that-have-statistically-meaningful-large-outlier-r
Here is how it looks like on the test data of this post:
and a zoom with some picks:
and here is the picks window:
Performance wise, VisIt was very good: every graphic operation either took only a small amount of time or was immediate. When I had to wait, it shows a "processing" message with the percentage of work left, and the GUI didn't freeze.
Since 10m points worked so well, I also tried 100m points (a 2.7G CSV file) but it crashed / went into a weird state unfortunately, I watched it in htop as the 4 VisIt threads took up all of my 16GiB RAM and died likely due to a failed malloc.
The initial getting started was a bit painful:
many of the defaults feel atrocious if you are not a nuclear bomb engineer? E.g.:
default point size 1px (gets confused with dust on my monitor)
axes scale from 0.0 to 1.0: How to show the actual axes number values on the Visit plotting program instead of fractions from 0.0 to 1.0?
multi-window setup, nasty multi popups when you Pick data points
shows your username and plot date (remove with "Controls" > "Annotation" > "User information")
automatic positioning defaults are bad: legend conflicts with axes, could not find title automation so had to add a label and reposition everything by hand
there are just a lot of features, so it can be hard to find what you want
the manual was very helpful, but it is a 386 page PDF mammoth ominously dated "October 2005 Version 1.5". I wonder if they used this to develop Trinity! and it is a nice Sphinx HTML created just after I originally answered this question
no Ubuntu package. But the prebuilt binaries did just work.
I attribute these problems to:
it has been around for such a long time and uses some outdated GUI ideas
you can't just click on the plot elements to change them (e.g. axes, title, etc.), and there are a lot of features, so it is a bit hard to find the one your are looking for
I also love it how a bit of LLNL infrastructure leaks into that repo. See for example docs/OfficeHours.txt and other files in that directory! I'm sorry for Brad who is the "Monday Morning guy"! Oh, and the password for the answering machine is "Kill Ed", don't forget that.
Paraview 5.9.0
Website: https://www.paraview.org/
License: BSD
Tested on: Ubuntu 20.10.
Installation:
sudo apt install paraview
or get the latest by download prebuilts from the website. This is what I did for this review, since the apt one was only at 5.7.0. I downloaded ParaView-5.9.0-MPI-Linux-Python3.8-64bit.tar.gz.
Developed by Kitware and Los Alamos National Laboratory, and later Sandia National Laboratories (so the other two NNSA labs), so once again we expect that it will easily handle the data. Also VTK based and written in C++, which was further promising.
However I was disappointed: for some reason, 10m points made the GUI very slow and unresponsive, making it unusable. Whenever I clicked something, like to hide the lines, it took several dozen seconds. I think that at some point it just glitched out and stopped responding at all.
I'm fine with a controlled well advertised "I'm working now, wait a bit" moment, but the GUI freezing while that happens? Not acceptable.
htop showed that Paraview was using 8 threads and 3GB RAM, so neither CPU nor memory was maxed out.
GUI-wise, Paraview is very nice and modern, way better than VisIt when it is not stuttering.
Since 10m1.csv killed it, I tested with 11.csv to see if I would have been able to solve my problem except for performance, and the answer is yes:
paraview 11.csv
select CSV reader from the popup
properties properties Apply on the left
right click on the CSV on Pipeline Browser
Add filter > Alphabetical > Plot data. Why is plotting a filter? Not very intuitive for first time users, related: paraview: plot data from csv file I'm sure it is one of those things that make sense once you understand further generalizations of what filters can do, but still.
properties > Apply
unselect "Use index for x axis"
X Array Name: Field 0
Series Parameters remove Field 0 and Field 2
Select Field 1 and:
Line style: None
Marker style: cross
Marker size: increase or decrease as needed
"Rectangle Selection (s)" icon above the plot
Select outlier (point is highlighted)
Add another filter to the plot filter: "Extract Selection"
Apply
And finally!!! I get a table containing only the selected outlier, and showing the value of "Field 2" as -1:
So yes, not exactly a walk in the park, but I managed eventually.
Another downside is that Paraview felt lacking features compared to VisIt, e.g.:
I could not find how to set the color of my scatter based on a third column: How to color scatter plot points by the value of a third column in Paraview like gnuplot palette?
Mayavi 4.6.2
Website: https://github.com/enthought/mayavi
Developped by: Enthought
Install:
sudo apt-get install libvtk6-dev
python3 -m pip install -u mayavi PyQt5
The VTK Python one.
Mayavi seems to be very focused on 3D, I could not find how to do 2D plots in it, so it does not cut it for my use case unfortunately.
Just to check performance however, I adapted the example from: https://docs.enthought.com/mayavi/mayavi/auto/example_scatter_plot.html for 10 million points, and it run just fine without lagging:
import numpy as np
from tvtk.api import tvtk
from mayavi.scripts import mayavi2
n = 10000000
pd = tvtk.PolyData()
pd.points = np.linspace((1,1,1),(n,n,n),n)
pd.verts = np.arange(n).reshape((-1, 1))
pd.point_data.scalars = np.arange(n)
#mayavi2.standalone
def main():
from mayavi.sources.vtk_data_source import VTKDataSource
from mayavi.modules.outline import Outline
from mayavi.modules.surface import Surface
mayavi.new_scene()
d = VTKDataSource()
d.data = pd
mayavi.add_source(d)
mayavi.add_module(Outline())
s = Surface()
mayavi.add_module(s)
s.actor.property.trait_set(representation='p', point_size=1)
main()
Output:
I couldn't however zoom in enough to see indivitual points, the near 3D plane was too far. Maybe there is a way?
One cool thing about Mayavi is that devs put a lot of effort into allowing you to fire and setup the GUI from a Python script nicely, much like Matplotlib and gnuplot. It seems that this is also possible in Paraview, but the docs are not as good at least.
Generally it feels not a featurefull as VisIt / Paraview. For example, I couldn't directly load a CSV from the GUI: How to load a CSV file from the Mayavi GUI?
Gnuplot 5.2.2
Website: http://www.gnuplot.info/
gnuplot is really convenient when I need to go quick and dirty, and it is always the first thing that I try.
Installation:
sudo apt-get install gnuplot
For non-interactive use, it can handle 10m points reasonably well:
#!/usr/bin/env gnuplot
set terminal png size 1024,1024
set output "gnuplot.png"
set key off
set datafile separator ","
plot "10m1.csv" using 1:2:3:3 with labels point
which finished in 7 seconds:
But if I try to go interactive with
#!/usr/bin/env gnuplot
set terminal wxt size 1024,1024
set key off
set datafile separator ","
plot "10m.csv" using 1:2:3 palette
and:
gnuplot -persist main.gnuplot
then the initial render and zooms feel too sluggish. I can't even see the rectangle selection line!
Also note that for my use case, I needed to use hypertext labels as in:
plot "10m.csv" using 1:2:3 with labels hypertext
but there was a performance bug with the labels feature including for non-interactive rendering. But I reported it, and Ethan solved it in a day: https://groups.google.com/forum/#!topic/comp.graphics.apps.gnuplot/qpL8aJIi9ZE
I must say however that there is one reasonable workaround for outlier selection: just add labels with the row ID to all points! If there are many points nearby, you won't be able to read the labels. But for the outliers which you care about, you just might! For example, if I add one outlier to our original data:
cp 10m.csv 10m1.csv
printf '2500000,10000000,40000000\n' >> 10m1.csv
and modify the plot command to:
#!/usr/bin/env gnuplot
set terminal png size 1024,1024
set output "gnuplot.png"
set key off
set datafile separator ","
plot "10.csv" using 1:2:3:3 palette with labels
This slowed down the plotting significantly (40 mins after the fix mentioned above!!!), but produces a reasonable output:
so with some data filtering, we would get there, eventually.
Matplotlib 1.5.1, numpy 1.11.1, Python 3.6.7
Website: https://matplotlib.org/
Matplotlib is what I usually try when my gnuplot script starts getting too insane.
numpy.loadtxt alone took about 10 seconds, so I knew this wasn't going to go well:
#!/usr/bin/env python3
import numpy
import matplotlib.pyplot as plt
x, y, z = numpy.loadtxt('10m.csv', delimiter=',', unpack=True)
plt.figure(figsize=(8, 8), dpi=128)
plt.scatter(x, y, c=z)
# Non-interactive.
#plt.savefig('matplotlib.png')
# Interactive.
plt.show()
First the non-interactive attempt gave good output, but took 3 minutes and 55 seconds...
Then the interactive one took a long time on initial render and on zooms. Not usable:
Notice on this screenshot how the zoom selection, which should immediately zoom and disappear stayed on screen for a long time while it waited for zoom to be calculated!
I had to comment out plt.figure(figsize=(8, 8), dpi=128) for the interactive version to work for some reason, or else it blew up with:
RuntimeError: In set_size: Could not set the fontsize
Bokeh 1.3.1
https://github.com/bokeh/bokeh
Ubuntu 19.04 install:
python3 -m pip install bokeh
Then launch Jupyter:
jupyter notebook
Now if I plot 1m points, everything works perfectly, the interface is awesome and fast, including zoom and on hover information:
from bokeh.io import output_notebook, show
from bokeh.models import HoverTool
from bokeh.transform import linear_cmap
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
import numpy as np
N = 1000000
source = ColumnDataSource(data=dict(
x=np.random.random(size=N) * N,
y=np.random.random(size=N) * N,
z=np.random.random(size=N)
))
hover = HoverTool(tooltips=[("z", "#z")])
p = figure()
p.add_tools(hover)
p.circle(
'x',
'y',
source=source,
color=linear_cmap('z', 'Viridis256', 0, 1.0),
size=5
)
show(p)
Initial view:
After a zoom:
If I go up to 10m though it chokes, htop shows that chromium has 8 threads taking up all my memory in uninterruptible IO state.
This asks about referencing the points: How to reference selected bokeh data points
PyViz
https://pyviz.org/
TODO evaluate.
Integrates Bokeh + datashader + other tools.
Video demoing 1B datapoints: https://www.youtube.com/watch?v=k27MJJLJNT4 "PyViz: Dashboards for Visualizing 1 Billion Datapoints in 30 Lines of Python" by "Anaconda, Inc." published on 2018-04-17.
seaborn
https://seaborn.pydata.org/
TODO evaluate.
There's already a QA on how to use seaborn to visualize at least 50 million rows.
A more recent project has strong potential for large data sets: Bokeh, which was created with exactly this in mind.
In fact, only the data that's relevant at the scale of the plot is sent to the display backend. This approach is much faster than the Matplotlib approach.
You can certainly optimize the reading of your file: you could directly read it into a NumPy array, so as to leverage the raw speed of NumPy. You have a few options. If RAM is an issue, you can use memmap, which keeps most of the file on disk (instead of in RAM):
# Each data point is a sequence of three 32-bit floats:
data = np.memmap(filename, mode='r', dtype=[('index', 'float32'), ('floati','float32'), ('floatq', 'float32')])
If RAM is not an issue, you can put the whole array in RAM with fromfile:
data = np.fromfile(filename, dtype=[('index', 'float32'), ('floati','float32'), ('floatq', 'float32')])
Plotting can then be done with Matplotlib's usual plot(*data) function, possibly through the "zoom in" method proposed in another solution.
I would suggest something a bit complex but that should work : build your graph at different resolutions, for different ranges.
Think of Google Earth, for example. If you unzoom at maximum level to cover the whole planet, the resolution is the lowest. When you zoom, the pictures change for more detailed ones, but just on the region you're zooming on.
So basically for your plot (is it 2D ? 3D ? I'll assume it's 2D), I suggest you build one big graph that covers the whole [0, n] range with low resolution, 2 smaller graphs that cover [0, n/2] and [n/2 + 1, n] with twice the resolution of the big one, 4 smaller graphs that cover [0, n/4] ... [3 * n / 4 + 1, n] with twice the resolution of the 2 above, and so on.
Not sure my explanation is really clear. Also, I don't know if this kind of multi-resolution graph is handled by any existing plot program.
I wonder if there's a win to be had by speeding up lookup of your points? (I've been intrigued by R* (r star) trees for a while.)
I wonder if using something like an r* tree in this case could be the way to go. (when zoomed out, higher up nodes in the tree could contain information about the coarser, zoomed out rendering, nodes further towards the leaves contain the individual samples)
maybe even memory map the tree (or whatever structure you end up using) into memory to keep your performance up and your RAM usage low. (you offload the task of memory management to the kernel)
hope that makes sense.. rambling a bit. it's late!

Read .nc (netcdf) files using python

I am trying to learn how to read .nc (netcdf) files using Python in the most easiest/fastest way. I heard that it can be done with 3 lines of code but I really don't know how.
I am running the MITgcm numerical model. I'm trying to get an easy way to visualize the output data in the same way as programs like NCview does but with Python, so I can customise the parameters to read and everything.
I found this:
from matplotlib import pyplot as plt
import pandas as pd
import netCDF4
fp='uwstemp.nc'
nc = netCDF4.Dataset(fp)
plt.imshow(nc['Temp'][1,:,0,:])
plt.show()
It worked roughly like I want it, but I would like to understand word by word what is it doing. I guess 'Temp' is one of my variables, but I don't know how to figure out what all my variables are.
Specially, I don't understand plt.imshow(nc['Temp'][1,:,0,:]) thhat [1,:,0,:] I tried to change it and does not compile; but I don't understand what is it doing and why this numbers.
I use the MITgcm too. Say you have your state.nc output.
First of all make sure you import all you need:
from scipy.io import netcdf
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
The easiest way to read the data is:
file2read = netcdf.NetCDFFile(path+'state.nc','r')
temp = file2read.variables[var] # var can be 'Theta', 'S', 'V', 'U' etc..
data = temp[:]*1
file2read.close()
Then a quick way to plot say layer z at time t is:
plt.contourf(data[t,z,:,:])
To answer your question I commented the code:
from matplotlib import pyplot as plt # import libraries
import pandas as pd # import libraries
import netCDF4 # import libraries
fp='uwstemp.nc' # your file name with the eventual path
nc = netCDF4.Dataset(fp) # reading the nc file and creating Dataset
""" in this dataset each component will be
in the form nt,nz,ny,nx i.e. all the variables will be flipped. """
plt.imshow(nc['Temp'][1,:,0,:])
""" imshow is a 2D plot function
according to what I have said before this will plot the second
iteration of the vertical slize with y = 0, one of the vertical
boundaries of your model. """
plt.show() # this shows the plot
If you want to check the various dimensions of your data so you know what you can plot simply do print(nc['Temp'].shape)
For netCDF4 files (with python 3), use:
import netCDF4
file2read = netCDF4.Dataset(cwd+'\filename.nc','r')
var1 = file2read.variables['var1'] # access a variable in the file
where cwd is my current working directory for getting the file path for the .nc file in order to read it:
import os
cwd = os.getcwd()
I am using Windows, so file directory will be different than for Mac or Linux.
To look at all of the variable keys:
print(file2read.variables.keys())
Which will give an output like this:
dict_keys(['ap', 'ap_bnds', 'b', 'b_bnds', 'bnds', 'ch4', 'lat', 'lat_bnds', 'lev', 'lev_bnds', 'lon', 'lon_bnds', 'time', 'time_bnds'])
Or to look at all of the variables in your netcfd4 file, you can just print 'file2read':
print(file2read)
And the output will include something like this (look at the end specifically):
source_id: GFDL-ESM4
source_type: AOGCM AER CHEM BGC
sub_experiment: none
sub_experiment_id: none
title: NOAA GFDL GFDL-ESM4 model output prepared for CMIP6 update of RCP8.5 based on SSP5
variable_id: ch4
variant_info: N/A
references: see further_info_url attribute
variant_label: r1i1p1f1
dimensions(sizes): lev(49), bnds(2), time(1032), lat(180), lon(288)
variables(dimensions): float64 ap(lev), float64 ap_bnds(lev, bnds), float64 b(lev), float64 b_bnds(lev, bnds), float64 bnds(bnds), float32 ch4(time, lev, lat, lon), float64 lat(lat), float64 lat_bnds(lat, bnds), float64 lev(lev), float64 lev_bnds(lev, bnds), float64 lon(lon), float64 lon_bnds(lon, bnds), float64 time(time), float64 time_bnds(time, bnds)
You can notice that the last part includes the dimensions of the variables along with the type and name of the variables.
Check out this website for more info and examples:
https://www.earthinversion.com/utilities/reading-NetCDF4-data-in-python/
If you are working in Linux, my package nctoolkit (toolkit.readthedocs.io/en/latest/) offers similar functionality to ncview, but within Python. It can autoplot the contents of NetCDF files either within a Jupyter notebook or a web browser. The following should work for the data given:
import nctoolkit as nc
fp='uwstemp.nc'
data = nc.open_data(fp)
data.plot()

How do I plot GFS grib2 data with Python?

I would like to have a chart with the temperatures for the following days on my website, and the Global Forecasting System meets my needs the most. How do I plot the GRIB2 data in matplotlib and create a PNG image from the plot?
I've spend hours of searching on the internet, asking people who do know how to do this (they where not helpfull at all) and I don't know where to start.
GFS data can be found here: ftp://ftp.ncep.noaa.gov/pub/data/nccf/com/gfs/prod/
If possible, I'd like it to be lightweight and without loosing too much server space.
When you think lightweight about data usage and storage, you may consider to use other data forms than GRIB. GRIB-files usually contain worldwide data, which is pretty useless when you only want to plot for a specific domain.
I can strongly recommend to use data from the NOAA-NCEP opendap data server. You can gain data from this server using netCDF4. Unfortunately, this server is known to be unstable at some times which may causes delays in refreshing runs and/or malformed datasets. Although, in 95% of the time, I have acces to all the data I need.
Note: This data server may be slow due to high trafficking after a release of a new run. Acces to the data server can be found here: http://nomads.ncdc.noaa.gov/data.php?name=access#hires_weather_datasets
Plotting data is pretty easy with Matplotlib and Basemap toolkits. Some examples, including usage of GFS-datasets, can be found here: http://matplotlib.org/basemap/users/examples.html
Basically, there are 2 steps:
use wgrib to extract selected variables from grib2 data, and save into NetCDF file. Although there are some API such as pygrib, yet I found it less buggy to use the command line tool directly. some useful links:
install: http://www.cpc.ncep.noaa.gov/products/wesley/wgrib2/compile_questions.html
tricks: http://www.ftp.cpc.ncep.noaa.gov/wd51we/wgrib2/tricks.wgrib2
For example, extract temperature and humidity:
wgrib2 test.grb2 -s | egrep '(:RH:2 m above ground:|:TMP:2 m above ground:)'|wgrib2 -i test.grb2 -netcdf test.nc
use Python libraries to process NetCDF files, example code may look like this:
import warnings
warnings.filterwarnings("ignore")
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
% matplotlib inline
from netCDF4 import Dataset
from mpl_toolkits.basemap import Basemap
from pyproj import Proj
import matplotlib.cm as cm
import datetime
file = "test.nc"
rootgrp = Dataset(file, "r")
x = rootgrp['longitude'][:] # 0-359, step = 1
y = rootgrp['latitude'][:] # -90~90, step =1
tmp = rootgrp['TMP_2maboveground'][:][0] # shape(181,360)
dt = datetime.datetime(1970,1,1) + datetime.timedelta(seconds = rootgrp['time'][0])
fig = plt.figure(dpi=150)
m = Basemap(projection='mill',lat_ts=10,llcrnrlon=x.min(),
urcrnrlon=x.max(),llcrnrlat=y.min(),urcrnrlat=y.max(), resolution='c')
xx, yy = m(*np.meshgrid(x,y))
m.pcolormesh(xx,yy,tmp-273.15,shading='flat',cmap=plt.cm.jet)
m.colorbar(location='right')
m.drawcoastlines()
m.drawparallels(np.arange(-90.,120.,30.), labels=[1,0,0,0], fontsize=10)
m.drawmeridians(np.arange(0.,360.,60.), labels=[0,0,0,1], fontsize=10)
plt.title("{}, GFS, Temperature (C) ".format(dt.strftime('%Y-%m-%d %H:%M UTC')))
plt.show()

Categories