কোন শিল্পীরা বর্তমানে অক্ষগুলির প্রদর্শিত অঞ্চলে আছেন তা যাচাই করার জন্য ম্যাটপ্লটলিবের কোনও উপায় আছে?


9

আমার একটি ইন্টারেক্টিভ ফিগার সহ একটি প্রোগ্রাম রয়েছে যেখানে মাঝেমধ্যে অনেক শিল্পী আঁকেন। এই চিত্রটিতে, আপনি মাউস ব্যবহার করে জুম এবং প্যানও করতে পারেন। যাইহোক, প্যানিং জুম করার সময় অভিনয়টি খুব ভাল নয় কারণ প্রতিটি শিল্পী সর্বদা পুনরায় চিত্রিত হয়। বর্তমানে প্রদর্শিত শিল্পে কোন শিল্পীরা রয়েছেন এবং কেবল সেগুলি পুনরায় আঁকেন এমন কি কোনও উপায় আছে? (নীচের উদাহরণে পারফোমেস এখনও তুলনামূলকভাবে ভাল তবে আরও বা বেশি জটিল শিল্পী ব্যবহার করে এটি নির্বিচারে আরও খারাপ করা যায়)

hoverপদ্ধতিটির সাথে আমার একইরকম পারফরমেন্স সমস্যা ছিল যে যখনই এটি বলা canvas.draw()হত শেষে দৌড়ে । কিন্তু আপনি দেখতে পারেন আমি ক্যাশে ব্যবহার করে এবং অক্ষ পটভূমিতে (উপর ভিত্তি করে ফিরিয়ে নেওয়ার মাধ্যমে যে জন্য একটি ঝরঝরে কার্যসংক্রান্ত পাওয়া এই )। এটি পারফরম্যান্সকে উল্লেখযোগ্যভাবে উন্নত করেছে এবং এখন এমনকি অনেক শিল্পীর সাথে এটি খুব মসৃণভাবে চলে। সম্ভবত এটি করার মতো একটি উপায় আছে তবে পদ্ধতি panএবং zoomপদ্ধতির জন্য?

দীর্ঘ কোড নমুনার জন্য দুঃখিত, এটি বেশিরভাগই প্রশ্নের জন্য সরাসরি প্রাসঙ্গিক নয় তবে সমস্যাটি তুলে ধরার জন্য একটি কার্যকারী উদাহরণের জন্য প্রয়োজনীয়।

সম্পাদনা

আমি এমডব্লিউই এমন কিছুতে আপডেট করেছি যা আমার আসল কোডের আরও প্রতিনিধি is

import numpy as np
import numpy as np
import sys
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import \
    FigureCanvasQTAgg
import matplotlib.patheffects as PathEffects
from matplotlib.text import Annotation
from matplotlib.collections import LineCollection

from PyQt5.QtWidgets import QApplication, QVBoxLayout, QDialog


def check_limits(base_xlim, base_ylim, new_xlim, new_ylim):
    if new_xlim[0] < base_xlim[0]:
        overlap = base_xlim[0] - new_xlim[0]
        new_xlim[0] = base_xlim[0]
        if new_xlim[1] + overlap > base_xlim[1]:
            new_xlim[1] = base_xlim[1]
        else:
            new_xlim[1] += overlap
    if new_xlim[1] > base_xlim[1]:
        overlap = new_xlim[1] - base_xlim[1]
        new_xlim[1] = base_xlim[1]
        if new_xlim[0] - overlap < base_xlim[0]:
            new_xlim[0] = base_xlim[0]
        else:
            new_xlim[0] -= overlap
    if new_ylim[1] < base_ylim[1]:
        overlap = base_ylim[1] - new_ylim[1]
        new_ylim[1] = base_ylim[1]
        if new_ylim[0] + overlap > base_ylim[0]:
            new_ylim[0] = base_ylim[0]
        else:
            new_ylim[0] += overlap
    if new_ylim[0] > base_ylim[0]:
        overlap = new_ylim[0] - base_ylim[0]
        new_ylim[0] = base_ylim[0]
        if new_ylim[1] - overlap < base_ylim[1]:
            new_ylim[1] = base_ylim[1]
        else:
            new_ylim[1] -= overlap

    return new_xlim, new_ylim


class FigureCanvas(FigureCanvasQTAgg):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.bg_cache = None

    def draw(self):
        ax = self.figure.axes[0]
        hid_annotation = False
        if ax.annot.get_visible():
            ax.annot.set_visible(False)
            hid_annotation = True
        hid_highlight = False
        if ax.last_artist:
            ax.last_artist.set_path_effects([PathEffects.Normal()])
            hid_highlight = True
        super().draw()
        self.bg_cache = self.copy_from_bbox(self.figure.bbox)
        if hid_highlight:
            ax.last_artist.set_path_effects(
                [PathEffects.withStroke(
                    linewidth=7, foreground="c", alpha=0.4
                )]
            )
            ax.draw_artist(ax.last_artist)
        if hid_annotation:
            ax.annot.set_visible(True)
            ax.draw_artist(ax.annot)

        if hid_highlight:
            self.update()


