在世界地图上放大时,保持标记尺寸的扩展

发布于 2025-02-02 03:42:13 字数 13352 浏览 2 评论 0原文

我刚从python开始,可能在这里有点偏离,但是我想组合这个示例“>这个解决方案,托马斯·库恩(ThomasKühn)。

下面的数据创建了带有“火球”的世界地图。问题在于,当缩放进来时,圆的大小保持不变(绝对术语),相对于背景,它们变得较小。我想将托马斯·库恩(ThomasKühn)的解决方案应用于Zack Fizell的示例(不是真正的火球,而是使用世界地图)。

问题是,当解决代码时,我几乎没有收到有用的错误消息。这使得很难弄清楚我要去哪里。

我包含了所有代码,因此当链接在某个时候死亡时,这仍然是一个有趣的问题(我只是不确定该如何处理 csv-file 需要运行示例)。

这成为一个很长的问题,但我希望这至少是一个有趣的问题。

请随时给我有关如何改进此问题的提示

示例数据如下:

# Importing libraries
import matplotlib.pyplot as plt
import pandas as pd
import geopandas as gpd

# Reading cvs file using pandas
df = pd.read_csv('cneos_fireball_data.csv', 
                 usecols=["Peak Brightness Date/Time (UT)", 
                 "Calculated Total Impact Energy (kt)", 
                 "Latitude (deg.)", "Longitude (deg.)"])
df = df.rename(columns={"Peak Brightness Date/Time (UT)": 
                        'Datetime',
                        "Calculated Total Impact Energy (kt)": 
                        'Impact Energy [kt]',
                        "Latitude (deg.)": 'Latitude',
                        "Longitude (deg.)": 'Longitude'})

# Converting to a datetime datatype
df['Datetime'] = pd.to_datetime(df['Datetime'], errors='coerce')

# Applying +/- based on direction and converting to numeric datatype
for x in range(len(df['Longitude'])):
    if str(df.loc[x, 'Longitude'])[-1] == 'E':
        df.loc[x, 'Longitude'] = str(df.loc[x, 'Longitude'])[:-1]
    if str(df.loc[x, 'Longitude'])[-1] == 'W':
        df.loc[x, 'Longitude'] = \
            '-' + str(df.loc[x, 'Longitude'])[:-1]

for x in range(len(df['Latitude'])):
    if str(df.loc[x, 'Latitude'])[-1] == 'N':
        df.loc[x, 'Latitude'] = str(df.loc[x, 'Latitude'])[:-1]
    if str(df.loc[x, 'Latitude'])[-1] == 'S':
        df.loc[x, 'Latitude'] = \
            '-' + str(df.loc[x, 'Latitude'])[:-1]

df['Longitude'] = pd.to_numeric(df['Longitude'], errors='coerce')
df['Latitude'] = pd.to_numeric(df['Latitude'], errors='coerce')

# Converting to numeric datatype
threshold = 20
df = df[df['Impact Energy [kt]'] < threshold]
df['Impact Energy [kt]'] = pd.to_numeric(df['Impact Energy [kt]'], 
                                         errors='coerce')

# Dropping the errors from data conversions and resetting index
df.dropna()
df = df.reset_index(drop=True)

# From GeoPandas, our world map data
worldmap = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))

# Creating axes and plotting world map
fig, ax = plt.subplots(figsize=(12, 6))
worldmap.plot(color="lightgrey", ax=ax)

# Plotting our Impact Energy data with a color map
x = df['Longitude']
y = df['Latitude']
z = df['Impact Energy [kt]']
plt.scatter(x, y, s=20*z, c=z, alpha=0.6, vmin=0, vmax=threshold,
            cmap='autumn')
plt.colorbar(label='Impact Energy [kt]')

# Creating axis limits and title
plt.xlim([-180, 180])
plt.ylim([-90, 90])

first_year = df["Datetime"].min().strftime("%Y")
last_year = df["Datetime"].max().strftime("%Y")
plt.title("NASA: Fireballs Reported by Government Sensors\n" +     
          str(first_year) + " - " + str(last_year))
plt.xlabel("Longitude")
plt.ylabel("Latitude")
plt.show()

<

a href =“ https://i.sstatic.net/sihgw.png” rel = “ nofollow noreferrer”> “在此处输入图像描述”

我的重点是我在适应解决方案时遇到了麻烦。主要是因为我不太了解MarkerupDater类非常好(见下文)。

