datashader xarray.Image to holoviews Points - python

This is the code:
import datashader as ds
import pandas as pd
from colorcet import fire
from datashader import transfer_functions as tf
from datashader.utils import lnglat_to_meters
import holoviews as hv
import geoviews as gv
from holoviews.operation.datashader import datashade, spread, aggregate
hv.extension('bokeh')
df = pd.read_csv('...')
agg = ds.Canvas().points(df, 'x', 'y', agg=ds.count())
img = tf.shade(agg.where(agg['x']>0), cmap=fire)
url = 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{Z}/{Y}/{X}.jpg'
tile_opts = dict(width=1000,height=600,xaxis=None,yaxis=None,show_grid=False,bgcolor='black')
map_tiles = gv.WMTS(url).opts(style=dict(alpha=1.0), plot=tile_opts)
points = hv.Points(df, ['x', 'y'])
#points = img # <-- Using this does not work
ds_points = spread(datashade(points, width=1000, height=600, cmap=fire), px=2)
map_tiles * ds_points
The above code creates a holoviews Points object based on data from a pandas dataframe and uses spread() and datashade() functions in holoviews to plot the points on a map. However, I want to do some transformations on the data before I plot it on the map. I tried to use the functionality already available in datashader, but I'm unable to figure out how I can convert the xarray.Image object created by datashader into a holoviews Point object which can be plotted on top of the map tiles.
EDIT
I'm not able to format code properly in comments, so I'll just put it here.
I tried doing the following as a degenerate case:
from custom_operation import CustomOperation
points = hv.Points(df, ['x', 'y'])
CustomOperation(rasterize(points))
where CustomOperation is defined as:
from holoviews.operation import Operation
class CustomOperation(Operation):
def _process(self, element, key=None):
return element
This produces the following error:
AttributeError: 'Image' object has no attribute 'get'

The Image object created by Datashader is a regular grid/array of values that aggregates the original points by bin, so it is no longer possible to recover the original points. It would not be meaningful to use a HoloViews Points object on this already 2D-histogrammed data; a Points object expects a set of individual points, not a 2D array. Instead, you can use a HoloViews Image object, which accepts a 2D array like that generated by Datashader. The syntax would be something like hv.Image(img), though I can't test it with the above code because it's not runnable without the CSV file.
Note that if you take this approach, what will happen is that Datashader will render the points into a fixed-size grid, and HoloViews will then overlay that specific grid of values onto the map. Even if you zoom in or pan, you'll still see that same grid; it will never update to show a subset of the data at a higher resolution as your current code will, because the Datashader computations will have all completed and given you a fixed array before you start plotting anything with HoloViews or Bokeh. If you want dynamic zoom and updating, don't use the Datashader API (Canvas, .points, tf.shade, etc.) separately; you'll need to use either the HoloViews operations you are already using (datashade,spread, rasterize, etc.) or define a custom HoloViews operation to encapsulate the processing you want to do (which can include manually calling the Datashader API if you need to) and allow the processing to be dynamically applied each time the user pans or zooms.

Related

how works with Linear ColorMap

I have question to branca.colormap
Below code works:
from branca.colormap import linear
x=linear.YlOrRd_09.scale(1,10)
but I would like to use a different color palette for example gnuplot or gnuplot2
Below code doesn't work:
from branca.colormap import linear
x=linear.gnuplot.scale(1,10)
I have error '_LinearColormaps' object has not attribiute 'gnuplot'. Do You know how use other pallet with linearColormap or where can I find list of available colors names ?
I have one more question, below my code
import folium
import branca.colormap as cm
color_mapa=cm.linear.YlOrRd_09.scale(1,10)
color_mapa=color_mapa.to_step(index=[10,20,30,40,50,60,70,80,90,100])
color_mapa2=color_mapa.to_linear()
m=folium.Map(location=[52,20],zoom_start=7)
color_mapa.add_to(m)
color_mapa.caption='Colors'
color_mapa.add_to(m)
color_mapa2.add_to(m)
color_mapa2.caption='Colors2'
color_mapa2.add_to(m)
m.save('mapy_test.html')
The problem is when I want add lables. I do this by 'to_step()' and define index. But then colors don't change smoothly. So I add 'to_linear()' (color_mapa2), but this change labels (Colors2 on my peacture). Is the way to keep labels and have colors change smoothly ?
You can use the dir() function from the Python standard library to see all the attributes from the linear object :
>>> dir(linear)
['Accent_03',
'Accent_04',
'Accent_05',
'Accent_06',
'Accent_07',
'Accent_08',
'Blues_03',
...]