def position(t_, coeff, var=0.1):
    x_ = np.random.normal(np.polyval(coeff[:, 0], t_), var)
    y_ = np.random.normal(np.polyval(coeff[:, 1], t_), var)

    return x_, y_


class Data:
    def __init__(self, times):
        self.length = np.random.randint(1, 20)
        self.t = np.sort(
            np.random.choice(times, size=self.length, replace=False)
        )
        self.vel = [np.random.uniform(-2, 2), np.random.uniform(-2, 2)]
        self.accel = [np.random.uniform(-0.01, 0.01), np.random.uniform(-0.01,
                                                                      0.01)]
        x0, y0 = np.random.uniform(0, 1000, 2)
        self.x, self.y = position(
            self.t, np.array([self.accel, self.vel, [x0, y0]])
        )


class Test(QDialog):
    def __init__(self):
        super().__init__()
        self.fig, self.ax = plt.subplots()
        self.canvas = FigureCanvas(self.fig)
        self.artists = []
        self.zoom_factor = 1.5
        self.x_press = None
        self.y_press = None
        self.annot = Annotation(
            "", xy=(0, 0), xytext=(-20, 20), textcoords="offset points",
            bbox=dict(boxstyle="round", fc="w", alpha=0.7), color='black',
            arrowprops=dict(arrowstyle="->"), zorder=6, visible=False,
            annotation_clip=False, in_layout=False,
        )
        self.annot.set_clip_on(False)
        setattr(self.ax, 'annot', self.annot)
        self.ax.add_artist(self.annot)
        self.last_artist = None
        setattr(self.ax, 'last_artist', self.last_artist)

        self.image = np.random.uniform(0, 100, 1000000).reshape((1000, 1000))
        self.ax.imshow(self.image, cmap='gray', interpolation='nearest')
        self.times = np.linspace(0, 20)
        for i in range(1000):
            data = Data(self.times)
            points = np.array([data.x, data.y]).T.reshape(-1, 1, 2)
            segments = np.concatenate([points[:-1], points[1:]], axis=1)
            z = np.linspace(0, 1, data.length)
            norm = plt.Normalize(z.min(), z.max())
            lc = LineCollection(
                segments, cmap='autumn', norm=norm, alpha=1,
                linewidths=2, picker=8, capstyle='round',
                joinstyle='round'
            )
            setattr(lc, 'data_id', i)
            lc.set_array(z)
            self.ax.add_artist(lc)
            self.artists.append(lc)
        self.default_xlim = self.ax.get_xlim()
        self.default_ylim = self.ax.get_ylim()

        self.canvas.draw()

        self.cid_motion = self.fig.canvas.mpl_connect(
            'motion_notify_event', self.motion_event
        )
        self.cid_button = self.fig.canvas.mpl_connect(
            'button_press_event', self.pan_press
        )
        self.cid_zoom = self.fig.canvas.mpl_connect(
            'scroll_event', self.zoom
        )

        layout = QVBoxLayout()
        layout.addWidget(self.canvas)
        self.setLayout(layout)

    def zoom(self, event):
        if event.inaxes == self.ax:
            scale_factor = np.power(self.zoom_factor, -event.step)
            xdata = event.xdata
            ydata = event.ydata
            cur_xlim = self.ax.get_xlim()
            cur_ylim = self.ax.get_ylim()
            x_left = xdata - cur_xlim[0]
            x_right = cur_xlim[1] - xdata
            y_top = ydata - cur_ylim[0]
            y_bottom = cur_ylim[1] - ydata

            new_xlim = [
                xdata - x_left * scale_factor, xdata + x_right * scale_factor
            ]
            new_ylim = [
                ydata - y_top * scale_factor, ydata + y_bottom * scale_factor
            ]
            # intercept new plot parameters if they are out of bounds
            new_xlim, new_ylim = check_limits(
                self.default_xlim, self.default_ylim, new_xlim, new_ylim
            )

            if cur_xlim != tuple(new_xlim) or cur_ylim != tuple(new_ylim):
                self.ax.set_xlim(new_xlim)
                self.ax.set_ylim(new_ylim)

                self.canvas.draw_idle()

    def motion_event(self, event):
        if event.button == 1:
            self.pan_move(event)
        else:
            self.hover(event)

    def pan_press(self, event):
        if event.inaxes == self.ax:
            self.x_press = event.xdata
            self.y_press = event.ydata

    def pan_move(self, event):
        if event.inaxes == self.ax:
            xdata = event.xdata
            ydata = event.ydata
            cur_xlim = self.ax.get_xlim()
            cur_ylim = self.ax.get_ylim()
            dx = xdata - self.x_press
            dy = ydata - self.y_press
            new_xlim = [cur_xlim[0] - dx, cur_xlim[1] - dx]
            new_ylim = [cur_ylim[0] - dy, cur_ylim[1] - dy]

            # intercept new plot parameters that are out of bound
            new_xlim, new_ylim = check_limits(
                self.default_xlim, self.default_ylim, new_xlim, new_ylim
            )

            if cur_xlim != tuple(new_xlim) or cur_ylim != tuple(new_ylim):
                self.ax.set_xlim(new_xlim)
                self.ax.set_ylim(new_ylim)

                self.canvas.draw_idle()

    def update_annot(self, event, artist):
        self.ax.annot.xy = (event.xdata, event.ydata)
        text = f'Data #{artist.data_id}'
        self.ax.annot.set_text(text)
        self.ax.annot.set_visible(True)
        self.ax.draw_artist(self.ax.annot)

    def hover(self, event):
        vis = self.ax.annot.get_visible()
        if event.inaxes == self.ax:
            ind = 0
            cont = None
            while (
                ind in range(len(self.artists))
                and not cont
            ):
                artist = self.artists[ind]
                cont, _ = artist.contains(event)
                if cont and artist is not self.ax.last_artist:
                    if self.ax.last_artist is not None:
                        self.canvas.restore_region(self.canvas.bg_cache)
                        self.ax.last_artist.set_path_effects(
                            [PathEffects.Normal()]
                        )
                        self.ax.last_artist = None
                    artist.set_path_effects(
                        [PathEffects.withStroke(
                            linewidth=7, foreground="c", alpha=0.4
                        )]
                    )
                    self.ax.last_artist = artist
                    self.ax.draw_artist(self.ax.last_artist)
                    self.update_annot(event, self.ax.last_artist)
                ind += 1

            if vis and not cont and self.ax.last_artist:
                self.canvas.restore_region(self.canvas.bg_cache)
                self.ax.last_artist.set_path_effects([PathEffects.Normal()])
                self.ax.last_artist = None
                self.ax.annot.set_visible(False)
        elif vis:
            self.canvas.restore_region(self.canvas.bg_cache)
            self.ax.last_artist.set_path_effects([PathEffects.Normal()])
            self.ax.last_artist = None
            self.ax.annot.set_visible(False)
        self.canvas.update()
        self.canvas.flush_events()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    test = Test()
    test.show()
    sys.exit(app.exec_())