库恩(

from matplotlib import pyplot as plt
import numpy as np

##plt.switch_backend('TkAgg')
class MarkerUpdater:
    def __init__(self):
        ##for storing information about Figures and Axes
        self.figs = {}

        ##for storing timers
        self.timer_dict = {}

    def add_ax(self, ax, features=[]):
        ax_dict = self.figs.setdefault(ax.figure,dict())
        ax_dict[ax] = {
            'xlim' : ax.get_xlim(),
            'ylim' : ax.get_ylim(),
            'figw' : ax.figure.get_figwidth(),
            'figh' : ax.figure.get_figheight(),
            'scale_s' : 1.0,
            'scale_a' : 1.0,
            'features' : [features] if isinstance(features,str) else features,
        }
        ax.figure.canvas.mpl_connect('draw_event', self.update_axes)

    def update_axes(self, event):

        for fig,axes in self.figs.items():
            if fig is event.canvas.figure:

                for ax, args in axes.items():
                    ##make sure the figure is re-drawn
                    update = True

                    fw = fig.get_figwidth()
                    fh = fig.get_figheight()
                    fac1 = min(fw/args['figw'], fh/args['figh'])


                    xl = ax.get_xlim()
                    yl = ax.get_ylim()
                    fac2 = min(
                        abs(args['xlim'][1]-args['xlim'][0])/abs(xl[1]-xl[0]),
                        abs(args['ylim'][1]-args['ylim'][0])/abs(yl[1]-yl[0])
                    )

                    ##factor for marker size
                    facS = (fac1*fac2)/args['scale_s']

                    ##factor for alpha -- limited to values smaller 1.0
                    facA = min(1.0,fac1*fac2)/args['scale_a']

                    ##updating the artists
                    if facS != 1.0:
                        for line in ax.lines:
                            if 'size' in args['features']:
                                line.set_markersize(line.get_markersize()*facS)

                            if 'alpha' in args['features']:
                                alpha = line.get_alpha()
                                if alpha is not None:
                                    line.set_alpha(alpha*facA)


                        for path in ax.collections:
                            if 'size' in args['features']:
                                path.set_sizes([s*facS**2 for s in path.get_sizes()])

                            if 'alpha' in args['features']:
                                alpha = path.get_alpha()
                                if alpha is not None:
                                    path.set_alpha(alpha*facA)

                        args['scale_s'] *= facS
                        args['scale_a'] *= facA

                self._redraw_later(fig)



    def _redraw_later(self, fig):
        timer = fig.canvas.new_timer(interval=10)
        timer.single_shot = True
        timer.add_callback(lambda : fig.canvas.draw_idle())
        timer.start()

        ##stopping previous timer
        if fig in self.timer_dict:
            self.timer_dict[fig].stop()

        ##storing a reference to prevent garbage collection
        self.timer_dict[fig] = timer

if __name__ == '__main__':
    my_updater = MarkerUpdater()

    ##setting up the figure
    fig, axes = plt.subplots(nrows = 2, ncols =2)#, figsize=(1,1))
    ax1,ax2,ax3,ax4 = axes.flatten()

    ## a line plot
    x1 = np.linspace(0,np.pi,30)
    y1 = np.sin(x1)
    ax1.plot(x1, y1, 'ro', markersize = 10, alpha = 0.8)
    ax3.plot(x1, y1, 'ro', markersize = 10, alpha = 1)

    ## a scatter plot
    x2 = np.random.normal(1,1,30)
    y2 = np.random.normal(1,1,30)
    ax2.scatter(x2,y2, c = 'b', s = 100, alpha = 0.6)

    ## scatter and line plot
    ax4.scatter(x2,y2, c = 'b', s = 100, alpha = 0.6)
    ax4.plot([0,0.5,1],[0,0.5,1],'ro', markersize = 10) ##note: no alpha value!

    ##setting up the updater
    my_updater.add_ax(ax1, ['size'])  ##line plot, only marker size
    my_updater.add_ax(ax2, ['size'])  ##scatter plot, only marker size
    my_updater.add_ax(ax3, ['alpha']) ##line plot, only alpha
    my_updater.add_ax(ax4, ['size', 'alpha']) ##scatter plot, marker size and alpha

    plt.show()

ThomasKühn

托马斯· “ alt =”在此处输入图像描述”>

我的尝试

请注意:我没有触摸MarketUpdater,我只使用Thomas的解决方案的ax2

from matplotlib import pyplot as plt
import numpy as np

##plt.switch_backend('TkAgg')
class MarkerUpdater:
    def __init__(self):
        ##for storing information about Figures and Axes
        self.figs = {}

        ##for storing timers
        self.timer_dict = {}

    def add_ax(self, ax, features=[]):
        ax_dict = self.figs.setdefault(ax.figure,dict())
        ax_dict[ax] = {
            'xlim' : ax.get_xlim(),
            'ylim' : ax.get_ylim(),
            'figw' : ax.figure.get_figwidth(),
            'figh' : ax.figure.get_figheight(),
            'scale_s' : 1.0,
            'scale_a' : 1.0,
            'features' : [features] if isinstance(features,str) else features,
        }
        ax.figure.canvas.mpl_connect('draw_event', self.update_axes)

    def update_axes(self, event):

        for fig,axes in self.figs.items():
            if fig is event.canvas.figure:

                for ax, args in axes.items():
                    ##make sure the figure is re-drawn
                    update = True

                    fw = fig.get_figwidth()
                    fh = fig.get_figheight()
                    fac1 = min(fw/args['figw'], fh/args['figh'])


                    xl = ax.get_xlim()
                    yl = ax.get_ylim()
                    fac2 = min(
                        abs(args['xlim'][1]-args['xlim'][0])/abs(xl[1]-xl[0]),
                        abs(args['ylim'][1]-args['ylim'][0])/abs(yl[1]-yl[0])
                    )

                    ##factor for marker size
                    facS = (fac1*fac2)/args['scale_s']

                    ##factor for alpha -- limited to values smaller 1.0
                    facA = min(1.0,fac1*fac2)/args['scale_a']

                    ##updating the artists
                    if facS != 1.0:
                        for line in ax.lines:
                            if 'size' in args['features']:
                                line.set_markersize(line.get_markersize()*facS)

                            if 'alpha' in args['features']:
                                alpha = line.get_alpha()
                                if alpha is not None:
                                    line.set_alpha(alpha*facA)


                        for path in ax.collections:
                            if 'size' in args['features']:
                                path.set_sizes([s*facS**2 for s in path.get_sizes()])

                            if 'alpha' in args['features']:
                                alpha = path.get_alpha()
                                if alpha is not None:
                                    path.set_alpha(alpha*facA)

                        args['scale_s'] *= facS
                        args['scale_a'] *= facA

                self._redraw_later(fig)



    def _redraw_later(self, fig):
        timer = fig.canvas.new_timer(interval=10)
        timer.single_shot = True
        timer.add_callback(lambda : fig.canvas.draw_idle())
        timer.start()

        ##stopping previous timer
        if fig in self.timer_dict:
            self.timer_dict[fig].stop()

        ##storing a reference to prevent garbage collection
        self.timer_dict[fig] = timer

if __name__ == '__main__':
    my_updater = MarkerUpdater()

    ##setting up the figure
    fig, axes = plt.subplots(nrows=2, ncols=3,figsize=(12, 6)) # swatchai's comment
    ax2 = axes.flatten()

    ## a line plot
    # x1 = np.linspace(0,np.pi,30)
    # y1 = np.sin(x1)
    # ax1.plot(x1, y1, 'ro', markersize = 10, alpha = 0.8)
    # ax3.plot(x1, y1, 'ro', markersize = 10, alpha = 1)

    ## a scatter plot
    worldmap.plot(color="lightgrey", ax=ax2)

    # Plotting our Impact Energy data with a color map
    x = df['Longitude']
    y = df['Latitude']
    z = df['Impact Energy [kt]']
    # x = np.random.normal(1,1,30)
    # y = np.random.normal(1,1,30)
    ax2.scatter(x, y, s=20*z, c=z, alpha=0.6, vmin=0, vmax=threshold,
        cmap='autumn')

    ## scatter and line plot
    # ax4.scatter(x2,y2, c = 'b', s = 100, alpha = 0.6)
    # ax4.plot([0,0.5,1],[0,0.5,1],'ro', markersize = 10) ##note: no alpha value!

    ##setting up the updater
    # my_updater.add_ax(ax1, ['size'])  ##line plot, only marker size
    my_updater.add_ax(ax2, ['size'])  ##scatter plot, only marker size
    # my_updater.add_ax(ax3, ['alpha']) ##line plot, only alpha
    # my_updater.add_ax(ax4, ['size', 'alpha']) ##scatter plot, marker size and alpha

    plt.show()

追溯

错误是在此行中的错误:

worldmap.plot(color="lightgrey", ax=ax2)

Trackback:

Traceback (most recent call last):
  File "c:\Users\x\OneDrive - Wageningen University & Research\Arjen Daane\Data\tempCodeRunnerFile.python", line 185, in <module>
    worldmap.plot(color="lightgrey", ax=ax2)
  File "C:\Users\x\AppData\Local\Programs\Python\Python310\lib\site-packages\geopandas\geodataframe.py", line 617, in plot
    return plot_dataframe(self, *args, **kwargs)
  File "C:\Users\x\AppData\Local\Programs\Python\Python310\lib\site-packages\geopandas\plotting.py", line 504, in plot_dataframe
    ax.set_aspect("equal")
AttributeError: 'numpy.ndarray' object has no attribute 'set_aspect'

有人有兴趣帮助我前进吗?

I am just starting out with Python and probably in a little bit over my head here, but I would like to combine this example, by Zack Fizell, with this solution, by Thomas Kühn.

The data below creates a world map with "fire balls". The issue is that when zooming in, the size of the circles remains the same (in absolute terms) and they become smaller relative to the background. I would like to apply the solution by Thomas Kühn to this example by Zack Fizell (not really for the fireballs, but for my own data using a world map).

The problem is that when fiddling around with the code, I hardly ever get a useful error message. Which makes it hard to figure out where I'm going wrong.

I have included all the code, so that it is still an interesting question when the link dies at some point (I am just not sure what to do with the csv-file needed to run the example).

It became quite a long question but I hope it is at least an interesting one.

Please feel free to give me tips on how to improve this question

The example data is as follows:

# Importing libraries
import matplotlib.pyplot as plt
import pandas as pd
import geopandas as gpd

# Reading cvs file using pandas
df = pd.read_csv('cneos_fireball_data.csv', 
                 usecols=["Peak Brightness Date/Time (UT)", 
                 "Calculated Total Impact Energy (kt)", 
                 "Latitude (deg.)", "Longitude (deg.)"])
df = df.rename(columns={"Peak Brightness Date/Time (UT)": 
                        'Datetime',
                        "Calculated Total Impact Energy (kt)": 
                        'Impact Energy [kt]',
                        "Latitude (deg.)": 'Latitude',
                        "Longitude (deg.)": 'Longitude'})

# Converting to a datetime datatype
df['Datetime'] = pd.to_datetime(df['Datetime'], errors='coerce')

# Applying +/- based on direction and converting to numeric datatype
for x in range(len(df['Longitude'])):
    if str(df.loc[x, 'Longitude'])[-1] == 'E':
        df.loc[x, 'Longitude'] = str(df.loc[x, 'Longitude'])[:-1]
    if str(df.loc[x, 'Longitude'])[-1] == 'W':
        df.loc[x, 'Longitude'] = \
            '-' + str(df.loc[x, 'Longitude'])[:-1]

for x in range(len(df['Latitude'])):
    if str(df.loc[x, 'Latitude'])[-1] == 'N':
        df.loc[x, 'Latitude'] = str(df.loc[x, 'Latitude'])[:-1]
    if str(df.loc[x, 'Latitude'])[-1] == 'S':
        df.loc[x, 'Latitude'] = \
            '-' + str(df.loc[x, 'Latitude'])[:-1]

df['Longitude'] = pd.to_numeric(df['Longitude'], errors='coerce')
df['Latitude'] = pd.to_numeric(df['Latitude'], errors='coerce')

# Converting to numeric datatype
threshold = 20
df = df[df['Impact Energy [kt]'] < threshold]
df['Impact Energy [kt]'] = pd.to_numeric(df['Impact Energy [kt]'], 
                                         errors='coerce')

# Dropping the errors from data conversions and resetting index
df.dropna()
df = df.reset_index(drop=True)

# From GeoPandas, our world map data
worldmap = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))

