Coder Social home page Coder Social logo

Comments (10)

Phlya avatar Phlya commented on August 19, 2024

Thank you for reporting and glad you like the package!

Could you please provide an example with this behaviour? I can't reproduce it with a couple examples I tried, the results with and without saving steps are the same.

from adjusttext.

scaine1 avatar scaine1 commented on August 19, 2024

Here is a stripped down version of my plotting code which should show the problem described above.
Without save_steps=True or adding ax.draw(r) to the adjust_text routine, the labels end up going over the border of the map.

adjust_figure_with_save_steps
adjust_figure_without_save_steps

import pickle
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits import basemap
from collections import namedtuple, OrderedDict
from adjustText import adjust_text

def polygon(x, y, r, n):
    angle= (2 * np.pi) / n
    #convert r to degrees
    r = r * 1.852 # conveting to nautical miles
    r = r / (111.12)
    px_list = []
    py_list = []
    for i in range(0, n):
        px = r / np.cos(y * 0.0174532925) * np.sin(angle * i) + x
        py = r * np.cos(angle * i) + y
        px_list.append(px)
        py_list.append(py)
    px_list.append(px_list[0])
    py_list.append(py_list[0])
    return px_list, py_list


def create_basemap(lat_array, lon_array):
    lon_2d, lat_2d = np.meshgrid(lon_array, lat_array)
    cen_lat = np.sum(lat_array) / len(lat_array)
    cen_lon = np.sum(lon_array) / len(lon_array)
    proj = 'merc'
    m = basemap.Basemap(projection=proj,
                        llcrnrlon=lon_2d[0, 0],
                        llcrnrlat=lat_2d[0, 0],
                        urcrnrlon=lon_2d[-1, -1],
                        urcrnrlat=lat_2d[-1, -1],
                        lat_0=cen_lat,
                        lon_0=cen_lon,
                        resolution='h')

    x , y = m(lon_2d[:, :],lat_2d[:, :])
    return m, x ,y


Point = namedtuple('Point', ['lat', 'lon'])

example_points = [Point(lat=-20.0, lon=110.7),
                  Point(lat=-20.2, lon=110.8),
                  Point(lat=-20.5, lon=110.9),
                  Point(lat=-20.3, lon=111.2),
                  Point(lat=-20.0, lon=111.1),
                  Point(lat=-19.8, lon=111.0),
                  Point(lat=-19.8, lon=110.8),
                  Point(lat=-19.9, lon=110.6),
                  Point(lat=-20.2, lon=110.4),
                  Point(lat=-20.6, lon=110.3),
                  Point(lat=-21.2, lon=109.9),
                  Point(lat=-21.9, lon=109.4),
                  Point(lat=-22.8, lon=108.8),
                  Point(lat=-23.9, lon=108.3),
                  Point(lat=-25.0, lon=107.8),
                  Point(lat=-26.1, lon=107.8),
                  Point(lat=-27.3, lon=107.7),
                  Point(lat=-28.5, lon=108.8),
                  Point(lat=-29.2, lon=109.6),
                  Point(lat=-29.8, lon=110.7),
                  Point(lat=-30.0, lon=112.0)
                  ]

lat_array = np.arange(-40, -9.8, 0.1)
lon_array = np.arange(97.7, 122.0, 0.1)
m, x, y = create_basemap(lat_array, lon_array)

# below is a basic figure with no adjust, looks horrible
fig = plt.figure()
ax = fig.add_subplot(111)
for indx, pt in enumerate(example_points):
    x_pt, y_pt = m(pt.lon, pt.lat)
    m.scatter(x_pt, y_pt, s=20, c='k')
    if np.mod(indx, 2) == 0:
        my_text = plt.text(x_pt, y_pt, 'str about this long',
                  ha='right', va='center', fontsize=10,
                  fontweight='bold', color='k')
plt.savefig('basic_figure.png')

# below is a very stripped down version of my plot, there are more things plotted near
# the points, but I have removed them for the example purposes.
# the aim is to not have the labels too close to the points, but also not have them go over
# the border of the map

