Giter VIP home page Giter VIP logo

pylandstats's Introduction

PyPI version fury.io Conda Downloads Documentation Status tests pre-commit.ci status codecov GitHub license

PyLandStats

Open-source library to compute landscape metrics in the Python ecosystem (NumPy, pandas, matplotlib...)

Citation: Bosch M. 2019. "PyLandStats: An open-source Pythonic library to compute landscape metrics". PLOS ONE, 14(12), 1-19. doi.org/10.1371/journal.pone.0225734

Features

  • Read GeoTiff files of land use/cover:

    import pylandstats as pls
    
    ls = pls.Landscape("../data/processed/veveyse-AS18_4.tif")
    ls.plot_landscape(legend=True)

    landscape-veveyse

  • Compute pandas data frames of landscape metrics at the patch, class and landscape level:

    class_metrics_df = ls.compute_class_metrics_df(
        metrics=["proportion_of_landscape", "edge_density", "euclidean_nearest_neighbor_mn"]
    )
    class_metrics_df
    class_val proportion_of_landscape edge_density euclidean_nearest_neighbor_mn
    1 7.749572 19.102211 309.244705
    2 56.271868 50.599270 229.079970
    3 33.946252 38.167200 253.299859
    4 2.032308 3.722177 552.835154
  • Analyze the spatio-temporal evolution of landscapes:

    import matplotlib.pyplot as plt
    
    input_filepaths = [
        "../data/processed/veveyse-AS97R_4.tif",
        "../data/processed/veveyse-AS09R_4.tif",
        "../data/processed/veveyse-AS18_4.tif",
    ]
    
    sta = pls.SpatioTemporalAnalysis(input_filepaths, dates=["1992", "2004", "2012"])
    sta.plot_metric("contagion")

    spatiotemporal-analysis

  • Zonal analysis of landscapes

See the documentation and the pylandstats-notebooks repository for a more complete overview.

Installation

The easiest way to install PyLandStats is with conda:

$ conda install -c conda-forge pylandstats

which will install PyLandStats and all of its dependencies. Alternatively, you can install PyLandStats using pip:

$ pip install pylandstats

Nevertheless, note that in order to define zones by vector geometries in ZonalAnalysis, or in order to use the the BufferAnalysis and SpatioTemporalBufferAnalysis classes, PyLandStats requires geopandas, which cannot be installed with pip. If you already have the dependencies for geopandas installed in your system, you might then install PyLandStats with the geo extras as in:

$ pip install pylandstats[geo]

and you will be able to use the aforementioned features (without having to use conda).

Development install

To install a development version of PyLandStats, you can first use conda to create an environment with all the dependencies and activate it as in:

$ conda create -n pylandstats -c conda-forge geopandas matplotlib-base rasterio scipy openblas
$ conda activate pylandstats

and then clone the repository and use pip to install it in development mode

$ git clone https://github.com/martibosch/pylandstats.git
$ cd pylandstats/
$ pip install -e .

Acknowledgments

  • The computation of the adjacency matrix in transonic has been implemented by Pierre Augier (paugier)
  • Several information theory-based metrics from Nowosad and Stepinski [1] were added by achennu
  • With the support of the École Polytechnique Fédérale de Lausanne (EPFL)
  • The Corine Land Cover datasets used for the test datasets were produced with funding by the European Union

References

  1. Nowosad, J., & Stepinski, T. F. (2019). Information theory as a consistent framework for quantification and classification of landscape patterns. Landscape Ecology, 34(9), 2091-2101.

pylandstats's People

Contributors

