PHP code example of asharif88 / filament-plotly

1. Go to this page and download the library: Download asharif88/filament-plotly library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

asharif88 / filament-plotly example snippets


use Asharif88\FilamentPlotly\FilamentPlotlyPlugin;
public function panel(Panel $panel): Panel
{
    return $panel
        ->plugins([
            FilamentPlotlyPlugin::make()
        ]);
}

use Asharif88\FilamentPlotly\Widgets\PlotlyWidget;

class BlogPostsChart extends PlotlyWidget 
{
    protected function getChartData(): array
    {
        return [
            'data' => [
                [
                    'x' => ['2025-07-01', '2025-07-02', '2025-07-03', '2025-07-04', '2025-07-05'],
                    'y' => [10, 15, 13, 17, 22],
                    'type' => 'scatter',
                    'mode' => 'lines+markers',
                    'name' => 'Blog Posts',
                ],
            ],
            'layout' => [
                'title' => 'Blog Posts Over Time',
                'xaxis' => [
                    'title' => 'Date',
                ],
                'yaxis' => [
                    'title' => 'Number of Posts',
                ],
            ],
            'config' => [
                'responsive' => true,
            ],
        ];
    }
}

protected function getChartData(): array
{
    return [
        [
            'x' => ['2025-07-01', '2025-07-02', '2025-07-03', '2025-07-04', '2025-07-05'],
            'y' => [10, 15, 13, 17, 22],
            'type' => 'scatter',
            'mode' => 'lines+markers',
            'name' => 'Blog Posts',
        ],
    ]; 
}

protected function getChartLayout(): array
{
    return [
        'title' => 'Blog Posts Over Time',
        'xaxis' => [
            'title' => 'Date',
        ],
        'yaxis' => [
            'title' => 'Number of Posts',
        ],
    ];
}

protected function getChartConfig(): array
{
    return [
        'responsive' => true,
    ];
}

protected static ?string $heading = 'Blog Posts Chart';

protected static ?string $subheading = 'This is a subheading';

public function getBeforeContent(): null|string|Htmlable|View
{
    return '...';
}

protected static string $chartId = 'blogPostsChart';

protected static bool $isCollapsible = true;

protected function isCollapsible(): bool
{
    return true;
}

protected static ?int $contentHeight = 400; //px

protected function getContentHeight(): ?int
{
    return 400;
}

protected static ?string $footer = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.';

use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Contracts\View\View;