# Creating axes and plotting world map
fig, ax = plt.subplots(figsize=(12, 6))
worldmap.plot(color="lightgrey", ax=ax)

# Plotting our Impact Energy data with a color map
x = df['Longitude']
y = df['Latitude']
z = df['Impact Energy [kt]']
plt.scatter(x, y, s=20*z, c=z, alpha=0.6, vmin=0, vmax=threshold,
            cmap='autumn')
plt.colorbar(label='Impact Energy [kt]')

# Creating axis limits and title
plt.xlim([-180, 180])
plt.ylim([-90, 90])

first_year = df["Datetime"].min().strftime("%Y")
last_year = df["Datetime"].max().strftime("%Y")
plt.title("NASA: Fireballs Reported by Government Sensors\n" +     
          str(first_year) + " - " + str(last_year))
plt.xlabel("Longitude")
plt.ylabel("Latitude")
plt.show()

Result:

enter image description here

The point is that I am having trouble adapting the solution. Mostly because I do not understand the MarkerUpdater class very well (see below).

Solution by Thomas Kühn

from matplotlib import pyplot as plt
import numpy as np

##plt.switch_backend('TkAgg')
class MarkerUpdater:
    def __init__(self):
        ##for storing information about Figures and Axes
        self.figs = {}

        ##for storing timers
        self.timer_dict = {}

    def add_ax(self, ax, features=[]):
        ax_dict = self.figs.setdefault(ax.figure,dict())
        ax_dict[ax] = {
            'xlim' : ax.get_xlim(),
            'ylim' : ax.get_ylim(),
            'figw' : ax.figure.get_figwidth(),
            'figh' : ax.figure.get_figheight(),
            'scale_s' : 1.0,
            'scale_a' : 1.0,
            'features' : [features] if isinstance(features,str) else features,
        }
        ax.figure.canvas.mpl_connect('draw_event', self.update_axes)

    def update_axes(self, event):

        for fig,axes in self.figs.items():
            if fig is event.canvas.figure:

                for ax, args in axes.items():
                    ##make sure the figure is re-drawn
                    update = True

                    fw = fig.get_figwidth()
                    fh = fig.get_figheight()
                    fac1 = min(fw/args['figw'], fh/args['figh'])


                    xl = ax.get_xlim()
                    yl = ax.get_ylim()
                    fac2 = min(
                        abs(args['xlim'][1]-args['xlim'][0])/abs(xl[1]-xl[0]),
                        abs(args['ylim'][1]-args['ylim'][0])/abs(yl[1]-yl[0])
                    )

                    ##factor for marker size
                    facS = (fac1*fac2)/args['scale_s']

                    ##factor for alpha -- limited to values smaller 1.0
                    facA = min(1.0,fac1*fac2)/args['scale_a']

                    ##updating the artists
                    if facS != 1.0:
                        for line in ax.lines:
                            if 'size' in args['features']:
                                line.set_markersize(line.get_markersize()*facS)

                            if 'alpha' in args['features']:
                                alpha = line.get_alpha()
                                if alpha is not None:
                                    line.set_alpha(alpha*facA)


                        for path in ax.collections:
                            if 'size' in args['features']:
                                path.set_sizes([s*facS**2 for s in path.get_sizes()])

                            if 'alpha' in args['features']:
                                alpha = path.get_alpha()
                                if alpha is not None:
                                    path.set_alpha(alpha*facA)

                        args['scale_s'] *= facS
                        args['scale_a'] *= facA

                self._redraw_later(fig)



    def _redraw_later(self, fig):
        timer = fig.canvas.new_timer(interval=10)
        timer.single_shot = True
        timer.add_callback(lambda : fig.canvas.draw_idle())
        timer.start()

        ##stopping previous timer
        if fig in self.timer_dict:
            self.timer_dict[fig].stop()

        ##storing a reference to prevent garbage collection
        self.timer_dict[fig] = timer

