Code Monkey home page Code Monkey logo

figanos's Introduction

figanos

Versions PyPI Supported Python Versions
Documentation and Support Documentation Status
Open Source License OpenSSF Scorecard
Coding Standards Python Black Ruff pre-commit.ci status
Development Status Project Status: Active – The project has reached a stable, usable state and is being actively developed. Build Status Coveralls

Figanos: Tool to create FIGures in the OurANOS style

Pour nous partager vos codes à ajouter dans figanos, s.v.p créer un issue sur le repo github avec une description de la fonction et le code de celle-ci.

Features

  • timeseries(): Creates time series as line plots.
  • gridmap(): Plots gridded georeferenced data on a map.
  • scattermap(): Make a scatter plot of georeferenced data on a map.
  • gdfmap(): Plots geometries (through a GeoDataFrame) on a map.
  • stripes(): Create climate stripe diagrams.
  • violin(): Create seaborn violin plots with extra options.
  • heatmap(): Create seaborn heatmaps with extra options.
  • taylordiagram(): Create Taylor diagram.

Credits

This package was created with Cookiecutter and the Ouranosinc/cookiecutter-pypackage project template.

figanos's People

Contributors

aulemahal avatar beauprel avatar coxipi avatar dependabot[bot] avatar juliettelavoie avatar pre-commit-ci[bot] avatar rondeaug avatar sarahclaude avatar vindelico avatar zeitsperre avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

figanos's Issues

Add divergent option in gdfmap

  • should get the divergent version when cmap=None and divergent is not None
  • also: change default cmap to None
  • also: add "evspsblpot" in recognized variables.

Extra colormaps like Portraits Climatiques

Feature Request:
For Portraits Climatiques 2.0, we identified IPCC colormaps for each indicators. Some of them
I would like us to be able to identify them as well by looking at the name of the variable.
Here are the one that don't work with our defaults right now.

liquidprcptot            : prec_seq 
dlyfrzthw                : misc_seq_3 
growing_degree_days_gt_X : wind_seq 
degree_days_below_0      : misc_seq_2 
tn_days_below_X        : misc_seq_2 

Atlas-style maps

Putting my code here for an eventual transfer to spirograph. The general idea is to load the Atlas shapefile in geopandas and add data to it, using TRONCON / station_id to match the correct reaches together between the NetCDF and shapefile.

Initialisation

import cartopy
import geopandas as gpd

# Carte des tronçons de l'Atlas: https://www.donneesquebec.ca/recherche/dataset/atlas-hydroclimatique-2022
shp = gpd.read_file("path_to_shp")
shp = shp.set_index("TRONCON")

# Initialize figure with a cartopy projection
fig, _ = plt.subplots(1, 1, figsize=(35, 15))
ax = plt.subplot(1, 1, 1, projection=cartopy.crs.Mercator())

Function to create the map

import matplotlib
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import cartopy.feature as cpf

def map_hydro(ax, data, shp, cmap, bnds, **kwargs):
    """

    Parameters
    ----------
    ax: cartopy.mpl.geoaxes.GeoAxes | cartopy.mpl.geoaxes.GeoAxesSubplot
        Created by initialising a matplotlib plot with the 'projection' argument.
    data: xr.DataArray
        Data to be plotted. Requires a 'station_id' coordinate.
    shp: geopandas.geodataframe.GeoDataFrame
        Spatial information data. Indexes should match 'station_id'
    cmap:
        Colormap to use.
    bnds: list
        Boundaries to use for matplotlib.colors.BoundaryNorm.

    """
    # Add data to the shapefile
    data["station_id"] = data.station_id.astype(str)
    da2 = data.to_dataframe().set_index("station_id")
    i = da2.index.intersection(shp.index)
    shp["val"] = da2.loc[i][data.name]

    # Change CRS of the shapefile, for cartopy/geopandas compatibility
    crs_proj4 = ax.projection.proj4_init
    df_ae = shp.to_crs(crs_proj4)

    # add the background
    ax.add_feature(cpf.LAND, color="#f0f0f0")
    ax.add_feature(cpf.OCEAN, color="#cfd3d4")
    ax.add_feature(cpf.STATES, edgecolor="black", linestyle="dotted")

    ax.add_feature(cpf.RIVERS, color="#cfd3d4")
    ax.add_feature(cpf.LAKES, color="#cfd3d4")

    # Normalize colormap to match the Atlas boundaries
    norm = matplotlib.colors.BoundaryNorm(boundaries=bnds, ncolors=256)

    # Plot data using geopandas
    df_ae.plot(column="val", ax=ax, norm=norm, cmap=cmap, **kwargs)