আমি সমস্যা বুঝতে পারি না। যেহেতু অক্ষগুলির বাইরে থাকা শিল্পীরা যেভাবেই আঁকেন না, তাই তারা কোনও কিছুও কমিয়ে দেবেন না।
ImportanceOfBeing

সুতরাং আপনি বলছেন যে ইতিমধ্যে একটি রুটিন রয়েছে যা পরীক্ষা করে দেখা যায় যে শিল্পীদের মধ্যে কোনটি দেখা যায় তাই কেবল দৃশ্যমানগুলিই আঁকেন? সম্ভবত এই রুটিনটি কি কম্পিউটারের খুব ব্যয়বহুল? কারণ আপনি নীচের উদাহরণগুলি চেষ্টা করে দেখলে আপনি সহজেই পারফরম্যান্সের পার্থক্য দেখতে পাবেন: উপরে আমার 1000 শিল্পী ডাব্লুএমই এর সাথে একক শিল্পীর উপর জুম বাড়ান এবং চারপাশে প্যান করুন। আপনি একটি উল্লেখযোগ্য বিলম্ব লক্ষ্য করবেন। এখন একই করুন তবে প্লট করুন কেবলমাত্র 1 (বা এমনকি 100) শিল্পী (গুলি) এবং আপনি দেখতে পাবেন যে প্রায় কোনও বিলম্ব নেই।
mapf

ঠিক আছে, প্রশ্নটি হল, আপনি কি আরও দক্ষ রুটিন লিখতে সক্ষম? একটি সাধারণ ক্ষেত্রে, সম্ভবত। সুতরাং আপনি যা শিল্পীদের দেখার সীমাতে রয়েছেন তা পরীক্ষা করতে পারেন এবং অন্যান্য সমস্ত অদৃশ্য সেট করতে পারেন। যদি চেকটি কেবল বিন্দুর কেন্দ্রের স্থানাঙ্কগুলির সাথে তুলনা করে, তবে এটি আরও দ্রুত। তবে এটি আপনাকে বিন্দুটি আলগা করে তুলবে যদি কেবলমাত্র তার কেন্দ্রের বাইরে থাকে তবে এটির অর্ধেকের চেয়ে কিছুটা কম দৃষ্টিতে থাকত। বলা হচ্ছে, এখানে প্রধান সমস্যাটি হল অক্ষগুলিতে 1000 শিল্পী রয়েছে। পরিবর্তে, আপনি plotসমস্ত পয়েন্ট সহ কেবলমাত্র একটি একক ব্যবহার করেছেন, সমস্যাটি ঘটবে না।
ImportanceOfBeingEnnest