if __name__ == '__main__':
    my_updater = MarkerUpdater()

    ##setting up the figure
    fig, axes = plt.subplots(nrows = 2, ncols =2)#, figsize=(1,1))
    ax1,ax2,ax3,ax4 = axes.flatten()

    ## a line plot
    x1 = np.linspace(0,np.pi,30)
    y1 = np.sin(x1)
    ax1.plot(x1, y1, 'ro', markersize = 10, alpha = 0.8)
    ax3.plot(x1, y1, 'ro', markersize = 10, alpha = 1)

    ## a scatter plot
    x2 = np.random.normal(1,1,30)
    y2 = np.random.normal(1,1,30)
    ax2.scatter(x2,y2, c = 'b', s = 100, alpha = 0.6)

    ## scatter and line plot
    ax4.scatter(x2,y2, c = 'b', s = 100, alpha = 0.6)
    ax4.plot([0,0.5,1],[0,0.5,1],'ro', markersize = 10) ##note: no alpha value!

    ##setting up the updater
    my_updater.add_ax(ax1, ['size'])  ##line plot, only marker size
    my_updater.add_ax(ax2, ['size'])  ##scatter plot, only marker size
    my_updater.add_ax(ax3, ['alpha']) ##line plot, only alpha
    my_updater.add_ax(ax4, ['size', 'alpha']) ##scatter plot, marker size and alpha

    plt.show()