achennu avatar dependabot[bot] avatar martibosch avatar paugier avatar pre-commit-ci[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

pylandstats's Issues

loop of ufunc does not support argument 0 of type float which has no callable log method

PyLandStats version: 2.4.2
Python version: 3.12.3
Operating System: MacOS
Description
I encountered an issue while using the conditional_entropy function in the pylandstats package. The error message suggests there is a problem with the compute_entropy function when it attempts to handle the log method on a float. I was expecting the function to compute the conditional entropy without any errors.

What I Did
I ran the code:
This resulted in the following traceback:

Traceback (most recent call last):
File "path/to/your/script.py", line 153, in
cauculate(tif_file)
File "path/to/your/script.py", line 105, in cauculate
CONDENT = lscape.conditional_entropy()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "path/to/pylandstats/landscape.py", line 2638, in conditional_entropy
return self.joint_entropy(base=base) - self.entropy(base=base)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "path/to/pylandstats/landscape.py", line 2611, in joint_entropy
return compute_entropy(adjacencies, base=base)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "path/to/pylandstats/landscape.py", line 116, in compute_entropy
entropy = -np.sum(pcounts * np.log(pcounts))
^^^^^^^^^^^^^^^
TypeError: loop of ufunc does not support argument 0 of type float which has no callable log method
Proposed Solution
To fix this issue, I suggest modifying the compute_entropy function to ensure that counts is converted to a NumPy array with a float data type before performing any operations. Adding the following line at the beginning of the function should resolve the problem:

python
Copy code
def compute_entropy(counts, base=None):
counts = np.asarray(counts, dtype=float)
pcounts = (counts / counts.sum())[counts > 0]
print("Proportional counts:", pcounts)
entropy = -np.sum(pcounts * np.log(pcounts))
if base:
entropy /= np.log(base)
return entropy
This change ensures that the counts variable is correctly handled as a NumPy array of floats, preventing the TypeError related to the log method.

Thank you for your attention to this matter.

Best regards

Problem installing on Windows (Anaconda)

  • PyLandStats version:
  • Python version:
  • Operating System:

Description

I have not been able to installed it.

I used anaconda on Windows I try to connect this with Earth Engine
Capture

What I Did

Capture

PyLandStats does not install on M1 MacBook using Anaconda

  • PyLandStats version: 2.4.2
  • Python version: 3.10.5
  • Operating System: MacOS 12.4 Monterey (Apple Silicon M1)

Description

Describe what you were trying to get done.
I was attempting to install pylandstats, but could not via conda.

Tell us what happened, what went wrong, and what you expected to happen.
It failed to install with fixed solve and flexible solve. It seems to not be listed in the architecture osx-arm64 and noarch channels (error #1).

What I Did

The only way I could get it to installl with via pip. However, it would give a message indicating that landscape.py failed to compile for transonic-pythian (error #2).

Paste the command(s) you ran and the output.
and use the search bar at the top of the page.

<!--Error #1-->
(model_studies) billyhales@ ~ % conda install -c conda-forge pylandstats
Collecting package metadata (current_repodata.json): done
Solving environment: failed with initial frozen solve. Retrying with flexible solve.
Collecting package metadata (repodata.json): done
Solving environment: failed with initial frozen solve. Retrying with flexible solve.

PackagesNotFoundError: The following packages are not available from current channels:

  - pylandstats

Current channels:

  - https://conda.anaconda.org/conda-forge/osx-arm64
  - https://conda.anaconda.org/conda-forge/noarch

To search for alternate channels that may provide the conda package you're
looking for, navigate to

    https://anaconda.org

<!--Error #2-->
>>> import pylandstats
Module /Users/billyhales/miniforge3/envs/model_studies/lib/python3.10/site-packages/pylandstats/landscape.py has not been compiled for Transonic-Pythran

If there was a crash, please include the traceback here.

[feature thought] Xarray(Dask) as backend for performance increase

Description

Describe your feature request:

First, thank you very much for the pythonic package, convenient and powerful.

I'm already impressed by the performance comparison in the pylandstats-notebook. Calculating landscape metrics is often computationally expensive, especially when the image is large or class_id increases. When testing my about 60mb-each TIF files GLC10, I'm wondering if pylandstats could be more performant.

Recently, the Dask team posted a use case to accelerate raster analysis using Xarray and Dask. Possibly it is relevant to Pylandstats and worth considerating. Additional benefits to speed may be the temporal-spatial analysis, which consumes a list of inputs. Is this path a potential direction for the package?

Additional notes:
The following is related to the topic but possibly should be in annother issue, so I apologize in advance if not proper. For the same performance reason, I tried running the analysis on Colab to overcome the local machine limits. However, the installs failed. Sor far I've tested:

!pip install pylandstats
# Try installing 1.1.1, but get: ERROR: Command errored out with exit status 1: /usr/bin/python3 /usr/local/lib/python3.6/dist-packages/pip/_vendor/pep517/_in_process.py get_requires_for_build_wheel /tmp/tmp539jdlhk Check the logs for full command output.

!pip install pylandstats==2.0.0b1
# Trying installing 2.0.0ba, but get: 

#Installing build dependencies ... done
#Getting requirements to build wheel ... error
#ERROR: Command errored out with exit status 1: /usr/bin/python3 #/usr/local/lib/python3.6/dist-packages/pip/_vendor/pep517/_in_process.py #get_requires_for_build_wheel /tmp/tmppayw9hpt Check the logs for full command output.

# using git clone and python setup.py install get the same error message. 

I couldn't figure out a way to install pylandstats although all its dependencies can be installed well. I'm wondering if you could provide some insights? Thank you very much.

Error in `landscape.compute_total_adjacency_df()`

  • PyLandStats version: 2.4.2
  • Python version: 3.8.16
  • Operating System: macOS 13.3.1

Description

When running the compute_landscape_metrics_df() function errors for entropy (and other landscape-level metrics) is thrown out: "entropy cannot be computed at the landscape level"

What I Did

plsobj = pls.Landscape(data.astype(int), res=(1, 1), neighborhood_rule='8')

kws = {'total_area': {'hectares': False},
           'edge_density': {'hectares': False},
           'perimeter_area_ratio': {'hectares': False},
           'patch_density': {'hectares': False}}
df = plsobj.compute_landscape_metrics_df(metrics_kws=kws).T.squeeze()

this would throw the error for ANY data and it works if I chose not to calculate any of the diversity measures (like entropy, contagion, etc).

I figured that in the landscape.py library the function compute_total_adjacency_df() was returning a data frame of objects instead of integers (as it should because this is an array of adjacency counts), and then when entropy() uses this function to calculate counts per class, which then is passed to compute_entropy(), the calculation fails because the values in the list aren't numeric, and hence the statement

entropy = -np.sum(pcounts * np.log(pcounts))

throws an error at the numpy log command.

I fixed this problem by forcing the return of compute_total_adcacency_df() to be a data frame of integers:

def compute_total_adjacency_df(self):
        """
        Compute the total adjacency (vertical and horizontal) data frame.

        Returns
        -------
        adjacency_df: pandas.DataFrame
            Adjacency data frame with total adjacencies (vertical and horizontal).
        """
        # first `groupby` and `sum` to sum vertical and horizontal adjacencies
        # (first-level index), then `loc` to overlook the nodata row/column
        df = self._adjacency_df.groupby(level=1).sum().loc[self.classes, self.classes]
        return df.astype('int')

You should consider revising this simple error for the next update

Error with landscape.Landscape._adjacency_df

  • PyLandStats version: 2.3.0
  • Python version: 3.8.10
  • Operating System: Windows

Description

I tried to compute class and landscape metrics on a ZonalAnalysis object.

What happened: Contagion (and other metrics that rely on the adjacency matrix) produced a key error when self._adjacency_df.groupby(level=1, sort=False).sum()[i] is called.

What went wrong: self._adjacency_df.groupby(level=1, sort=False) does not produce the expected output.

Output Adjacency DF
Output Adjacency DF GroupBy Sum

What I expected to happen: Somehow the adjacency_df is malformatted, but I could not figure out what is wrong with it. I managed to "repair" it by converting it to a dict and back with adjacency_df = pd.DataFrame.from_dict(adjacency_df.to_dict()).

Output Adjacency DF Repaired
Output Adjacency DF Repaired GroupBy Sum

What I Did

import numpy as np
import pylandstats as pls

masks, values = GEMEINDEN_raster.masks() # custom function

ls = pls.Landscape(LANDCOVER, nodata=0)
za = pls.ZonalAnalysis(ls, masks_arr=masks, attribute_values=values)

ls_metric_df = za.compute_landscape_metrics_df(metrics=['contagion'])
KeyError: 1
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
~\AppData\Local\Continuum\anaconda3\envs\woelt_basic\lib\site-packages\pandas\core\indexes\base.py in get_loc(self, key, method, tolerance)
   3360             try:
-> 3361                 return self._engine.get_loc(casted_key)
   3362             except KeyError as err:

~\AppData\Local\Continuum\anaconda3\envs\woelt_basic\lib\site-packages\pandas\_libs\index.pyx in pandas._libs.index.IndexEngine.get_loc()

~\AppData\Local\Continuum\anaconda3\envs\woelt_basic\lib\site-packages\pandas\_libs\index.pyx in pandas._libs.index.IndexEngine.get_loc()

pandas\_libs\hashtable_class_helper.pxi in pandas._libs.hashtable.Int64HashTable.get_item()

pandas\_libs\hashtable_class_helper.pxi in pandas._libs.hashtable.Int64HashTable.get_item()

KeyError: 1

The above exception was the direct cause of the following exception:

KeyError                                  Traceback (most recent call last)
C:\Users\FLORIA~1.FRO\AppData\Local\Temp/ipykernel_7688/415773056.py in <module>
     16 za = pls.ZonalAnalysis(ls, masks_arr=masks, attribute_values=values)
     17 
---> 18 ls_metric_df = za.compute_landscape_metrics_df(metrics=['contagion'])

~\AppData\Local\Continuum\anaconda3\envs\woelt_basic\lib\site-packages\pylandstats\multilandscape.py in compute_landscape_metrics_df(self, metrics, metrics_kws)
    226                                               self.landscapes):
    227             landscape_metrics_df.loc[attribute_value, columns] = \
--> 228                 landscape.compute_landscape_metrics_df(
    229                     metrics,
    230                     metrics_kws=metrics_kws).iloc[0]

~\AppData\Local\Continuum\anaconda3\envs\woelt_basic\lib\site-packages\pylandstats\landscape.py in compute_landscape_metrics_df(self, metrics, metrics_kws)
   2674                     metric_kws = {}
   2675 
-> 2676                 metrics_dict[metric] = getattr(self, metric)(**metric_kws)
   2677 
   2678         except AttributeError:

~\AppData\Local\Continuum\anaconda3\envs\woelt_basic\lib\site-packages\pylandstats\landscape.py in contagion(self, percent)
   2436         for i in self.classes:
   2437             p_i = np.sum(self._get_patch_area_ser(i)) / self.landscape_area
-> 2438             g_i = self._adjacency_df.groupby(level=1, sort=False).sum()[i]
   2439             # print(g_i)
   2440             g_i_sum = np.sum(g_i)

~\AppData\Local\Continuum\anaconda3\envs\woelt_basic\lib\site-packages\pandas\core\frame.py in __getitem__(self, key)
   3453             if self.columns.nlevels > 1:
   3454                 return self._getitem_multilevel(key)
-> 3455             indexer = self.columns.get_loc(key)
   3456             if is_integer(indexer):
   3457                 indexer = [indexer]

~\AppData\Local\Continuum\anaconda3\envs\woelt_basic\lib\site-packages\pandas\core\indexes\base.py in get_loc(self, key, method, tolerance)
   3361                 return self._engine.get_loc(casted_key)
   3362             except KeyError as err:
-> 3363                 raise KeyError(key) from err
   3364 
   3365         if is_scalar(key) and isna(key) and not self.hasnans:

KeyError: 1

4 cell neighborhood rule

4 cell neighborhood rule

You did really great work on the pylandstats toolbox. Thank you for sharing it!

I have noticed that e.g. the number_of_patches function uses a 8 cell neighborhood rule, and probably the other functions do so too. In Fragstats you can chose between 4- and 8- cell rule.
Did you implement the 4 cell neighborhood aswell?

Best regards

Zonal statistics, multiple regions, single class.

  • PyLandStats version: 2.2.0
  • Python version: 3.8.6
  • Operating System: Windows 10

Description

Run zonal statistics on a region with two zones. It works for many of my cases doing the exact same thing, but when a zone contains only one class in the raster it throws this error. More than happy to send you the files, as well as files generated in the same way with multiple rasters in the class.

What I Did

fName = r"C:\Users\evanmuis.stu\Sync\Masters\Data\outputs\InkaneepPark\rasters\InkaneepPark_PACE-2015-HMM.tif"
zones = r"C:\Users\evanmuis.stu\Sync\Masters\Data\outputs\InkaneepPark\InkaneepPark_PACE_dissolved.shp"

za = pls.ZonalAnalysis(fName, masks = zones, masks_index_col = 'ppa_gpe')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-36-a7dc8dd8d653> in <module>
      2 zones = r"C:\Users\evanmuis.stu\Sync\Masters\Data\outputs\InkaneepPark\InkaneepPark_PACE_dissolved.shp"
      3 
----> 4 za = pls.ZonalAnalysis(fName, masks = zones, masks_index_col = 'ppa_gpe')

~\Miniconda3\envs\frag\lib\site-packages\pylandstats\zonal.py in __init__(self, landscape, masks_arr, landscape_crs, landscape_transform, attribute_name, attribute_values, masks, masks_index_col, **kwargs)
    142                     # we first rasterize the geometries using the values of
    143                     # each geometry's index key in the raster
--> 144                     zone_arr = features.rasterize(
    145                         shapes=((geom, val)
    146                                 for geom, val in zip(masks_gser, masks.index)),

~\Miniconda3\envs\frag\lib\site-packages\rasterio\env.py in wrapper(*args, **kwds)
    383         else:
    384             with Env.from_defaults():
--> 385                 return f(*args, **kwds)
    386     return wrapper
    387 

~\Miniconda3\envs\frag\lib\site-packages\rasterio\features.py in rasterize(shapes, out_shape, fill, out, transform, all_touched, merge_alg, default_value, dtype)
    264     if fill != 0:
    265         fill_array = np.array([fill])
--> 266         if not validate_dtype(fill_array, valid_dtypes):
    267             raise ValueError(format_invalid_dtype('fill'))
    268 

~\Miniconda3\envs\frag\lib\site-packages\rasterio\dtypes.py in validate_dtype(values, valid_dtypes)
    185 
    186     return (values.dtype.name in valid_dtypes or
--> 187             get_minimum_dtype(values) in valid_dtypes)

~\Miniconda3\envs\frag\lib\site-packages\rasterio\dtypes.py in get_minimum_dtype(values)
    125 
    126     else:
--> 127         if min_value >= -3.4028235e+38 and max_value <= 3.4028235e+38:
    128             return float32
    129         return float64

TypeError: '>=' not supported between instances of 'NoneType' and 'float'

Landscape complexity analysis [feature]

Thanks for creating and sharing this nice library @martibosch

I was looking to perform analysis of landscape complexity, and think that pylandstats would be a good host for such functionality. By landscape complexity, I'm specifically referring to the recently published information theoretical framework proposed by Nowosad and Stepinski.

A first version on biorxiv has a more bare description of the methodology: https://www.biorxiv.org/content/10.1101/383281v1
The peer-reviewed version is here, adding more context: https://link.springer.com/article/10.1007/s10980-019-00830-x

Description

Information theory can provide a consistent and universal framework to analyze complexity of landscape patterns. In the referenced study, the authors provide the background to explain that a single metric cannot capture the two inherent terms of landscape complexity, but two metrics are required. The two components of landscape complexity are compositional (diversity of classes) and configurational (spatial pattern), and show that compositional complexity is always the major component of landscape complexity.

They propose two metrics that can be used to analyze the complexity of a landscape: H and U. H is the well-described (Shannon) marginal entropy of the p log(p) form. U is the Mutual Information criterion (eq 5) divided by the marginal entropy, i.e., U = I(x,y) / H(y) = (1 - H(y|x) / H(y)). Essentially, this relies on an adjacency matrix for the focus cell containing a particular class.

Together a proposed visualization, the HYU diagram, helps project landscape patterns into a 2D space where landscapes with a different number of classes but with the same Shannon entropy (H) can be differentiated with their configurational complexity using U. See Fig 2A.

Implementation

A reference implementation from the authors is available in the R package landscapemetrics

Having looked into the Landscape class, I see that an internal dataframe is created with the horizontal and vertical adjacencies for a given landscape raster. I suppose this is the Rook's pattern (4 neighbors) adjacency, which is also what the original work uses for the analysis.

I'd like to help work up some code to produce the H & U metrics for a given landscape. H is pretty simple, as it just requires the proportional counts (p) of each class in the landscape to be used in the p log(p) summation. The mutual information I(x,y) requires the calculation of the conditional entropy H(x|y) (eq 2), ie, the summation of p log(p) where the p refers to the proportion of adjacent cells having a class x given that the focus cell has a class label y (if I've understood that correctly).

Could you indicate if this would be a welcome addition to the pylandstats library?

Some guidance on how to use the cached adjacency dataframe for calculating H(x|y) would be useful!

Landscape.py has not been compiled for Transonic-Numba

Hi Marti,

First, I want to thank you for creating Pylandstats because it is great having a package in Python for calculating landscape metrics.

Nevertheless, ever since I have been using Pylandstats, I have received the error "...\lib\site-packages\pylandstats\landscape.py has not been compiled for Transonic-Numba.". This is an error you have seen pass by on the Github here multiple times.

Usually, I have been using your package for smaller or far coarser datasets, so the significantly increased time it took to calculate some metrics could be overseen. However, currently I am using a dataset of about 210 hectares, and it takes approximately 30min/hectare to calculate all landscape metrics.

I was wondering whether recently you have gained more insight into factor that creates this warning for Windows computers, and how it can potentially be solved. If you require any additional information, I will gladly provide it. I hope to hear from you, and thank you again!

Cheers,

Jasper

Problem using Landscape analysis on Windows (Python)

  • PyLandStats version: 2.2.1
  • Python version: 3.6
  • Operating System: Windows

Description

Describe what you were trying to get done.
Tell us what happened, what went wrong, and what you expected to happen.

I am using the pylandstats library to solve the landscape index, and the following prompt appears after running.
image

C:\Users\GISzhao\AppData\Local\Programs\Python\Python36\python36.exe C:/Users/GISzhao/Desktop/MyGraduate/MyMaster/03_GeoSimulation_CA/code/temp.py
WARNING: Module C:\Users\GISzhao\AppData\Local\Programs\Python\Python36\lib\site-packages\pylandstats\landscape.py has not been compiled for Transonic-Numba

I want to know what is the reason for this and how to solve it.

`from pylandstats import Landscape

tif_file = '../test/data/lucc2015.tif'
landscape = Landscape(tif_file)
df = landscape.compute_landscape_metrics_df()
print(df)
print(df.columns)`
This is the code I am running.

Thank you.

What I Did

Paste the command(s) you ran and the output.
If there was a crash, please include the traceback here.

Warning message for contagion

Hello,

Thank you for putting together such a useful package. I had a question regarding the Contagion metric. When using the metric, I receive the warning "RuntimeWarning: Entropy-based metrics can only be computed in landscapes with more than two classes of patches. Returning nan". Should it say "two or more" classes instead of "more than two"? Pylandstats provides a value for Contagion when there are two classes.

No attribute read_geotiff

  • PyLandStats version: 2.3.0
  • Python version: 3.8
  • Operating System: Windows 10

Description

Hi @martibosch, pylandstats is a great package. I just found a small error in the readme.

The read_geotiff function used in the first readme example no longer works. I got it to work by instantiating a Landscape instead.

What I Did

>>> import pylandstats as pls
>>> ls = pls.read_geotiff('data/vaud_g100_clc00_V18_5.tif')

AttributeError: module 'pylandstats' has no attribute 'read_geotiff'

Using a shapefile for the zones in ZonalAnalysis

Description

Is it possible to implement using a shapefile for the mask_arr argument in pls.ZonalAnalysis? I don't need to buffer the zones, just generate the stats within each zone. From what I currently gather mask_arr takes rectangles in the form of numpy arrays.

Improving Space Efficiency for Zonal Analysis

Description

Idea

An improvement in space efficiency could be achieved by a size reduction of Landscape Arrays with sparse arrays (compression) or references instead of copies (duplication avoidance).

Reason

Improving the space efficiency of Landscape Arrays would greatly improve the usability of the library for zonal analyses of large datasets with many regions.

e.g.: I am using pylandstats on a large dataset with about 1100 regions and a raster of size 2600x2400. Zonal Analysis creates a copy of the raster for each region. This leads to high memory consumption (about 12 GB in my case -> but only with some manual improvements, like choosing the smallest possible dtype).

Possible improvements

  1. Using Zonal Analysis with a large set of regions means that each landscape has only a small fraction of non-null values. It should be possible to implement the landscape arrays as sparse arrays with the python library sparse without many adjustments to the rest of the code. I haven't tested it yet though and would appreciate an assessment on the feasibility and possible problems with other pieces of the code.
  2. Would it be possible to not copy the landscape for each region and instead use a reference to the original landscape together with the mask for the region? On request the array for the region could be computed on-the-fly with the mask and the original landscape. It could be discarded after the computation.

Let me know what you think about the suggestion, I might be able to submit a pull request if this change seems reasonable.

warnning when import pylandstats

Dear sir,
When I run import pylandstats as pls in pycharm, it shows warnning. Module C:\Softwares\20.Python\Lib\site-packages\pylandstats\landscape.py has not been compiled for Transonic-Numba.
What does it mean and how should I solve this problem?
Thanks for your help.

Exception: RuntimeError: structure and input must have equal rank

  • PyLandStats version: Latest
  • Python version: 3.8.6
  • Operating System: macOS 11.5.1

Description

Some preamble - I'm actually running pylandstats within a conda environment as I'm developing some code to run with Azure Functions. So I'm not sure if the below error is due to a problem with my conda environment, how Azure Functions is executing the code or whether it is actually a problem with pylandstats.

I'm posting this 'bug' here on the off-chance that someone may have seen this error outside of conda.

Please feel free to delete this bug/issue if it's not in any way related to pylandstats!

Trying to run compute_patch_metrics_df() produces the following error:

[2021-08-10T16:24:51.446Z] System.Private.CoreLib: Exception while executing function: Functions.LandcoverQueue. System.Private.CoreLib: Result: Failure
[2021-08-10T16:24:51.446Z] Exception: RuntimeError: structure and input must have equal rank
[2021-08-10T16:24:51.446Z] Stack:   File "/opt/homebrew/Cellar/azure-functions-core-tools@3/3.0.3477/workers/python/3.8/OSX/X64/azure_functions_worker/dispatcher.py", line 399, in _handle__invocation_request
[2021-08-10T16:24:51.446Z]     call_result = await self._loop.run_in_executor(
[2021-08-10T16:24:51.446Z]   File "/Users/simontarr/opt/miniconda3/envs/ecomap/lib/python3.8/concurrent/futures/thread.py", line 57, in run
[2021-08-10T16:24:51.446Z]     result = self.fn(*self.args, **self.kwargs)
[2021-08-10T16:24:51.446Z]   File "/opt/homebrew/Cellar/azure-functions-core-tools@3/3.0.3477/workers/python/3.8/OSX/X64/azure_functions_worker/dispatcher.py", line 603, in _run_sync_func
[2021-08-10T16:24:51.446Z]     return ExtensionManager.get_sync_invocation_wrapper(context,
[2021-08-10T16:24:51.446Z]   File "/opt/homebrew/Cellar/azure-functions-core-tools@3/3.0.3477/workers/python/3.8/OSX/X64/azure_functions_worker/extension.py", line 215, in _raw_invocation_wrapper
[2021-08-10T16:24:51.446Z]     result = function(**args)
[2021-08-10T16:24:51.446Z]   File "/Users/simontarr/Documents/ecomap/LandcoverQueue/__init__.py", line 98, in main
[2021-08-10T16:24:51.446Z]     x = ls.compute_patch_metrics_df()
[2021-08-10T16:24:51.446Z]   File "/Users/simontarr/Documents/ecomap/.venv/lib/python3.8/site-packages/pylandstats/landscape.py", line 2527, in compute_patch_metrics_df
[2021-08-10T16:24:51.446Z]     metrics_dfs = [self._patch_class_ser]
[2021-08-10T16:24:51.446Z]   File "/Users/simontarr/Documents/ecomap/.venv/lib/python3.8/site-packages/pylandstats/landscape.py", line 423, in _patch_class_ser
[2021-08-10T16:24:51.446Z]     np.concatenate([
[2021-08-10T16:24:51.446Z]   File "/Users/simontarr/Documents/ecomap/.venv/lib/python3.8/site-packages/pylandstats/landscape.py", line 424, in <listcomp>
[2021-08-10T16:24:51.446Z]     np.full(self._num_patches_dict[class_val], class_val)
[2021-08-10T16:24:51.446Z]   File "/Users/simontarr/Documents/ecomap/.venv/lib/python3.8/site-packages/pylandstats/landscape.py", line 395, in _num_patches_dict
[2021-08-10T16:24:51.446Z]     self._cached_num_patches_dict = {
[2021-08-10T16:24:51.446Z]   File "/Users/simontarr/Documents/ecomap/.venv/lib/python3.8/site-packages/pylandstats/landscape.py", line 396, in <dictcomp>
[2021-08-10T16:24:51.447Z]     class_val: self.class_label(class_val)[1]
[2021-08-10T16:24:51.447Z]   File "/Users/simontarr/Documents/ecomap/.venv/lib/python3.8/site-packages/pylandstats/landscape.py", line 205, in class_label
[2021-08-10T16:24:51.447Z]     return ndimage.label(self.landscape_arr == class_val,
[2021-08-10T16:24:51.447Z]   File "/Users/simontarr/Documents/ecomap/.venv/lib/python3.8/site-packages/scipy/ndimage/measurements.py", line 183, in label
[2021-08-10T16:24:51.447Z]     raise RuntimeError('structure and input must have equal rank')

My code:

# Load in raster as rioxarray
raster = rxr.open_rasterio(corine_lc['href'])
raster = raster.astype(int)

ls = Landscape(raster.values, res=(len(raster.x), len(raster.y)), nodata=0)

x = ls.compute_patch_metrics_df() # CODE FAILS HERE WITH THE ABOVE ERROR

My conda environment has the following libs/packages installed:

# Name                    Version                   Build  Channel
affine                    2.3.0                      py_0    conda-forge
astunparse                1.6.3              pyhd8ed1ab_0    conda-forge
attrs                     21.2.0             pyhd8ed1ab_0    conda-forge
autopep8                  1.5.7              pyhd8ed1ab_0    conda-forge
beniget                   0.4.1              pyhd8ed1ab_0    conda-forge
boost-cpp                 1.74.0               hff03dee_4    conda-forge
bzip2                     1.0.8                h0d85af4_4    conda-forge
c-ares                    1.17.2               h0d85af4_0    conda-forge
ca-certificates           2021.5.30            h033912b_0    conda-forge
cairo                     1.16.0            he43a7df_1008    conda-forge
cctools                   927.0.2              h5ba7a2e_4    conda-forge
certifi                   2021.5.30        py38h50d1736_0    conda-forge
cfitsio                   3.470                h01dc385_7    conda-forge
clang                     9.0.1           default_hf57f61e_0    conda-forge
clang_osx-64              9.0.1                h05bbb7f_0    conda-forge
clangxx                   9.0.1           default_hf57f61e_0    conda-forge
clangxx_osx-64            9.0.1                h05bbb7f_2    conda-forge
click                     7.1.2              pyh9f0ad1d_0    conda-forge
click-plugins             1.1.1                      py_0    conda-forge
cligj                     0.7.2              pyhd8ed1ab_0    conda-forge
compiler-rt               9.0.1                h6a512c6_3    conda-forge
compiler-rt_osx-64        9.0.1                h99342c6_3    conda-forge
curl                      7.78.0               hb861fe1_0    conda-forge
cycler                    0.10.0                     py_2    conda-forge
decorator                 4.4.2                      py_0    conda-forge
expat                     2.4.1                he49afe7_0    conda-forge
fiona                     1.8.20           py38hc9be10a_1    conda-forge
fontconfig                2.13.1            h10f422b_1005    conda-forge
freetype                  2.10.4               h4cff582_1    conda-forge
freexl                    1.0.6                h0d85af4_0    conda-forge
gast                      0.5.0              pyhd8ed1ab_0    conda-forge
gdal                      3.3.1            py38h140b4a6_1    conda-forge
geopandas                 0.6.1                      py_0  
geos                      3.9.1                he49afe7_2    conda-forge
geotiff                   1.6.0                h26421ea_6    conda-forge
gettext                   0.19.8.1          h7937167_1005    conda-forge
giflib                    5.2.1                hbcb3906_2    conda-forge
gmp                       6.2.1                h2e338ed_0    conda-forge
gmpy2                     2.1.0b5          py38h6052812_0    conda-forge
hdf4                      4.2.15               hefd3b78_3    conda-forge
hdf5                      1.10.6          nompi_hc5d9132_1114    conda-forge
icu                       68.1                 h74dc148_0    conda-forge
jbig                      2.1               h0d85af4_2003    conda-forge
jpeg                      9d                   hbcb3906_0    conda-forge
json-c                    0.15                 hcb556a6_0    conda-forge
kealib                    1.4.14               h31dd65d_2    conda-forge
kiwisolver                1.3.1            py38h12bbefe_1    conda-forge
krb5                      1.19.2               hcfbf3a7_0    conda-forge
lcms2                     2.12                 h577c468_0    conda-forge
ld64                      450.3                h3c32e8a_4    conda-forge
lerc                      2.2.1                h046ec9c_0    conda-forge
libblas                   3.9.0           11_osx64_openblas    conda-forge
libcblas                  3.9.0           11_osx64_openblas    conda-forge
libcurl                   7.78.0               hf45b732_0    conda-forge
libcxx                    12.0.1               habf9029_0    conda-forge
libdap4                   3.20.6               h3e144a0_2    conda-forge
libdeflate                1.7                  h35c211d_5    conda-forge
libedit                   3.1.20191231         h0678c8f_2    conda-forge
libev                     4.33                 haf1e3a3_1    conda-forge
libffi                    3.3                  h046ec9c_2    conda-forge
libgdal                   3.3.1                hd51e85c_1    conda-forge
libgfortran               5.0.0           9_3_0_h6c81a4c_23    conda-forge
libgfortran5              9.3.0               h6c81a4c_23    conda-forge
libglib                   2.68.3               hd556434_0    conda-forge
libiconv                  1.16                 haf1e3a3_0    conda-forge
libkml                    1.3.0             h8fd9edb_1014    conda-forge
liblapack                 3.9.0           11_osx64_openblas    conda-forge
libllvm9                  9.0.1                h223d4b2_3    conda-forge
libnetcdf                 4.8.0           nompi_hb4d10b0_103    conda-forge
libnghttp2                1.43.0               h07e645a_0    conda-forge
libopenblas               0.3.17          openmp_h3351f45_1    conda-forge
libpng                    1.6.37               h7cec526_2    conda-forge
libpq                     13.3                 hea3049e_0    conda-forge
librttopo                 1.1.0                h5413771_6    conda-forge
libspatialindex           1.9.3                he49afe7_4    conda-forge
libspatialite             5.0.1                h035f608_5    conda-forge
libssh2                   1.9.0                h52ee1ee_6    conda-forge
libtiff                   4.3.0                h1167814_1    conda-forge
libwebp-base              1.2.0                h0d85af4_2    conda-forge
libxml2                   2.9.12               h93ec3fd_0    conda-forge
libzip                    1.8.0                h8b0c345_0    conda-forge
llvm-openmp               12.0.1               hda6cdc1_1    conda-forge
lz4-c                     1.9.3                he49afe7_1    conda-forge
matplotlib                3.4.2            py38h50d1736_0    conda-forge
matplotlib-base           3.4.2            py38hc7d2367_0    conda-forge
mpc                       1.1.0             ha57cd0f_1009    conda-forge
mpfr                      4.1.0                h0f52abe_0    conda-forge
mpmath                    1.2.1              pyhd8ed1ab_0    conda-forge
munch                     2.5.0                      py_0    conda-forge
ncurses                   6.2                  h2e338ed_4    conda-forge
networkx                  2.6.2              pyhd8ed1ab_0    conda-forge
numpy                     1.21.1           py38had91d27_0    conda-forge
olefile                   0.46               pyh9f0ad1d_1    conda-forge
openjpeg                  2.4.0                h6e7aa92_1    conda-forge
openssl                   1.1.1k               h0d85af4_0    conda-forge
pandas                    1.3.1            py38h1f261ad_0    conda-forge
pcre                      8.45                 he49afe7_0    conda-forge
pillow                    8.3.1            py38ha4cf6ea_0  
pip                       21.2.3             pyhd8ed1ab_0    conda-forge
pixman                    0.40.0               hbcb3906_0    conda-forge
ply                       3.11                       py_1    conda-forge
poppler                   21.03.0              h640f9a4_0    conda-forge
poppler-data              0.4.10                        0    conda-forge
postgresql                13.3                 he8fe76e_0    conda-forge
proj                      8.0.1                h1512c50_0    conda-forge
pycodestyle               2.7.0              pyhd8ed1ab_0    conda-forge
pylandstats               2.1.1            py38ha0d09dd_0    conda-forge
pyparsing                 2.4.7              pyh9f0ad1d_0    conda-forge
pyproj                    3.1.0            py38hd0b2b97_3    conda-forge
python                    3.8.10          h0e5c897_0_cpython    conda-forge
python-dateutil           2.8.2              pyhd8ed1ab_0    conda-forge
python_abi                3.8                      2_cp38    conda-forge
pythran                   0.9.6            py38ha0d09dd_0    conda-forge
pytz                      2021.1             pyhd8ed1ab_0    conda-forge
rasterio                  1.2.6            py38hfca4e73_2    conda-forge
readline                  8.1                  h05e3726_0    conda-forge
rioxarray                 0.6.1              pyhd8ed1ab_0    conda-forge
rtree                     0.9.7            py38hc59ffc2_2    conda-forge
rust                      1.46.0               h1de35cc_0  
scipy                     1.7.1            py38hd329d04_0    conda-forge
setuptools                49.6.0           py38h50d1736_3    conda-forge
shapely                   1.7.1            py38h1830c62_5    conda-forge
six                       1.16.0             pyh6c4a22f_0    conda-forge
snuggs                    1.4.7                      py_0    conda-forge
sqlite                    3.36.0               h23a322b_0    conda-forge
sympy                     1.8              py38hecd8cb5_0  
tapi                      1000.10.8            h879752b_4    conda-forge
tiledb                    2.3.3                h8370e7a_0    conda-forge
tk                        8.6.10               h0419947_1    conda-forge
toml                      0.10.2             pyhd8ed1ab_0    conda-forge
tornado                   6.1              py38h96a0964_1    conda-forge
transonic                 0.4.10           py38h50d1736_0    conda-forge
tzcode                    2021a                h0d85af4_2    conda-forge
tzdata                    2021a                he74cb21_1    conda-forge
wheel                     0.37.0             pyhd8ed1ab_0    conda-forge
xarray                    0.19.0             pyhd8ed1ab_1    conda-forge
xerces-c                  3.2.3                h379762d_2    conda-forge
xsimd                     7.2.2                h770b8ee_0    conda-forge
xz                        5.2.5                haf1e3a3_1    conda-forge
zlib                      1.2.11            h7795811_1010    conda-forge
zstd                      1.5.0                h582d3a0_0    conda-forge

I have checked which dependencies pylandstats requires with:

conda search pylandstats --info 

pylandstats 2.3.0 py38h12bbefe_0
--------------------------------
file name   : pylandstats-2.3.0-py38h12bbefe_0.tar.bz2
name        : pylandstats
version     : 2.3.0
build       : py38h12bbefe_0
build number: 0
size        : 88 KB
license     : GPL-3.0-or-later
subdir      : osx-64
url         : https://conda.anaconda.org/conda-forge/osx-64/pylandstats-2.3.0-py38h12bbefe_0.tar.bz2
md5         : c519c0ad06ec1fdef9c45d87400f3e3d
timestamp   : 2021-04-23 22:38:58 UTC
dependencies: 
  - gast 0.3.3
  - geopandas
  - libcxx >=11.1.0
  - matplotlib-base
  - numpy
  - pandas
  - python >=3.8,<3.9.0a0
  - python_abi 3.8.* *_cp38
  - pythran
  - rasterio
  - scipy
  - transonic >=0.4.0

and can't see anything listed there which isn't included in my list of packages/libraries in my Conda environment.

Thanks!

Compute CORE proportion_of_landscape

Calculation of Core Proportion of Landscape

Hi @martibosch,

Thanks for such great work with package and exhaustive dcumentation.

I am trying to calculate proportion_of_landscape, although I would like to remove cells that are labeled with the Moore/Queen rule (neighborhood rule), so I could remove the influence of edge effects and then calculate a CORE value for each class type? Is this implemented somehow in pylandstats? What could be the best approach to it?

Thanks for the help and suggestions,
Vitor

line 611, in _patch_area_ser return self._cached_patch_area_ser AttributeError: 'Landscape' object has no attribute '_cached_patch_area_ser'

  • PyLandStats version:pylandstats 3.0.0rc1
  • Python version:python3.9
  • Operating System:window

Description

D:\anaconda\python.exe "D:\lhflearn\指数计算\landscape level1.py"
Traceback (most recent call last):
File "C:\Users\Administrator\AppData\Roaming\Python\Python39\site-packages\pylandstats\landscape.py", line 611, in _patch_area_ser
return self._cached_patch_area_ser
AttributeError: 'Landscape' object has no attribute '_cached_patch_area_ser'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "D:\lhflearn\指数计算\landscape level1.py", line 14, in
landscape_metrics_df = za.compute_landscape_metrics_df(metrics=metrics)
File "C:\Users\Administrator\AppData\Roaming\Python\Python39\site-packages\pylandstats\multilandscape.py", line 233, in compute_landscape_metrics_df
] = landscape.compute_landscape_metrics_df(
File "C:\Users\Administrator\AppData\Roaming\Python\Python39\site-packages\pylandstats\landscape.py", line 3943, in compute_landscape_metrics_df
metrics_dict[metric] = getattr(self, metric)(**metric_kws)
File "C:\Users\Administrator\AppData\Roaming\Python\Python39\site-packages\pylandstats\landscape.py", line 1711, in area_mn
return self._metric_mn(
File "C:\Users\Administrator\AppData\Roaming\Python\Python39\site-packages\pylandstats\landscape.py", line 792, in _metric_mn
return self._metric_reduce(
File "C:\Users\Administrator\AppData\Roaming\Python\Python39\site-packages\pylandstats\landscape.py", line 778, in _metric_reduce
patch_metrics = patch_metric_method(
File "C:\Users\Administrator\AppData\Roaming\Python\Python39\site-packages\pylandstats\landscape.py", line 882, in area
area_ser = self._get_patch_area_ser(class_val=class_val)
File "C:\Users\Administrator\AppData\Roaming\Python\Python39\site-packages\pylandstats\landscape.py", line 727, in _get_patch_area_ser
patch_area_ser = self._patch_area_ser
File "C:\Users\Administrator\AppData\Roaming\Python\Python39\site-packages\pylandstats\landscape.py", line 614, in _patch_area_ser
np.concatenate(
File "<array_function internals>", line 5, in concatenate
ValueError: need at least one array to concatenate

进程已结束,退出代码1

What I Did

import geopandas as gpd
import pandas as pd
from pylandstats import ZonalAnalysis

读取矢量区域块数据

gdf = gpd.read_file(r"D;\ .shp")
tif_file = r" D;\ .tif"

创建 ZonalAnalysis 实例并指定文件路径

za = ZonalAnalysis(landscape_filepath=tif_file, zones=gdf)

定义要计算的指标

metrics = ['area_mn']

计算景观级别指标

landscape_metrics_df = za.compute_landscape_metrics_df(metrics=metrics)

将结果存储到 Excel 文件

output_file = r"D:\lhf\ybds\景观级别指标.xlsx"
landscape_metrics_df.to_excel(output_file, index=False)

print("景观级别指标已保存到 Excel 文件:", output_file)

Paste the command(s) you ran and the output.
If there was a crash, please include the traceback here.
line 611, in _patch_area_ser
    return self._cached_patch_area_ser
AttributeError: 'Landscape' object has no attribute '_cached_patch_area_ser'

Error with compute_class_metrics_df

  • PyLandStats version: 2.3.0
  • Python version: 3.9
  • Operating System: Linux (inside Docker)

Description

I have a small .tif file and I'm trying to compute patch and class-level metrics with PyLandStats using the methods compute_patch_metrics_df and compute_class_metrics_df. I can successfully use compute_patch_metrics_df which returns:

          class_val          area  perimeter  perimeter_area_ratio  shape_index  fractal_dimension  euclidean_nearest_neighbor
patch_id                                                                                                                      
0                 2  1.607143e-08   0.122938          7.649463e+06     2.400000           0.797257                    0.002561
1                 2  1.639942e-10   0.005122          3.123531e+07     1.000000           1.000000                    0.024733
2                 2  1.013484e-07   0.274049          2.704027e+06     2.140000           0.777663                    0.032724
3                 2  3.279884e-10   0.007684          2.342648e+07     1.000000           0.990673                    0.002561
4                 2  1.459548e-08   0.117815          8.072046e+06     2.421053           0.798199                    0.010325
...             ...           ...        ...                   ...          ...                ...                         ...
169              43  6.559767e-10   0.012806          1.952207e+07     1.250000           0.962605                    0.002864
170              43  1.475948e-09   0.017928          1.214706e+07     1.166667           0.972284                    0.002561
171              43  3.279884e-10   0.007684          2.342648e+07     1.000000           0.990673                    0.004050
172              43  3.279884e-10   0.007684          2.342648e+07     1.000000           0.990673                    0.004050
173              44  2.469096e-06   0.952768          3.858772e+05     1.512195           0.775226                         NaN

[174 rows x 7 columns]

However I get an error with using compute_class_metrics_df (regardless of the input raster). The error is:

Traceback (most recent call last):
  File "/usr/src/app/ecomap/tests.py", line 278, in test_pylandstats
    y = ls.compute_class_metrics_df()
  File "/usr/local/lib/python3.9/site-packages/pylandstats/landscape.py", line 2616, in compute_class_metrics_df
    {
  File "/usr/local/lib/python3.9/site-packages/pylandstats/landscape.py", line 2617, in <dictcomp>
    class_val: getattr(self, metric)(
  File "/usr/local/lib/python3.9/site-packages/pylandstats/landscape.py", line 1240, in total_edge
    self._adjacency_df.groupby(
  File "/usr/local/lib/python3.9/site-packages/pandas/core/frame.py", line 4308, in drop
    return super().drop(
  File "/usr/local/lib/python3.9/site-packages/pandas/core/generic.py", line 4153, in drop
    obj = obj._drop_axis(labels, axis, level=level, errors=errors)
  File "/usr/local/lib/python3.9/site-packages/pandas/core/generic.py", line 4188, in _drop_axis
    new_axis = axis.drop(labels, errors=errors)
  File "/usr/local/lib/python3.9/site-packages/pandas/core/indexes/base.py", line 5591, in drop
    raise KeyError(f"{labels[mask]} not found in axis")
KeyError: '[None] not found in axis'

Is this error user error on my part or some other issue related to the code in PyLandStats? I've included one of the rasters which creates the above error.

from pylandstats import Landscape

ls = Landscape('/data/tests/testraster.tif')
x = ls.compute_patch_metrics_df() # Executes successfully
print(x)

y = ls.compute_class_metrics_df() # Described error here
print(y)

Thank you!
testraster.tif.zip

zonal analysis (03-zonal-analysis.ipynb) -"TypeError: expected string or bytes-like object"

  • PyLandStats version: Latest
  • Python version: 3.9.7
  • Operating System: Windows 10 x64

Hi Marti,

Thanks for creating the Pylandstat. I have calculated the metrics and now I am trying to do the zonal analysis (03-zonal-analysis.ipynb) but I received the following error: "TypeError: expected string or bytes-like object". I wanted to make sure the problem is not with my map therefore, I copied and pasted the code with the vaud_g100_clc00_V18_5 and bern_valais_g100_clc00 maps that you used in Pylandstat and realized that we received the same error.

I would appreciate it if you could help to resolve the error.

Best,
Bahareh

2022-04-12 (2)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.