mplfinance plot not saving when called outside of plot command [duplicate]

This question already has an answer here:
How to save candlestick chart in matplotlib finance
(1 answer)
Closed 1 year ago.
I'm new to matplotlib. I'm struggling to customise elements of my plot within the first .plot call. For example, ylabel works but xlabel doesn't. I was hoping I could separate the savefig command so that I could add/modify elements of the plot between the first .plot call and the savefig call (because all the examples I see online seem to create the plot and then modify elements separately, i.e. the line fplt.xlabel("Blah")
I notice that a lot of plot examples I found online (for line graphs and such) provide all x and y values separately, but I like the plot technique I've used as it automatically uses high, low, etc. to create candles.
So why does this code work:
fplt.plot(
dft,
type="candle",
style='charles',
addplot=extraPlot2,
ylabel=stock,
# xlabel="Blah", <= removed as doesn't work
figratio=(10, 6), volume=True,
savefig=dict(
fname=folder2,
bbox_inches="tight"
)
)
But this code doesn't (even with the hashes added):
fplt.plot(
dft,
type="candle",
style='charles',
addplot=extraPlot2,
ylabel=stock,
# xlabel="Blah", <= removed as doesn't work
figratio=(10, 6), volume=True,
)
# fplt.xlabel("Blah") <= would like to do this if I can get savefig to work
# fplt.xticks(rotation=45) <= i'd also like to do stuff like this
fplt.savefig(folder2)
I've tried making fplt.plot a variable and targeting that but with no luck.
Apologies for any poor terminology, I am very new to this.
EDIT: Imports added below for reference. And I realise why xlabel wasn't working now, as I see I was importing it.
import datetime as dt
from matplotlib.pyplot import bar, xlabel
from numpy import False_, NaN
import pandas as pd
from pandas_datareader import data as pdr
import yfinance as yf
from tkinter import EXCEPTION, Tk
from tkinter.filedialog import askopenfilename
import os
from pandas import ExcelWriter
import mplfinance as fplt
from pathlib import Path
You can import the Matplotlib pyplot module and use the gcf() ("get current figure") function to return a Figure object. It is the Figure object that has the savefig() method. E.g.,
from matplotlib import pyplot as plot
# your code here
fig = plt.gcf() # gcf is "get current figure"
fig.savefig(folder2)
Looking at this mplfinance issue it also looks like you can return the figure object with:
fig, axlist = fplt.plot(..., returnfig=True)
# save figure
fig.savefig(folder2)

How do I test that PyVista successfully plotted a figure?

I am generating 3D meshes in PyVista, and I would like to update my integration test suite to ensure that it successfully shows my plots.
I'm hoping to adapt the methodology described here, to work with PyVista. Unfortunately, I can't find any results for any equivalent function to plt.gcf() in PyVista.
Does anyone know of a workaround?
There's a few ways of doing this. First, pyvista returns a instance of pyvista.plotting.renderer.CameraPosition upon a successful plot. For example:
>>> import pyvista
>>> sphere = pyvista.Sphere()
>>> cpos = sphere.plot(off_screen=True)
>>> print(type(cpos))
<class 'pyvista.plotting.renderer.CameraPosition'>
Since it's necessary to setup a plot and renderer to properly display a plot, getting a return camera position means that your plot was successful.
Alternatively, you can save the screenshot and check that the file exists:
import os
import pyvista
sphere = pyvista.Sphere()
cpos = sphere.plot(off_screen=True, screenshot='tmp.png')
assert os.path.isfile('tmp.png')
You could also check the content of the saved image as well (or potentially file size)

Can I save to disk a plot generated by pandas df.plot? [duplicate]