image

Hard-coded colormap (in case it is somehow useful to spirograph)

def get_atlas_cmap(indicator, plot_type):
    """
    Creates a hard-coded colormap that matches the colors and boundaries of the 2022 Hydroclimatic Atlas.

    Parameters
    ----------
    indicator: str
        Indicator to be plotted.
    plot_type: str
        One of [Direction, Ampleur, Dispersion]

    Returns
    -------
    cmap
        matplotlib.colors.LinearSegmentedColormap
    bnds: list
        Boundaries used by matplotlib.colors.BoundaryNorm

    """
    cmap = _atlas_cmap(plot_type)

    if plot_type == "Direction":
        bnds = [0, 0.10, 0.33, 0.66, 0.90, 1.00]
    elif plot_type == "Ampleur":
        bnds = {
            "Q1MAX2AN": [-999, -9, -5.4, -1.8, 1.8, 5.4, 9, 999],
            "Q1MAX20AN": [-999, -13, -7.8, -2.6, 2.6, 7.8, 13, 999],
            "Q1MAX100AN": [-999, -15, -9, -3, 3, 9, 15, 999],
            "Q1MAX350AN": [-999, -18, -10.8, -3.6, 3.6, 10.8, 18, 999],
            "Q7MIN2AN": [-999, -23, -13.8, -4.6, 4.6, 13.8, 23, 999],
            "Q7MIN2EA": [-999, -36, -21.6, -7.2, 7.2, 21.6, 36, 999],
            "QMOYAN": [-999, -8, -4.8, -1.6, 1.6, 4.8, 8, 999],
            "QMOYEA": [-999, -12, -7.2, -2.4, 2.4, 7.2, 12, 999],
            "QMOYHP": [-999, -17, -10.2, -3.4, 3.4, 10.2, 17, 999]
        }
        bnds = bnds[indicator]

    elif plot_type == "Dispersion":

        bnds = {
            "Q1MAX2AN": [0, 4, 8, 12, 15, 19, 23, 999],
            "Q1MAX20AN": [0, 5, 10, 15, 21, 26, 31, 999],
            "Q1MAX100AN": [0, 7, 14, 21, 28, 35, 42, 999],
            "Q1MAX350AN": [0, 9, 17, 26, 35, 43, 52, 999],
            "Q7MIN2AN": [0, 6, 11, 17, 23, 28, 34, 999],
            "Q7MIN2EA": [0, 5, 10, 16, 21, 26, 31, 999],
            "QMOYAN": [0, 2, 4, 6, 8, 10, 12, 999],
            "QMOYEA": [0, 4, 8, 12, 16, 20, 24, 999],
            "QMOYHP": [0, 2, 4, 6, 8, 10, 11, 999]
        }
        bnds = bnds[indicator]

    else:
        raise ValueError()

    return cmap, bnds


def _atlas_cmap(plot_type):
    """ Creates the color scheme."""
    if plot_type == "Direction":
        red = [i / 255 for i in (255, 28, 12)]
        orange = [i / 255 for i in (255, 178, 15)]
        white = [i / 255 for i in (255, 255, 255)]
        l_blue = [i / 255 for i in (19, 191, 255)]
        blue = [i / 255 for i in (11, 34, 224)]
        cmap = [red, orange, white, l_blue, blue]
    elif plot_type in ["Ampleur", "Dispersion"]:
        red = [i / 255 for i in (236, 60, 60)]
        orange = [i / 255 for i in (255, 190, 60)]
        yellow = [i / 255 for i in (255, 255, 61)]
        white = [i / 255 for i in (255, 255, 255)]
        cyan = [i / 255 for i in (85, 237, 255)]
        l_blue = [i / 255 for i in (61, 140, 221)]
        blue = [i / 255 for i in (60, 64, 221)]
        cmap = [red, orange, yellow, white, cyan, l_blue, blue]
    else:
        raise ValueError(f"'plot_type' should be one of [Direction, Ampleur, Dispersion], received {plot_type}.")

    return matplotlib.colors.LinearSegmentedColormap.from_list("custom_cmap", colors=cmap, N=256)

Add Ouranos logo

Two versions: small, pretty logo in a corner or outside the graph and big logo in background (for preventing copyright infringement)

triangle heatmap

Addressing a Problem?