fig = plt.figure()
ax = fig.add_subplot(111)
label_list = []
repel_obj = []
for indx, pt in enumerate(example_points):
    x_pt, y_pt = m(pt.lon, pt.lat)
    m.scatter(x_pt, y_pt, s=20, c='k')
    if np.mod(indx, 2) == 0:
        my_text = plt.text(x_pt,
                           y_pt,
                           'str this long',
                           ha='right',
                           va='center',
                           fontsize=10,
                           fontweight='bold',
                           color='k')
        label_list.append(my_text)

    # create an area around the points that the labels should not enter
    # this is done by creating a fake circle around each point, with alpha=0 so we
    # do not see it, normally the plot has additional items plotted near the points

    circle_x, circle_y = polygon(pt.lon, pt.lat, 70, 32)
    map_circle_x, map_circle_y = m(circle_x, circle_y)
    repel_circle = plt.fill(map_circle_x, map_circle_y, color='m', alpha=0.0)
    repel_obj += repel_circle

# without save_steps or adding ax.draw(r) to adjust_text routine the labels go
# over the border.

adjust_text(label_list,
            add_objects=repel_obj,
            ax=ax,
            force_points=0.5,
            force_objects=0.5,
            lim=100,
            arrowprops=dict(arrowstyle="->", connectionstyle='arc3', color='k',lw=1.0)#,
            #save_steps=True
            )
plt.savefig('adjust_figure.png')

from adjusttext.

Phlya avatar Phlya commented on August 19, 2024

Any chance you can make an example without using basemap?.. I don't have it installed, and it doesn't seem to be as easy as I hoped it would be to install it.
Also, just in case, I have to mention that objects always work as rectangles, even if you create a circle, since the library uses their binding boxes to calculate overlaps...

from adjusttext.

Phlya avatar Phlya commented on August 19, 2024

(Also, to remove labels further away from points you can specify higher expand_points values)

from adjusttext.

scaine1 avatar scaine1 commented on August 19, 2024