Result:

enter image description here

My attempt

PLEASE NOTE: I have not touched the MarketUpdater, and I am only using ax2 of Thomas' solution:

from matplotlib import pyplot as plt
import numpy as np

##plt.switch_backend('TkAgg')
class MarkerUpdater:
    def __init__(self):
        ##for storing information about Figures and Axes
        self.figs = {}

        ##for storing timers
        self.timer_dict = {}

    def add_ax(self, ax, features=[]):
        ax_dict = self.figs.setdefault(ax.figure,dict())
        ax_dict[ax] = {
            'xlim' : ax.get_xlim(),
            'ylim' : ax.get_ylim(),
            'figw' : ax.figure.get_figwidth(),
            'figh' : ax.figure.get_figheight(),
            'scale_s' : 1.0,
            'scale_a' : 1.0,
            'features' : [features] if isinstance(features,str) else features,
        }
        ax.figure.canvas.mpl_connect('draw_event', self.update_axes)

    def update_axes(self, event):

        for fig,axes in self.figs.items():
            if fig is event.canvas.figure:

                for ax, args in axes.items():
                    ##make sure the figure is re-drawn
                    update = True

                    fw = fig.get_figwidth()
                    fh = fig.get_figheight()
                    fac1 = min(fw/args['figw'], fh/args['figh'])


                    xl = ax.get_xlim()
                    yl = ax.get_ylim()
                    fac2 = min(
                        abs(args['xlim'][1]-args['xlim'][0])/abs(xl[1]-xl[0]),
                        abs(args['ylim'][1]-args['ylim'][0])/abs(yl[1]-yl[0])
                    )

                    ##factor for marker size
                    facS = (fac1*fac2)/args['scale_s']

                    ##factor for alpha -- limited to values smaller 1.0
                    facA = min(1.0,fac1*fac2)/args['scale_a']

                    ##updating the artists
                    if facS != 1.0:
                        for line in ax.lines:
                            if 'size' in args['features']:
                                line.set_markersize(line.get_markersize()*facS)

                            if 'alpha' in args['features']:
                                alpha = line.get_alpha()
                                if alpha is not None:
                                    line.set_alpha(alpha*facA)


                        for path in ax.collections:
                            if 'size' in args['features']:
                                path.set_sizes([s*facS**2 for s in path.get_sizes()])

                            if 'alpha' in args['features']:
                                alpha = path.get_alpha()
                                if alpha is not None:
                                    path.set_alpha(alpha*facA)

                        args['scale_s'] *= facS
                        args['scale_a'] *= facA

                self._redraw_later(fig)



    def _redraw_later(self, fig):
        timer = fig.canvas.new_timer(interval=10)
        timer.single_shot = True
        timer.add_callback(lambda : fig.canvas.draw_idle())
        timer.start()

        ##stopping previous timer
        if fig in self.timer_dict:
            self.timer_dict[fig].stop()

        ##storing a reference to prevent garbage collection
        self.timer_dict[fig] = timer