In ipython Notebook, first create a pandas Series object, then by calling the instance method .hist(), the browser displays the figure.
I am wondering how to save this figure to a file (I mean not by right click and save as, but the commands needed in the script).
Use the Figure.savefig() method, like so:
ax = s.hist() # s is an instance of Series
fig = ax.get_figure()
fig.savefig('/path/to/figure.pdf')
It doesn't have to end in pdf, there are many options. Check out the documentation.
Alternatively, you can use the pyplot interface and just call the savefig as a function to save the most recently created figure:
import matplotlib.pyplot as plt
s.hist()
plt.savefig('path/to/figure.pdf') # saves the current figure
Plots from multiple columns
Added from a comment toto_tico made on 2018-05-11
If you are getting this error AttributeError: 'numpy.ndarray' object has no attribute 'get_figure', then it is likely that you are plotting multiple columns.
In this case, ax will be an array of all the axes.
ax = s.hist(columns=['colA', 'colB'])
# try one of the following
fig = ax[0].get_figure()
fig = ax[0][0].get_figure()
fig.savefig('figure.pdf')
You can use ax.figure.savefig():
import pandas as pd
s = pd.Series([0, 1])
ax = s.plot.hist()
ax.figure.savefig('demo-file.pdf')
This has no practical benefit over ax.get_figure().savefig() as suggested in Philip Cloud's answer, so you can pick the option you find the most aesthetically pleasing. In fact, get_figure() simply returns self.figure:
# Source from snippet linked above
def get_figure(self):
"""Return the `.Figure` instance the artist belongs to."""
return self.figure
You can simply save your (e.g. histogram) plot like this:
df.plot.hist().get_figure().savefig('name')
Just wanted to add that the default resolution is 100dpi, which is fine for screen but won't work if you want to enlarge or print it. You can pass a 'dpi' parameter to get a high-resolution file:
ax = s.hist() # s is an instance of Series
ax.figure.savefig('/path/to/figure.png', dpi=300)

What is the preferred way to import pylab at a function level in Python 2.7?

I have written a relatively simple function in python that can be used to plot the time domain history of a data set as well as the frequency domain response of a data set after a fast fourier transform. In this function I use the command from pylab import * to bring in all the necessary functionality. However, despite successfully creating the plot, I get a warning stating
import * only allowed at the module level.
So if using the command from pylab import * is not the preferred methodology, how do I properly load all the necessary functionality from pylab. The code is attached below. Also, is there a way to close the figure after the function is exited, I have tried plt.close() which is not recognized for subplots?
def Time_Domain_Plot(Directory,Title,X_Label,Y_Label,X_Data,Y_Data):
# Directory: The path length to the directory where the output file is
# to be stored
# Title: The name of the output plot, which should end with .eps or .png
# X_Label: The X axis label
# Y_Label: The Y axis label
# X_Data: X axis data points (usually time at which Yaxis data was acquired
# Y_Data: Y axis data points, usually amplitude
from pylab import *
from matplotlib import rcParams
rcParams.update({'figure.autolayout': True})
Output_Location = Directory.rstrip() + Title.rstrip()
fig,plt = plt.subplots()
matplotlib.rc('xtick',labelsize=18)
matplotlib.rc('ytick',labelsize=18)
plt.set_xlabel(X_Label,fontsize=18)
plt.set_ylabel(Y_Label,fontsize=18)
plt.plot(X_Data,Y_Data,color='red')
fig.savefig(Output_Location)
plt.clear()
From the matplotlib documentation:
pylab is a convenience module that bulk imports matplotlib.pyplot (for plotting) and numpy (for mathematics and working with arrays) in a single name space. Although many examples use pylab, it is no longer recommended.
I would recommend not importing pylab at all, and instead try using
import matplotlib
import matplotlib.pyplot as plt
And then prefixing all of your pyplot functions with plt.
I also noticed that you assign the second return value from plt.subplots() to plt. You should rename that variable to something like fft_plot (for fast fourier transform) to avoid naming conflicts with pyplot.
With regards to your other question (about fig, save fig()) you're going to need to drop that first fig because it's not necessary, and you'll call savefig() with plt.savefig() because it is a function in the pyplot module. So that line will look like
plt.savefig(Output_Location)
Try something like this:
def Time_Domain_Plot(Directory,Title,X_Label,Y_Label,X_Data,Y_Data):
# Directory: The path length to the directory where the output file is
# to be stored
# Title: The name of the output plot, which should end with .eps or .png
# X_Label: The X axis label
# Y_Label: The Y axis label
# X_Data: X axis data points (usually time at which Yaxis data was acquired
# Y_Data: Y axis data points, usually amplitude
import matplotlib
from matplotlib import rcParams, pyplot as plt
rcParams.update({'figure.autolayout': True})
Output_Location = Directory.rstrip() + Title.rstrip()
fig,fft_plot = plt.subplots()
matplotlib.rc('xtick',labelsize=18)
matplotlib.rc('ytick',labelsize=18)
fft_plot.set_xlabel(X_Label,fontsize=18)
fft_plot.set_ylabel(Y_Label,fontsize=18)
plt.plot(X_Data,Y_Data,color='red')
plt.savefig(Output_Location)
plt.close()

Categories

Resources