J'aimerais une fonction heatmap, mais qui sépare chaque cellule en 2 triangles.
Je ne suis pas certaine si ça devrait être une option de fg.heatmap ou une nouvelle fonction fg.trianglemap ?

Potential Solution

Lorsque j'aurai du temps, j'aimerais ajouter ça en m'inpirant de https://stackoverflow.com/questions/63530701/python-package-to-plot-two-heatmaps-in-one-split-each-square-into-two-triangles

Additional context

Dans un projet, je considérais faire une heatmap avec diagonales. Finalement, je pense que ça ne fonctionne pas pour mes données, mais ce serait quand même bien d'avoir cette figure dans notre trousseau.

Contribution

  • I would be willing/able to open a Pull Request to contribute this feature.

Allow to choose to location of show_time

Sometimes the show_time is hidden under the figure (see image)
Capture d’écran, le 2023-04-18 à 15 38 48

I would like to be able to choose the location of show_time. This could be done either by coordinates (like bbox_to_anchor) or a string ('bottom right') like for legends.

Clean up env file and others

We import stuff that is not necessary in environment.yml. We should remove the package that are not needed.

We should also clean environment-docs.yml, requirements_docs.txt, requirements_dev.txt, ...

can't replace title in timeseries

using set_title with timeseries doesn't work. It writes on top instead of replacing.
It seems like it works fine for gridmap.

ax=sp.plot.timeseries(ds_time.tx_max_p50)
ax.set_title('test')

test

Test / improve matplotlib style sheets

Addressing a Problem?

Check if the other style sheets (paper and poster) work to produce figure for both options

Potential Solution

No response

Additional context

No response

Contribution

  • I would be willing/able to open a Pull Request to contribute this feature.

Can't import figanos

Generic Issue

  • figanos version: 0.2
  • Python version: 3.9
  • Operating System: linux

Description

I want to install the latest figanos (to use hatchmap).

What I Did

In my env and in the figanos directory

pip install . 

and then
import figanos.matplotlib as sp

What I Received

FileNotFoundError: [Errno 2] No such file or directory: '/exec/jlavoie/.conda/espo-fig/lib/python3.9/site-packages/figanos/data/terms.yml'

That file is present in my figanos directory, but it seems like it is not seen in the pip install ...

@aulemahal Do I have to do something special ? I assume there is no make translate here as I don't see it in the makefile ?

Automatically squeeze data

I sometimes have 3D data with the time dimension of lenght 1. gridmap and other maps fail to plot is because "it is not 2D". This is easily fixed by doing sp.gridmap(ds.squeeze()), but I would like spirograph to do the squeezing for me.

Add the ability to easily create custom colormaps

Description

In some cases, it might be useful to have the ability to easily create a fully custom colormap, with a color progression of your choosing, such as what was done in #13. I think the idea would be to

  • have a list of colors that are recognized
  • have the ability to provide the RGB

Then from what is provided, we construct the colormap.

Here's the (really rough and hard-coded) code in #13.

def _atlas_cmap(plot_type):
    """ Creates the color scheme."""
      red = [i / 255 for i in (255, 28, 12)]
      orange = [i / 255 for i in (255, 178, 15)]
      white = [i / 255 for i in (255, 255, 255)]
      l_blue = [i / 255 for i in (19, 191, 255)]
      blue = [i / 255 for i in (11, 34, 224)]
      cmap = [red, orange, white, l_blue, blue]

    return matplotlib.colors.LinearSegmentedColormap.from_list("custom_cmap", colors=cmap, N=256)

User access to colormaps

When using any function with a colorbar, users might want to create their own colorbar (fig.colorbar()), for instance when they have multiple subplots and want one colorbar. For this, they need to be able to create a ScalarMappable with the cmap used by spirograph.

This could be done by adding a util like get_cmap(str) where str is the name of an IPCC cmap.

Guess freezing rain

Feature Request:

Choose the right colormap for freezing rain.

I think it should have a distinct colormap to create a clear Ouranos style. My preference would be misc_sec_2.txt.
Example of variable names and their attrs:


zr_heures_mean_annuel
{'long_name': 'Annual hours of freezing rain', 'long_name_fr': 'Heures annuelles de verglas', 'description_fr': 'Moyenne des heures annuelles de verglas', 'units_fr': 'heures', 'units': 'h'}
zr_episodes_mean_annuel
{'long_name': 'Annual number of freezing rain events', 'long_name_fr': "Nombre annuel d'épisodes de verglas", 'description_fr': "Moyenne du nombre annuel d'épisodes de verglas", 'units_fr': 'épisodes', 'units': 'events'}
zr_episodescourts_mean_annuel
{'long_name': 'Annual number of short freezing rain events', 'long_name_fr': "Nombre annuel d'épisodes courts de verglas", 'description_fr': "Moyenne du nombre annuel d'épisodes courts (<= 6h) de verglas", 'units_fr': 'épisodes', 'units': 'events'}
zr_episodeslongs_annuel
{'long_name': 'Annual number of long freezing rain events', 'long_name_fr': "Nombre annuel d'épisodes longs de verglas", 'description_fr': "Moyenne du nombre annuel d'épisodes longs (> 6h) de verglas", 'units_fr': 'épisodes', 'units': 'events'}
zr_taux_mean_annuel
{'long_name': 'Annual rate of freezing rain events', 'long_name_fr': 'Taux annuel de verglas', 'description_fr': 'Moyenne du taux annuel de verglas', 'units_fr': 'mm/jour', 'units': 'mm d-1'}
zr_annees10mm_sum_30ans
{'long_name': 'Number of years with at least one 10-mm freezing rain event', 'long_name_fr': "Nombre d'années avec au moins un épisode de verglas > 10 mm", 'description_fr': "Nombre d'années avec au moins un épisode de verglas de plus de 10 mm", 'units_fr': 'années', 'units': 'y'}

Chris: "Pour les simulations MRCC5 la variable c'est "prfr", dans les observations le code (METAR) c'est FZRA, ZR est la version courte je crois. Je dirais que FZRA serait le plus standard"

Pascal: "Dans les données du MELCC, j'avais mis dret "freezing_rain"."

spiro modifies the features dict

I am plotting the same features on many subplots:

features={ 'lakes':{'scale':'110m', 'edgecolor':'black', 'facecolor':'none'},'coastline':{'scale':'50m'}}

  sp.gridmap(prop_ref, ax=ax0, plot_kw=plot_kw_prop, features=features)
  print(features)
  sp.gridmap(prop_sim, ax=ax1, plot_kw=plot_kw_prop, features=features)
  sp.gridmap(prop_scen, ax=ax3, plot_kw=plot_kw_prop, features=features)
  sp.gridmap(meas_sim_prop, ax=ax2, plot_kw=plot_kw_meas,divergent=0, features=features)
  sp.gridmap(meas_scen_prop, ax=ax4, plot_kw=plot_kw_meas,divergent=0, features=features)

After the first usage, the scale args disapear ({'lakes': {'edgecolor': 'black', 'facecolor': 'none'}, 'coastline': {}}) and the next plots have the default scales.
I think spiro should make sure to not modify the input dicts.

Standardized folders for logos and badges

Addressing a Problem?

When making a plot, the default approach is to use the Ouranos logo when figanos.matplotlib.utils.plot_logo() is called.

This behaviour is a bit odd, considering that this project is licensed under the Apache v2.0 License, specifically because we don't want to give a license for people to use our logos or create products that have our endorsements. In the event that someone not from Ouranos wants to use figanos and forgets to manually set the call signature, they'll have infringed on our software license.

Potential Solution

Using the platformdirs library, we can generate a config folder in the user's $HOME directory that, when figanos.matplotlib.utils.plot_logo() is called, grabs a file that adheres to the regex .+logo.png. This becomes the new default logo image whenever called.

This library would remove the Ouranos logo from the source code, and we would simply need to add the ouranos-logo.png to our config folders.

The platformdirs library is already installed by default for users of and projects based on xclim as of v0.45.0.

Additional context

https://github.com/platformdirs/platformdirs

Contribution

  • I would be willing/able to open a Pull Request to contribute this feature.

Feature Bug

Description

I'm trying to set a feature with a specific resolution, but it doesn't work.

What I Did

In the doc notebook, it is written that I can use {'coastline': {'scale': '50m', 'color':'grey'}}, but it doesn't actually work.

import cartopy.crs as ccrs

#Selecting a time and slicing our starting Dataset
ds_space = opened[['tx_max_p50']].isel(time=0).sel(lat=slice(40,65), lon=slice(-90,-55))

# defining our projection.
projection = ccrs.PlateCarree()

sp.plot.gridmap(ds_space, projection = projection,features = {'coastline': {'scale': '50m', 'color':'grey'}}, frame = True, show_time = True)