if __name__ == '__main__':
    my_updater = MarkerUpdater()

    ##setting up the figure
    fig, axes = plt.subplots(nrows=2, ncols=3,figsize=(12, 6)) # swatchai's comment
    ax2 = axes.flatten()

    ## a line plot
    # x1 = np.linspace(0,np.pi,30)
    # y1 = np.sin(x1)
    # ax1.plot(x1, y1, 'ro', markersize = 10, alpha = 0.8)
    # ax3.plot(x1, y1, 'ro', markersize = 10, alpha = 1)

    ## a scatter plot
    worldmap.plot(color="lightgrey", ax=ax2)

    # Plotting our Impact Energy data with a color map
    x = df['Longitude']
    y = df['Latitude']
    z = df['Impact Energy [kt]']
    # x = np.random.normal(1,1,30)
    # y = np.random.normal(1,1,30)
    ax2.scatter(x, y, s=20*z, c=z, alpha=0.6, vmin=0, vmax=threshold,
        cmap='autumn')

    ## scatter and line plot
    # ax4.scatter(x2,y2, c = 'b', s = 100, alpha = 0.6)
    # ax4.plot([0,0.5,1],[0,0.5,1],'ro', markersize = 10) ##note: no alpha value!

    ##setting up the updater
    # my_updater.add_ax(ax1, ['size'])  ##line plot, only marker size
    my_updater.add_ax(ax2, ['size'])  ##scatter plot, only marker size
    # my_updater.add_ax(ax3, ['alpha']) ##line plot, only alpha
    # my_updater.add_ax(ax4, ['size', 'alpha']) ##scatter plot, marker size and alpha

    plt.show()

Traceback

The error is in this line:

worldmap.plot(color="lightgrey", ax=ax2)

Traceback:

Traceback (most recent call last):
  File "c:\Users\x\OneDrive - Wageningen University & Research\Arjen Daane\Data\tempCodeRunnerFile.python", line 185, in <module>
    worldmap.plot(color="lightgrey", ax=ax2)
  File "C:\Users\x\AppData\Local\Programs\Python\Python310\lib\site-packages\geopandas\geodataframe.py", line 617, in plot
    return plot_dataframe(self, *args, **kwargs)
  File "C:\Users\x\AppData\Local\Programs\Python\Python310\lib\site-packages\geopandas\plotting.py", line 504, in plot_dataframe
    ax.set_aspect("equal")
AttributeError: 'numpy.ndarray' object has no attribute 'set_aspect'