Sorry I should have thought of that basemap could cause an issue, and it is not even really required for this example. Attached is the code with basemap removed (images attached before look the same so I won't upload them again)

At one stage I played with the expand_points value but didn't get the results I was looking for. However, I probably didn't give it a good enough go so I will look into that further.
For now, here is the code that shows the save_steps issue.

import pickle
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from collections import namedtuple, OrderedDict
from adjustText import adjust_text



def polygon(x, y, r, n):
    angle= (2 * np.pi) / n
    #convert r to degrees
    r = r * 1.852 # conveting to nautical miles
    r = r / (111.12)
    px_list = []
    py_list = []
    for i in range(0, n):
        px = r / np.cos(y * 0.0174532925) * np.sin(angle * i) + x
        py = r * np.cos(angle * i) + y
        px_list.append(px)
        py_list.append(py)
    px_list.append(px_list[0])
    py_list.append(py_list[0])
    return px_list, py_list


Point = namedtuple('Point', ['lat', 'lon'])

example_points = [Point(lat=-20.0, lon=110.7),
                  Point(lat=-20.2, lon=110.8),
                  Point(lat=-20.5, lon=110.9),
                  Point(lat=-20.3, lon=111.2),
                  Point(lat=-20.0, lon=111.1),
                  Point(lat=-19.8, lon=111.0),
                  Point(lat=-19.8, lon=110.8),
                  Point(lat=-19.9, lon=110.6),
                  Point(lat=-20.2, lon=110.4),
                  Point(lat=-20.6, lon=110.3),
                  Point(lat=-21.2, lon=109.9),
                  Point(lat=-21.9, lon=109.4),
                  Point(lat=-22.8, lon=108.8),
                  Point(lat=-23.9, lon=108.3),
                  Point(lat=-25.0, lon=107.8),
                  Point(lat=-26.1, lon=107.8),
                  Point(lat=-27.3, lon=107.7),
                  Point(lat=-28.5, lon=108.8),
                  Point(lat=-29.2, lon=109.6),
                  Point(lat=-29.8, lon=110.7),
                  Point(lat=-30.0, lon=112.0)
                  ]

lat_array = np.arange(-40, -9.8, 0.1)
lon_array = np.arange(97.7, 122.0, 0.1)

# below is a basic figure with no adjust, looks horrible
fig = plt.figure()
ax = fig.add_subplot(111)
for indx, pt in enumerate(example_points):
    m.scatter(pt.lon, pt.lat, s=20, c='k')
    if np.mod(indx, 2) == 0:
        my_text = plt.text(pt.lont pt.lat, 'str about this long',
                  ha='right', va='center', fontsize=10,
                  fontweight='bold', color='k')
plt.savefig('basic_figure.png')

# below is a very stripped down version of my plot, there are more things plotted near
# the points, but I have removed them for the example purposes.
# the aim is to not have the labels too close to the points, but also not have them go over
# the border of the map

fig = plt.figure()
ax = fig.add_subplot(111)
label_list = []
repel_obj = []
for indx, pt in enumerate(example_points):
    m.scatter(pt.lon, pt.lat, s=20, c='k')
    if np.mod(indx, 2) == 0:
        my_text = plt.text(pt.lon,
                           pt.lat,
                           'str this long',
                           ha='right',
                           va='center',
                           fontsize=10,
                           fontweight='bold',
                           color='k')
        label_list.append(my_text)

    # create an area around the points that the labels should not enter
    # this is done by creating a fake circle around each point, with alpha=0 so we
    # do not see it, normally the plot has additional items plotted near the points

    circle_x, circle_y = polygon(pt.lon, pt.lat, 70, 32)
    repel_circle = plt.fill(circle_x, circle_y, color='m', alpha=0.0)
    repel_obj += repel_circle

# without save_steps or adding ax.draw(r) to adjust_text routine the labels go
# over the border.

adjust_text(label_list,
            add_objects=repel_obj,
            ax=ax,
            force_points=0.5,
            force_objects=0.5,
            lim=100,
            arrowprops=dict(arrowstyle="->", connectionstyle='arc3', color='k',lw=1.0)#,
            #save_steps=True
            )
plt.savefig('adjust_figure.png')

from adjusttext.

Phlya avatar Phlya commented on August 19, 2024

I had to fix some things a bit because it wasn't working, but still, I can't reproduce the problem... m wasn't defined, so I substituted it for ax, and there was a comma missing.
I also see that your figsize and/or x/ylim are not standard, is it set to something in your rcparams? You don't specify it here.Or is it all the remnants of you basemap code?

I have to say, I never tested this with basemap, and it is possible that something from it might be at play here...

from adjusttext.

scaine1 avatar scaine1 commented on August 19, 2024

My apologies, I think that I had half-modified the script to remove basemap, but then was running the old script.. stupid mistake.

It seems I also cannot reproduce the issue if basemap is not used. So I guess the issue is related to the use of basemap..

from adjusttext.

Phlya avatar Phlya commented on August 19, 2024

OK, no problem. I guess adding draw calls shouldn't harm even without basemap, so maybe it's a good idea if it fixes the basemap situation... Since you have already modified the code, could you please check that the speed isn't affected much compared to the repo version? And if the difference is minimal, maybe submit a PR to introduce this?

from adjusttext.

scaine1 avatar scaine1 commented on August 19, 2024

I ran some speed tests, adding ax.draw(r) changed the average time to run the adjust_text function from ~ 0.5 seconds to ~1 sec.
Instead of just adding this in and slowing the function down, i created an on_basemap argument (default=False) which means the ax.draw(r) will only be called if the user plans to plot on a basemap.
I did a fork and created a pull request. This is the first time I have done that so please let me know if It worked correctly.

from adjusttext.

Phlya avatar Phlya commented on August 19, 2024

OK, great, thanks! Looks good to me, I'll merge it.

from adjusttext.

Related Issues (20)

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.