AttributeError: PathCollection.set() got an unexpected keyword argument 'scale'

Add heatmap function

Feature request for a function that plots heatmap.

It can be useful to plot the output of xs.diagnostics.measures_improvement_2d. I guess it can be used to plot any 2D dataset.
I am open to finding a better name for this.

Example:

image

Produced by :

pcat = xs.ProjectCatalog(ASK_ME_FOR_THE_PATH)
#assemble all improved into 1 dataset
dict_hm = pcat.search(processing_level='diag-improved', domain= 'QC-rdrs', experiment='ssp370').to_dataset_dict()
dict_hm= {ds.attrs['cat:source']:ds for name,ds in dict_hm.items()}
ds_merge=xs.diagnostics.measures_improvement_2d(dict_hm)

# convert to % # dont put this in spirograph
ds_merge['improved_grid_points']= ds_merge['improved_grid_points']*100


#plot
plt.figure(figsize=(15,7))
heatmap = ds_merge.improved_grid_points.plot.imshow(add_colorbar=True,vmin=0, cmap = 'RdBu',
                                                    cbar_kwargs={"orientation": "vertical"})
heatmap.colorbar.set_label('% of improved grid cells (IMP)', size=20)

plt.xticks( rotation=45, size=15, ha='right',rotation_mode='anchor')
plt.yticks(size=15)
plt.xlabel('')
plt.ylabel('')
y=1.03
# annotations , probably won't be put in spiro
plt.annotate(r"marginal",fontsize=15,xy=(0.26, y), xycoords='figure fraction')
plt.annotate(r"temporal",fontsize=15,xy=(0.53, y), xycoords='figure fraction')
plt.annotate(r"mv",fontsize=15,xy=(0.705, y), xycoords='figure fraction')
ax2 = plt.gca().secondary_xaxis('top')
ax2.tick_params(axis='x',length=20)
ax2.set_xticks([9.5,16.5])
plt.setp(ax2.get_xticklabels(), visible=False)

I don't know if there is a smart way to do the top axis. This is not necessary for the first iteration of this function. Right now, xclim doesn't write the aspects (marginal, temportal,mv..) in the attributes, but if we find a smart way to write the top axis, it could be added to xclim.

More control on the width of the white zone of divergent colorbars

Description

I have this colorbar:
image

Let's say that I'm not interested in values below ±4 (they are within the internal variability, or whatever). I would appreciate a way to easily hide them and associate all of that range to a white color.

What I did

I can use da.where(np.abs(da) > 4) to hide those grid cells on the graph itself, but the colorbar will stay the same and will be confusing. This is not a solution.

Ideally, I would also like the color gradient to start after the white zone (±4 in this example), which would not happen with the .where() solution.

make wrap optional

Sometimes the wrap of the colorbar label is annoying, especially when working with subplots. It wraps too much.

I would like to add an argument to make it optional or even choose the length at which to wrap.
I guess we might need one for the title and colorbar to be consistent, but the problem is mostly with colorbars.
Do you think it is overkill ?

My current solution is just to rewrite it as I want after spirograph with
axs[j,i].collections[-1].colorbar.set_label(f"{diff.attrs['long_name']} ({diff.attrs['units']})", fontsize=18)

image

Using Python 3.10 annotations with __future__

We could consider using Python 3.10 annotations (e.g. the | operator instead of Union[ ] for multiple types). To do so, every file would have to include from __future__ import annotations, to maintain backwards compatibility for Python 3.8 and 3.9.

gridmap function - bugs

  • Title with multiple lines is sometimes cut off from figure (ex: '30 year mean Annual: minimum of daily maximum: temperature.')
    GetImage

show_time doesn't work with cftime

I have a dataset with my time axis as cftime object, not np.datetime. This breaks show_time ingridmap. It is a common type, spiro should be able to handle it.

@Beauprel I can provide you with an example in private.

Detect 'month' and 'season' for timeseries

Addressing a Problem?

A common type of graph is an annual cycle. If time is not in the dimensions, timeseries should try to detect if either month or season are there.

Potential Solution

No response

Additional context

No response

Contribution

  • I would be willing/able to open a Pull Request to contribute this feature.

Transparent option

Addressing a Problem?

The matplotlib stylesheet are very nice feature of figanos, but I think they can be even cooler.

Potential Solution

Transparent background is a simple addition to the figures that makes them go from 😄 to 😎 when used in poster/presentations with non-white background.