Would anyone be interested in helping me to move forward?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

日久见人心 2025-02-09 03:42:13

问题在于,MarkerupDater对象也试图重建世界地图本身。您可以通过在避免重新缩放的课堂中添加IF语句来避免这种情况。还为此解决方案添加额外的导入列表:

import matplotlib.pyplot as plt
## UPDATE: Add this import: #########################################
from matplotlib.collections import PatchCollection
import pandas as pd

##plt.switch_backend('TkAgg')
class MarkerUpdater:
    def __init__(self):
        ##for storing information about Figures and Axes
        self.figs = {}

        ##for storing timers
        self.timer_dict = {}

    def add_ax(self, ax, features=[]):
        ax_dict = self.figs.setdefault(ax.figure,dict())
        ax_dict[ax] = {
            'xlim' : ax.get_xlim(),
            'ylim' : ax.get_ylim(),
            'figw' : ax.figure.get_figwidth(),
            'figh' : ax.figure.get_figheight(),
            'scale_s' : 1.0,
            'scale_a' : 1.0,
            'features' : [features] if isinstance(features,str) else features,
        }
        ax.figure.canvas.mpl_connect('draw_event', self.update_axes)

    def update_axes(self, event):

        for fig,axes in self.figs.items():
            if fig is event.canvas.figure:

                for ax, args in axes.items():
                    ##make sure the figure is re-drawn
                    update = True

                    fw = fig.get_figwidth()
                    fh = fig.get_figheight()
                    fac1 = min(fw/args['figw'], fh/args['figh'])


                    xl = ax.get_xlim()
                    yl = ax.get_ylim()
                    fac2 = min(
                        abs(args['xlim'][1]-args['xlim'][0])/abs(xl[1]-xl[0]),
                        abs(args['ylim'][1]-args['ylim'][0])/abs(yl[1]-yl[0])
                    )

                    ##factor for marker size
                    facS = (fac1*fac2)/args['scale_s']

                    ##factor for alpha -- limited to values smaller 1.0
                    facA = min(1.0,fac1*fac2)/args['scale_a']

                    ##updating the artists
                    if facS != 1.0:
                        for line in ax.lines:
                            if 'size' in args['features']:
                                line.set_markersize(line.get_markersize()*facS)

                            if 'alpha' in args['features']:
                                alpha = line.get_alpha()
                                if alpha is not None:
                                    line.set_alpha(alpha*facA)


                        for path in ax.collections:
                            if 'size' in args['features']:
############################### UPDATE: Add this if statement: ########################
                                if not isinstance(path, PatchCollection):   
                                    path.set_sizes([s*facS**2 for s in path.get_sizes()])

                            if 'alpha' in args['features']:
                                alpha = path.get_alpha()
                                if alpha is not None:
                                    path.set_alpha(alpha*facA)

                        args['scale_s'] *= facS
                        args['scale_a'] *= facA

                self._redraw_later(fig)



    def _redraw_later(self, fig):
        timer = fig.canvas.new_timer(interval=10)
        timer.single_shot = True
        timer.add_callback(lambda : fig.canvas.draw_idle())
        timer.start()

        ##stopping previous timer
        if fig in self.timer_dict:
            self.timer_dict[fig].stop()

        ##storing a reference to prevent garbage collection
        self.timer_dict[fig] = timer

                            if 'alpha' in args['features']:
                                alpha = path.get_alpha()
                                if alpha is not None:
                                    path.set_alpha(alpha*facA)

                        args['scale_s'] *= facS
                        args['scale_a'] *= facA

                self._redraw_later(fig)



    def _redraw_later(self, fig):
        timer = fig.canvas.new_timer(interval=10)
        timer.single_shot = True
        timer.add_callback(lambda : fig.canvas.draw_idle())
        timer.start()

        ##stopping previous timer
        if fig in self.timer_dict:
            self.timer_dict[fig].stop()

        ##storing a reference to prevent garbage collection
        self.timer_dict[fig] = timer

那么您的代码应该看起来像这样:

...

## UPDATE: construct the object
my_updater = MarkerUpdater()

# Creating axes and plotting world map
fig, ax = plt.subplots(figsize=(12, 6))
worldmap.plot(color="lightgrey", ax=ax)

# Plotting our Impact Energy data with a color map
x = df['Longitude']
y = df['Latitude']
z = df['Impact Energy [kt]']
plt.scatter(x, y, s=20*z, c=z, alpha=0.6, vmin=0, vmax=threshold,
            cmap='autumn')
plt.colorbar(label='Impact Energy [kt]')

## UPDATE: Link the scatter plot to the object
my_updater.add_ax(ax, ['size'])  ##line plot, only marker size