হ্যাঁ একেবারে সত্য। এটা ঠিক যে আমার ধারণা ভুল ছিল। আমি ভেবেছিলাম খারাপ পারফরম্যান্সের কারণ হ'ল সমস্ত শিল্পী তাদের দেখা যায় কি না সে সম্পর্কে স্বাধীনভাবে আঁকেন। সুতরাং আমি ভেবেছিলাম একটি স্মার্ট রুটিন যা কেবল প্রদর্শিত শিল্পীদের আঁকায় যা পারফরম্যান্সের উন্নতি করতে পারে তবে দৃশ্যত এ জাতীয় রুটিন ইতিমধ্যে রয়েছে, তাই আমি অনুমান করি যে এখানে করা যায় না। আমি নিশ্চিত যে আমি আরও দক্ষ রুটিন লিখতে পারব না, কমপক্ষে একটি সাধারণ মামলার জন্য।
mapf

আমার ক্ষেত্রে যাইহোক, আমি আসলে লেনিকোলেকশনগুলি (পটভূমির একটি চিত্র) এবং যেমনটি আপনি ইতিমধ্যে বলেছিলেন, এটি কেবল আমার মেগাওয়ুইয়ের মতো বিন্দুগুলির মধ্যেও ছিল, কেবল স্থানাঙ্কগুলি অক্ষের ভিতরে রয়েছে কিনা তা খতিয়ে দেখাই যথেষ্ট নয়। এটি আরও পরিষ্কার করার জন্য আমার সেই অনুযায়ী MWE আপডেট করা উচিত।
mapf

উত্তর:


0

শিল্পীরা যে ডেটা পরিকল্পনা করছেন তার উপরে আপনি যদি ফোকাস করেন তবে আপনি অক্ষরের বর্তমান অঞ্চলে কোন শিল্পীরা রয়েছেন তা খুঁজে পেতে পারেন।

উদাহরণস্বরূপ যদি আপনি এই জাতীয় বিন্যাসে আপনার পয়েন্ট ডেটা ( aএবং bঅ্যারে) রাখেন:

self.points = np.random.randint(0, 100, (1000, 2))

আপনি বর্তমান x এবং y সীমাতে পয়েন্টের তালিকা পেতে পারেন:

xmin, xmax = self.ax.get_xlim()
ymin, ymax = self.ax.get_ylim()

p = self.points

indices_of_visible_points = (np.argwhere((p[:, 0] > xmin) & (p[:, 0] < xmax) & (p[:, 1] > ymin) &  (p[:, 1] < ymax))).flatten()

আপনি indices_of_visible_pointsআপনার সম্পর্কিত self.artistsতালিকা সূচক করতে ব্যবহার করতে পারেন


আপনার উত্তর করার জন্য আপনাকে ধন্যবাদ! দুর্ভাগ্যক্রমে, শিল্পীরা একক পয়েন্ট হলে এটি কেবল কাজ করে। শিল্পীরা লাইন হলে এটি ইতিমধ্যে আর কাজ করে না। উদাহরণস্বরূপ একটি রেখা কেবল দুটি পয়েন্ট দ্বারা সংজ্ঞায়িত করা হয়েছে যেখানে পয়েন্টগুলি অক্ষ সীমাগুলির বাইরে থাকে তবে পয়েন্টগুলি সংযুক্ত রেখাটি অক্ষ ফ্রেমের ছেদ করে দেয় is সম্ভবত আমার সে অনুযায়ী এমডব্লিউই সম্পাদনা করা উচিত যাতে এটি আরও স্পষ্ট।
mapf

আমার কাছে দৃষ্টিভঙ্গি একই, ডেটাতে ফোকাস করুন । শিল্পীরা যদি লাইন হয় তবে আপনি অতিরিক্ত আয়তক্ষেত্রটি ছেদ করার জন্য অতিরিক্ত পরীক্ষা করতে পারেন। আপনি যদি বক্ররেখার পরিকল্পনা করছেন তবে সম্ভবত আপনি নির্দিষ্ট বিরতিতে সেগুলি রেখাংশগুলিতে হ্রাস করে নমুনা দিচ্ছেন। যাইহোক, আপনি কী চক্রান্ত করছেন তার আরও বাস্তবের নমুনা দিতে পারেন?
গুগলি

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.