plt.rcParams.update({
    "figure.facecolor":  (1.0, 1.0, 1.0, 0.0),
    "axes.facecolor":    (1.0, 1.0, 1.0, 0.3),
    "savefig.facecolor": (1.0, 1.0, 1.0, 0.0),
})

These lines could be added to a fourth stylesheet transparent ?

Additional context

Before
After

Contribution

  • I would be willing/able to open a Pull Request to contribute this feature.

check_timeindex compatibility with 360-day calendars.

check_timeindex might create issues with 360-day calendars. See #61

To do:

  • Check why check_timeindex was implemented in the first place (had to do with timeseries breaking).
  • If possible, find a workaround to this issue and get rid of check_timeindex altogether.
  • If not, find a way to convert that works with 360-day calendars.

Style uniformity of colormap

Dans les fonctions qui utilisent seaborn, la colormap n'a pas de frame. Dans celles qui utilisent matplotlib, oui.
Ce serait bien d'avoir un style plus uniforme. Mon choix serait pas de frame. Est-ce possible de définir ça dans la stylesheet?
Capture d’écran, le 2023-04-21 à 09 48 32
Capture d’écran, le 2023-04-21 à 09 48 57

timeseries function - bugs / limitations

To Do
logic of get_array_categ() has to be improved. Special cases might result in bugs

No support

No support for Need to add?
Datasets where the variables have different scales/units (e.g. temp, precipitation)
Ensemble with > 3 variables or percentiles later?
Xclim ensembles where the concatenation dimension is not 'realization'
any xarray object without a dimension named time

Known "Bugs"

Bug Need to fix?
split_legend function does not prevent overlapping labels yes

Guess more transform

This is a feature request.

Eventually, I would like us to be able to guess the transform of common types of data ( on top of the already existing guesses for PlateCarree and RotatedPoles) inside the gridmap function.

  • RegCM4 oblique mercator

Capture d’écran, le 2023-03-09 à 09 46 30

Docs notebooks to-do

To-do list for documentation notebook

Extending spirograph

  • Multiple subplots
  • Adding Arial (or other fonts) and resetting Matplotlib font cache

Figanos should rescale logos/images to fit the intended purpose

Figanos doesn't use actual scaling; Using zoom will deteriorate the image since it doesn't perform any interpolation (from what I can see in the docs for OffsetImage), but given that it's a PNG, we should be able to scale it down and/or constrain it to a region with Matplotlib (an example of that here: https://stackoverflow.com/questions/16742111/scale-image-in-matplotlib-without-changing-the-axis).

Lowering the logo resolution is a double-edged sword, since maybe it looks fine on monitors or in a notebook, but it'll look bad in print (article, poster) form. This is the exact problem that Seaborn deals with using their set_context() method.

Matplotlib offers lots of ways of interpolating/rescaling images: https://matplotlib.org/stable/api/image_api.html (more if we consider using scipy). Maybe it's worth looking into?

Originally posted by @Zeitsperre in #119 (comment)

Handling cartopy projections with Geopandas

Geopandas and Cartopy don't mix particularly well: when plotting a GeoDataFrame with df.plot(), which allows to automatically plot a column using a colormap, some cartopy projections are not displayed correctly on a matplotlib.ax.axes instance with a cartopy projection.

For our current applications, most projections we use are okay, especially when the extents are narrow (i.e. not the whole globe). Nonetheless, if this becomes a problem, we have the option of using ax.add_geometries() to plot the shapefile with colors using a method like in https://ipython-books.github.io/146-manipulating-geospatial-data-with-cartopy/.

add edge legend spacing

Generic Issue

Quand j'utilise la légende edge et que les derniers points sont très proches, j'aimerais que figanos comprenne qu'ils sont l'un par dessus l'autre et ajoute un peu de padding pour que ça se lise mieux.

Potentiellement, figanos pourait regarder les avant-derniers points si les derniers points sont trop proches.

Capture d’écran, le 2023-08-09 à 16 50 28

Detect if projection is needed in gdfmap

Description

Currently, projection is always used, no matter if ax already exists or if df is already in the right projection.

What I Did

  1. New ax with a projection (Mercator, for example)
  2. df.to_crs(ccrs.Mercator())
  3. gdfmap(df, ax=ax, ...) --> Even though everything should be fine, gdfmap changes df back to PlateCarree() (default value)
  4. My rivers appear in Florida, Africa, etc. 😭

Possible solution

If ax exists and has a projection, then change projection to it instead of PlateCarree().

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.