...

好运!

The problem is that the MarkerUpdater object also tries to rescale the world map itself. You can avoid this by adding an if statement to the class which avoids the rescaling. Also add an extra import to your import list for this solution:

import matplotlib.pyplot as plt
## UPDATE: Add this import: #########################################
from matplotlib.collections import PatchCollection
import pandas as pd

##plt.switch_backend('TkAgg')
class MarkerUpdater:
    def __init__(self):
        ##for storing information about Figures and Axes
        self.figs = {}

        ##for storing timers
        self.timer_dict = {}

    def add_ax(self, ax, features=[]):
        ax_dict = self.figs.setdefault(ax.figure,dict())
        ax_dict[ax] = {
            'xlim' : ax.get_xlim(),
            'ylim' : ax.get_ylim(),
            'figw' : ax.figure.get_figwidth(),
            'figh' : ax.figure.get_figheight(),
            'scale_s' : 1.0,
            'scale_a' : 1.0,
            'features' : [features] if isinstance(features,str) else features,
        }
        ax.figure.canvas.mpl_connect('draw_event', self.update_axes)

    def update_axes(self, event):

        for fig,axes in self.figs.items():
            if fig is event.canvas.figure:

                for ax, args in axes.items():
                    ##make sure the figure is re-drawn
                    update = True

                    fw = fig.get_figwidth()
                    fh = fig.get_figheight()
                    fac1 = min(fw/args['figw'], fh/args['figh'])


                    xl = ax.get_xlim()
                    yl = ax.get_ylim()
                    fac2 = min(
                        abs(args['xlim'][1]-args['xlim'][0])/abs(xl[1]-xl[0]),
                        abs(args['ylim'][1]-args['ylim'][0])/abs(yl[1]-yl[0])
                    )

                    ##factor for marker size
                    facS = (fac1*fac2)/args['scale_s']

                    ##factor for alpha -- limited to values smaller 1.0
                    facA = min(1.0,fac1*fac2)/args['scale_a']

                    ##updating the artists
                    if facS != 1.0:
                        for line in ax.lines:
                            if 'size' in args['features']:
                                line.set_markersize(line.get_markersize()*facS)

                            if 'alpha' in args['features']:
                                alpha = line.get_alpha()
                                if alpha is not None:
                                    line.set_alpha(alpha*facA)


                        for path in ax.collections:
                            if 'size' in args['features']:
############################### UPDATE: Add this if statement: ########################
                                if not isinstance(path, PatchCollection):   
                                    path.set_sizes([s*facS**2 for s in path.get_sizes()])

                            if 'alpha' in args['features']:
                                alpha = path.get_alpha()
                                if alpha is not None:
                                    path.set_alpha(alpha*facA)

                        args['scale_s'] *= facS
                        args['scale_a'] *= facA

                self._redraw_later(fig)



    def _redraw_later(self, fig):
        timer = fig.canvas.new_timer(interval=10)
        timer.single_shot = True
        timer.add_callback(lambda : fig.canvas.draw_idle())
        timer.start()

        ##stopping previous timer
        if fig in self.timer_dict:
            self.timer_dict[fig].stop()

        ##storing a reference to prevent garbage collection
        self.timer_dict[fig] = timer

                            if 'alpha' in args['features']:
                                alpha = path.get_alpha()
                                if alpha is not None:
                                    path.set_alpha(alpha*facA)

                        args['scale_s'] *= facS
                        args['scale_a'] *= facA

                self._redraw_later(fig)



    def _redraw_later(self, fig):
        timer = fig.canvas.new_timer(interval=10)
        timer.single_shot = True
        timer.add_callback(lambda : fig.canvas.draw_idle())
        timer.start()

        ##stopping previous timer
        if fig in self.timer_dict:
            self.timer_dict[fig].stop()

        ##storing a reference to prevent garbage collection
        self.timer_dict[fig] = timer

Then your code should look something like this:

...

## UPDATE: construct the object
my_updater = MarkerUpdater()

# Creating axes and plotting world map
fig, ax = plt.subplots(figsize=(12, 6))
worldmap.plot(color="lightgrey", ax=ax)

# Plotting our Impact Energy data with a color map
x = df['Longitude']
y = df['Latitude']
z = df['Impact Energy [kt]']
plt.scatter(x, y, s=20*z, c=z, alpha=0.6, vmin=0, vmax=threshold,
            cmap='autumn')
plt.colorbar(label='Impact Energy [kt]')

## UPDATE: Link the scatter plot to the object
my_updater.add_ax(ax, ['size'])  ##line plot, only marker size

...

Best of luck!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文