protected function getFooter(): null|string|Htmlable|View
{
    return view('custom-footer', ['text' => 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.']);
}

use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Contracts\View\View;
protected function getFooter(): null|string|Htmlable|View
{
    return new HtmlString('<p class="text-danger-500">Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>');
}

use Filament\Actions\Action;
use Filament\Support\Enums\Alignment;

protected function getHeaderActions(): array
{
    return [
        Action::make('refresh')
            ->label('Refresh')
            ->icon('heroicon-o-refresh')
            ->action('updateOptions')
            ->button(),

        Action::make('download')
            ->label('Download')
            ->url(route('reports.export'))
            ->color('secondary'),
    ];
}

protected function getHeaderActionsAlignment(): ?Alignment
{
    return Alignment::End; // align header actions to the right
}

use Filament\Actions\Action;
use Filament\Support\Enums\Alignment;

protected function getFooterActions(): array
{
    return [
        Action::make('details')
            ->label('Details')
            ->url(route('reports.details'))
            ->button(),
    ];
}

protected function getFooterActionsAlignment(): ?Alignment
{
    return Alignment::Center; // center footer actions
}

use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Schema;
use Filament\Widgets\ChartWidget\Concerns\HasFiltersSchema;  
use Asharif88\FilamentPlotly\Widgets\PlotlyWidget;

class BlogPostsChart extends PlotlyWidget 
{
    use HasFiltersSchema;
    
    public function filtersSchema(Schema $schema): Schema
    {
        return $schema->components([
            TextInput::make('title')
                ->default('Blog Posts Chart'),
                
            DatePicker::make('date_start')  
                ->default('2025-07-01'),
    
            DatePicker::make('date_end')
                ->default('2025-07-31'),
        ]);
    }
    
    /**
    * Use this method to update the chart options when the filter form is submitted.
    */
    public function updatedInteractsWithSchemas(string $statePath): void
    {
        $this->updateOptions();
    }
}

protected function getChartData(): array
{
    $title = $this->filters['title'];
    $dateStart = $this->filters['date_start'];
    $dateEnd = $this->filters['date_end'];

    return [
        //chart options
    ];
}

public ?string $filter = 'today';

protected function getFilters(): ?array
{
    return [
        'today' => 'Today',
        'week' => 'Last week',
        'month' => 'Last month',
        'year' => 'This year',
    ];
}

protected function getOptions(): array
{
    $activeFilter = $this->filter;

    return [
        //chart options
    ];
}

protected static ?string $pollingInterval = '10s';

protected static ?string $pollingInterval = null;

protected static bool $deferLoading = true;

protected function getChartData(): array
{
    //showing a loading indicator immediately after the page load
    if (!$this->readyToLoad) {
        return [];
    }

    //slow query
    sleep(2);

    return [
        //chart options
    ];
}

protected static ?string $loadingIndicator = 'Loading...';

use Illuminate\Contracts\View\View;
protected function getLoadingIndicator(): null|string|View
{
    return view('custom-loading-indicator');
}

use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Contracts\View\View;

protected function getChartOverlay(): null|string|Htmlable|View
{
    return view('charts.my-overlay');
}

protected function getOnChartReadyScript(): ?string
{
    return <<<'JS'
        // `el` is the Plotly chart DOM element
        el.on('plotly_afterplot', () => {
            document.getElementById('stream-progress').style.display = 'none';
        });
    JS;
}

use Asharif88\FilamentPlotly\Concerns\HasChartTheme;
use Asharif88\FilamentPlotly\Widgets\PlotlyWidget;

class RevenueChart extends PlotlyWidget
{
    use HasChartTheme;

    protected function getDarkThemeLayout(): array
    {
        return [
            'paper_bgcolor' => '#1e293b',
            'plot_bgcolor'  => '#1e293b',
            'font'          => ['color' => '#f1f5f9'],
        ];
    }

    protected function getLightThemeLayout(): array
    {
        return [
            'paper_bgcolor' => '#ffffff',
            'plot_bgcolor'  => '#ffffff',
            'font'          => ['color' => '#0f172a'],
        ];
    }
}

protected function getPlotlyEventListeners(): array
{
    return [
        'plotly_click'    => 'onChartClick',
        'plotly_selected' => 'onChartSelected',
    ];
}

public function onChartClick(array $data): void
{
    $recordId = $data['points'][0]['customdata'] ?? null;

    $this->dispatch('open-record', id: $recordId);
}

public function onChartSelected(array $data): void
{
    $ids = collect($data['points'])->pluck('customdata')->filter()->all();

    $this->dispatch('filter-table', ids: $ids);
}

protected function getChartData(): array
{
    $rows = Order::query()->get();

    return [[
        'x'          => $rows->pluck('created_at'),
        'y'          => $rows->pluck('total'),
        'customdata' => $rows->pluck('id'),   // ← record IDs travel with each point
        'type'       => 'scatter',
        'mode'       => 'markers',
    ]];
}

use Livewire\Attributes\On;

#[On('plotly:plotly_click')]
public function handleChartClick(array $data): void
{
    $this->tableFilters['id'] = $data['points'][0]['customdata'];
    $this->resetTable();
}

use Asharif88\FilamentPlotly\Concerns\HasStreamingSupport;
use Asharif88\FilamentPlotly\Widgets\PlotlyWidget;

class LiveDataChart extends PlotlyWidget
{
    use HasStreamingSupport;

    public int $sourceId = 1;

    // Return null to disable streaming (e.g. before $this->sourceId];
    }

    // JS body called for each data message. `d` = parsed JSON, `el` = chart DOM element.
    // Return null to use the built-in default: Plotly.extendTraces(el, {x:[[d.x]], y:[[d.y]]}, [0])
    protected function getOnStreamMessageScript(): ?string
    {
        return <<<'JS'
            Plotly.extendTraces(el, { x: [[d.ts]], y: [[d.value]] }, [0]);
        JS;
    }

    // JS body called once when {done: true} arrives, after the overlay is removed.
    // `el` is the chart DOM element. Return null if no post-stream work is needed.
    protected function getOnStreamDoneScript(): ?string
    {
        return null;
    }

    protected function getChartData(): array
    {
        return [['x' => [], 'y' => [], 'type' => 'scatter', 'mode' => 'lines']];
    }
}

use Asharif88\FilamentPlotly\Concerns\HasChartTheme;
use Asharif88\FilamentPlotly\Concerns\HasStreamingSupport;
use Asharif88\FilamentPlotly\Widgets\PlotlyWidget;
use Livewire\Attributes\On;

class DailyVariationChart extends PlotlyWidget
{
    use HasStreamingSupport;
    use HasChartTheme;

    protected ?string $pollingInterval = null;
    protected static ?string $chartId  = 'dailyVariationChart';
    protected static int $contentHeight = 660;

    public ?int $sourceId  = null;
    public ?string $dateFrom = null;
    public ?string $dateTo   = null;

    // --- Filter handlers -----------------------------------------------------

    #[On('sourceSelected')]
    public function onSourceSelected(int $sourceId): void
    {
        $this->sourceId = $sourceId;
    }

    #[On('dateRangeChanged')]
    public function onDateRangeChanged(?string $from, ?string $to): void
    {
        $this->dateFrom = $from;
        $this->dateTo   = $to;
    }

    // --- Chart data ----------------------------------------------------------

    // Starts empty — data is streamed in via extendTraces
    protected function getChartData(): array
    {
        return [[
            'x'          => [],
            'y'          => [],
            'customdata' => [],
            'mode'       => 'lines+markers',
            'line'       => ['width' => 2, 'color' => 'orange'],
            'marker'     => ['size' => 6, 'color' => 'orange'],
            'showlegend' => false,
        ]];
    }

    protected function getChartLayout(): array
    {
        return [
            'title'      => ['text' => 'Variations per day'],
            'yaxis'      => ['type' => 'category', 'autorange' => 'reversed'],
            'autosize'   => true,
            'showlegend' => false,
        ];
    }

    protected function getChartConfig(): array
    {
        return ['responsive' => true];
    }

    // --- HasStreamingSupport -------------------------------------------------

    protected function getStreamUrl(): ?string
    {
        return $this->sourceId ? url('/stream/data') : null;
    }

    protected function getStreamParams(): array
    {
        return [
            'source_id' => $this->sourceId,
            'date_from' => $this->dateFrom ?? '',
            'date_to'   => $this->dateTo   ?? '',
        ];
    }

    // Expected message shape: { x: <date>, y: <float>, payloadId: <int> }
    protected function getOnStreamMessageScript(): ?string
    {
        return <<<'JS'
            Plotly.extendTraces(el, {
                x:          [[d.x]],
                y:          [[d.y]],
                customdata: [[d.payloadId]],
            }, [0]);
        JS;
    }

    // --- HasChartTheme — automatic dark/light sync ---------------------------

    protected function getDarkThemeLayout(): array
    {
        return [
            'paper_bgcolor' => '#1e293b',
            'plot_bgcolor'  => '#1e293b',
            'font'          => ['color' => '#f1f5f9'],
        ];
    }

    protected function getLightThemeLayout(): array
    {
        return [
            'paper_bgcolor' => '#ffffff',
            'plot_bgcolor'  => '#ffffff',
            'font'          => ['color' => '#0f172a'],
        ];
    }

    // --- Plotly event listeners ----------------------------------------------

    protected function getPlotlyEventListeners(): array
    {
        return ['plotly_click' => 'onChartClick'];
    }

    public function onChartClick(array $data): void
    {
        $payloadId = $data['points'][0]['customdata'] ?? null;

        if ($payloadId !== null) {
            $this->dispatch('payloadSelected', payloadId: (int) $payloadId);
        }
    }
}

protected function getStreamingLayoutPatch(): array
{
    return [
        'template' => [
            'layout' => [
                'paper_bgcolor' => '#1e293b',
                'plot_bgcolor'  => '#1e293b',
            ],
        ],
    ];
}
bash
php artisan make:filament-plotly BlogPostsChart
html
<!--resources/views/custom-footer.blade.php-->
<div>
    <p class="text-danger-500">{{ $text }}</p>
</div>
bash
php artisan vendor:publish --tag="filament-plotly-views"
bash
php artisan vendor:publish --tag=filament-plotly-translations